Mateusz W. wrote in post #1007002:
Hi guys,
I was just looking at some articles on Ruby metaprogramming and came
across this example:
class Talker
[:hello, :good_bye].each do |arg|
method_name = (“say_” + arg.to_s).to_sym
send :define_method, method_name do
puts arg
end
end
end
Could we not write this the following way? I don’t understand why would
anyone choose the above option, it seems confusing to me.
define_method is private, which means you can’t write an explicit
receiver when you call it. If you were in a scope where self did not
equal Talker, then you could write Talker.send(…), but you could
not write Talker.define_method(…). The send() method lets you violate
all kinds of Ruby privacy.
Here is an example:
class Talker
def initialize(*names)
names.each do |name|
method_name = “say_#{name}”
define_method(method_name) do
puts name
end
end
end
end
t = Talker.new(:hello, :goodbye)
t.say_hello
t.say_goodbye
–output:–
ruby.rb:5:in initialize': undefined methoddefine_method’ for
#Talker:0x10016a070 (NoMethodError)
from ruby.rb:3:in each' from ruby.rb:3:ininitialize’
from ruby.rb:12:in `new’
from ruby.rb:12
Inside initialize(), ruby implicitly does this:
self.define_method(...)
But inside initialize(), self = t so that is equivalent to:
t.define_method(...)
…and t is not a class or module, so t does not have a method called
define_method().
On the other hand, you can explicitly write a receiver when you
call send():
class Talker
def initialize(*names)
names.each do |name|
method_name = “say_#{name}”
self.class.send(:define_method, method_name) do
puts name
end
end
end
end
t = Talker.new(:hello, :goodbye)
t.say_hello
t.say_goodbye
–output:–
hello
goodbye
So the send() form can be used anywhere, but define_method() can
only be called in a scope where self equals the class/module in which
you want to define an instance method.