Kernel #__ method__ does not work correctly in dynamically defined methods

I am trying to dynamically define some instance methods in Ruby 1.9. Here is the code I used to try:

class Testing [:one, :two].each do |name| define_method(name) do puts __method__ end end end 

And here is the conclusion:

 ruby-1.9.2-p180 :008 > t = Testing.new => #<Testing:0x00000100961878> ruby-1.9.2-p180 :009 > t.one two => nil ruby-1.9.2-p180 :010 > t.two two => nil ruby-1.9.2-p180 :011 > 

I expect the result to be one and two respectively. If I call the define_method each of them outside of the iteration, it works as expected. What I don’t understand here?

Here is one of many examples that I saw around online from define_method called in every iteration. Dynamically defined incubation methods using define_method?

What is missing?

also: Using __method__ not critical to me, but it was the best way I could show that it seems that only the last block sent to define_method used for certain methods. Maybe this is starting to explain this problem to me, but I still do not understand.

+4
source share
3 answers

Nice to find weird behavior. Of all the Rubies we tested, only MRI 1.9.2 demonstrates this.

Ryan Davis reported an error in the ruby ​​core list (referring to this question).

+3
source

You can use something like this instead of define_method :

 class Testing [:one, :two].each do |name| eval <<-EOM def #{name} puts __method__ end EOM end end t = Testing.new t.one #=> "one" t.two #=> "two" 
0
source

The reason for this is that define_method defines the method somewhat differently than def. This is due to the creation of anonymous procs and lambdas. I would suggest just using the method name, since you already have it. This should not distort the stack trace for the method name, so it should work better:

 class Testing [:one, :two].each do |name| define_method name do "This method name is #{name}." end end end Testing.new.one => This method name is one. Testing.new.two => This method name is two. 

To clarify, pay attention to what is returned by the following two statements:

 class Testing define_method :one do __method__ end end => #<Proc: 0x000001009ebfc8@ (irb):54 (lambda)> class Testing def one __method__ end end => nil 

PS: There is also a performance difference between the two formats. You can verify that def is faster than define_method using Benchmark.

0
source

Source: https://habr.com/ru/post/1341470/


All Articles