class Kung
mstr = %-
def foo
puts 'Hello World from Kung.foo'
puts caller(0)
end
-
module_eval mstr
end
Kung.new.foo
Which generates the following output:
Hello World from Kung.foo
(eval):4:in `foo'
Kung-foo.rb:11
The stack trace only shows "(Eval):4:in 'foo'" which is almost useless. The "(Eval)" is a clue that the method was dynamically created using meta-programming. In this simple example, it is easy to find the dynamic code since it is near the caller "Kung-foo.rb:11". However in a real project it is frequently located far away, possibly in other source files.
To fix the stack trace, the author should use the optional arguments to method_eval as follows:
class Monkey
line, mstr = __LINE__, %-
def see
puts 'Hello World from Monkey.see'
puts caller(0)
end
-
module_eval mstr, __FILE__, line
end
Monkey.new.see
The output now shows the correct line number and file name:
Hello World from Monkey.see
Monkey-see.rb:5:in `see'
Monkey-see.rb:11
Update after reading the code in ActiveSupport core_ext\attribute_accessors.rb I found a nice way to do the above with fewer lines of code:
class Monkey
module_eval(<<-EOS, __FILE__, __LINE__)
def see
puts 'Hello World from Monkey.see'
puts caller(0)
end
EOS
end
Monkey.new.see
No comments:
Post a Comment