A dot is used to call a method on an object. Imagine the string name is a person you can talk to. You can ask questions by “sending a message” to them, and they'll respond by sending (returning) something back.
Using user data to call any method via send could leave room open for users to execute any method they want. send is often used to call method names dynamically—but make sure the input values are trusted and can't be manipulated by users. Golden rule is never trust any input that comes from the user.
To convert a string in to function "eval()" method should be used. This method takes a string as a parameter and converts it into a function.
To call functions directly on an object
a = [2, 2, 3]
a.send("length")
# or
a.public_send("length")
which returns 3 as expected
or for a module function
FileUtils.send('pwd')
# or
FileUtils.public_send(:pwd)
and a locally defined method
def load()
puts "load() function was executed."
end
send('load')
# or
public_send('load')
Documentation:
Object#public_send
Object#send
send
/ call
/ eval
- and their BenchmarksTypical invocation (for reference):
s= "hi man"
s.length #=> 6
send
s.send(:length) #=> 6
call
method_object = s.method(:length)
p method_object.call #=> 6
eval
eval "s.length" #=> 6
require "benchmark"
test = "hi man"
m = test.method(:length)
n = 100000
Benchmark.bmbm {|x|
x.report("call") { n.times { m.call } }
x.report("send") { n.times { test.send(:length) } }
x.report("eval") { n.times { eval "test.length" } }
}
...as you can see, instantiating a method object is the fastest dynamic way in calling a method, also notice how slow using eval is.
#######################################
##### The results
#######################################
#Rehearsal ----------------------------------------
#call 0.050000 0.020000 0.070000 ( 0.077915)
#send 0.080000 0.000000 0.080000 ( 0.086071)
#eval 0.360000 0.040000 0.400000 ( 0.405647)
#------------------------------- total: 0.550000sec
# user system total real
#call 0.050000 0.020000 0.070000 ( 0.072041)
#send 0.070000 0.000000 0.070000 ( 0.077674)
#eval 0.370000 0.020000 0.390000 ( 0.399442)
Credit goes to this blog post which elaborates a bit more on the three methods and also shows how to check if the methods exist.
Use this:
> a = "my_string"
> meth = a.method("size")
> meth.call() # call the size method
=> 9
Simple, right?
As for the global, I think the Ruby way would be to search it using the methods
method.
Personally I would setup a hash to function references and then use the string as an index to the hash. You then call the function reference with it's parameters. This has the advantage of not allowing the wrong string to call something you don't want to call. The other way is to basically eval
the string. Do not do this.
PS don't be lazy and actually type out your whole question, instead of linking to something.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With