call function by name - applescript

Given: script with multiple functions in it (see below)
Wanted: call a function by name from command line, e.g. osascript lib.scpt fn1
Problem: Executing the above command gives "lib.scpt: execution error: «script» doesn't understand the argv message. (-1708)"
How can I call a function by name?
on run argv
argv() // <-- here's the problem
end run
on fn0()
return "hello from fn0"
end fn0
on fn1()
return "hello from fn1"
end fn1

I think I've found what you're looking for on MacScripter:
on run argv
set arg to (item 1 of argv)
set scpt to "on run inArgs\n(item 1 of inArgs)'s " & arg & "()\n\tend"
run script scpt with parameters {me}
end run
on fn0()
return "hello from fn0"
end fn0
on fn1()
return "hello from fn1"
end fn1

Related

Unified way in Rake to work with arguments passed by #invoke and #execute

I expected a Task to get arguments the same way, transparent to the caller methods #invoke or #execute:
desc "Add task"
task :add do |t, args|
puts args.class
puts "Add"
end
desc "Sub task"
task :sub do |t, args|
puts args.class
puts "Sub"
end
desc "all"
task :all do
Rake::Task['add'].execute("arg1") # cannot set multiple arguments, will fail with "wrong number of arguments"
Rake::Task['sub'].invoke("arg1", "arg2")
end
The result was:
» rake all
String
Add
Rake::TaskArguments
Sub
Upon checking the Rake source code it is clear these implementations are different.
Is there an unified way to manage arguments regardless where they come from? (command line, #invoke or #execution?). I use OptParse for the command line arguments so I have two ugly workarounds in my code now.
i assume that in case of execute if number of arguments > 1 then you want to execute with an argument is an array collect all those arguments, otherwise execute will execute with nil or the only input argument (a String, for example). So the way you call execute will match with the way you call invoke and execute still do the same as origin.
you could create a wrapper (alias) for Rake::Task#execute and handle the input arguments as below
# Rakefile
Rake::Task.alias_method :old_execute, :execute
Rake::Task.define_method("execute") do |*args|
if args&.size > 1
old_execute(args)
else
old_execute(args&.first)
end
end
# ...
Rake::Task['add'].execute # Rake::TaskArguments
Rake::Task['add'].execute("arg1") # String
Rake::Task['add'].execute("arg1", "arg2") # Array

Ruby get input only if input exists

I am looking for a way to take input from a terminal in a function called from the main loop of a program.
I am not worried about it executing scripts halfway through writing them as the main loop is paused when the application window (not the terminal or console window) loses focus.
This is dev-only so any mishaps with eval lie with me
Edit: I forgot to say, I want the main loop to continue uninterrupted if there is no input.
In Ruby, Kernel#gets will return nil when there is no more line to read (i.e. EOF is reached).
So the following script would do the equivalent to the above Java code:
script = ''
while line = gets
script += line
end
You can capture the input lines as an array and join the elements by newline:
script = STDIN.readlines.join("\n")
To evaluate it:
eval script rescue nil
Or:
begin
eval script
rescue
end
As you noted in the comments, you can STDOUT.flush if you need to. If the Ruby program is ending immediately, there's no need to flush stdout.
This works but only because self.reload! is not called while my console window is selected
Thread.new do
loop do
script_temp = gets
#script = #script + script_temp
end
end
def self.reload!
begin
eval #script
$stdout.flush()
rescue Exception
end
#script = ''
end
Based on this

Function executed without being called

I have a function func, and it executes automatically; I have never called it.
BEGIN {
print "Start"
}
*data = gets;
test = true
for i in 0...data.length
if i==0
print data[i]
end
if i==0 and !test
print "test"
else
print "uu"
end
end
END {
print "End"
}
def func()
print "test1"
yield
print "test2"
end
func {
print "func block"
}
Output of above code:
StartUSERINPUT
USERINPUT
uutest1func blocktest2End
I don't want that function to be executed by itself but only when I call it. I can't use a function with parameters due to this automatic calling.
func {} is actually calling the function func.
Why? {} is for accepting block. You can think of blocks as arguments.
See how the BEGIN and END works.
They got called with the parameters passed in (via blocks).
I'm not sure what you were trying to achieve, but this:
func {
print "func block"
}
in Ruby is a function call, exactly like this:
func() {
print "func block"
}

Do something if no arguments present

This is a small test script I wrote:
#!/usr/bin/env ruby
require 'packetfu'
def mac(host)
if host
rmac = PacketFu::Utils.arp(host, :iface => 'wlan0')
puts rmac
else
whoami = PacketFu::Utils.whoami?(:iface => 'wlan0')
puts whoami
end
end
mac(ARGV[0])
What I want to do is have it print the second variable if no argument is specified. Instead I get an ArgumentError. There's obviously an easier way that I'm just missing.
If you want to be able to call the function without any arguments, you need to change its definition to such that it does not require an argument. One way is to give the argument a default value. Then you can check for that, e.g.,
def mac(host = nil)
if host
puts "host: #{host}"
else
puts 'no host'
end
end
If you want to distinguish between no argument given and argument given with the default value, you could use a variable number of arguments:
def mac2(*args)
if args.empty?
puts "no arguments"
else
host = args[0]
end
end
On the other hand, if your problem is detecting whether ARGV was empty (i.e., no command-line argument given), you can check that higher up. For example, only call mac if an argument was given:
if ARGV.empty?
puts "Usage: …"
exit 1
end
mac(ARGV[0])

Access Ruby exit code in END {}

Ruby has BEGIN {} and END {} blocks that guarantee they run before and after the main portion of code, respectively.
I have the following code:
BEGIN {
$my_args = ARGV.dup
ARGV.clear
} # clean up 'gets'
# For the truly paranoid in all of us
def self.run_away?
print "You're paranoid. Exit? (Y/n) "
ans = gets.chomp.downcase
if ["no", "n"].include?(ans)
puts "Alright, your call. Let's keep going."
else
puts "EXITING"
log("Exiting at paranoid users request.")
exit 3
end
end
END { } # do stuff here
I have a handful of error codes that I have defined in my script.
I would like to be able to read the error code and print a short description based on that code. E.g. - EXITING - 3: Exit at user request instead of writing a descriptive string every time I use an exit in my code. Is there a way to do this in the END {} block? Or something else I am missing?
Edit/Note: I'm stuck with Ruby 1.8.7 and the following doesn't work: (see below)
BEGIN { puts "BEGIN block!" }
puts "Main block!"
exit 3
END {
puts "END block!"
puts "Current Exception: \n#{$!}"
puts "Current Backtrace: \n#{$#}"
}
Output:
~: $ ./test.rb
BEGIN block!
Main block!
~: $ echo $?
3
~: $
Edit #2: I had to define my END block before I exited. Thanks to #Stefan
Kernel#exit raises a SystemExit exception and since the global variable $! contains the current exception, you can get the exit status via $!.status:
END {
puts "exit status: #{$!.status}"
}
exit 3
Output:
exit status: 3
From the documentation:
When an exception has been raised but not yet handled (in rescue,
ensure, at_exit and END blocks) the global variable $! will contain
the current exception and $# contains the current exception’s
backtrace.
A way to centralize exit message :
module Kernel
alias :real_exit :exit
def exit status
puts "Hello World"
real_exit status
end
end
The method is just an around alias on the Kernel#exit method. Be aware that once you will have define this override, all other exit call will go through your override.

Resources