I understand that it is possible to decorate methods with before and after hooks in ruby, but is it possible to do it for each line of a given method?
For example, I
It sounds like you want tracing on every method call on every object, but only during the span of every call to one particular method. In that case, you could just redefine the method to turn on- and off instrumentation. First, use the universal instrumentation suggsted in Pinochle's answer, then redefine the method in question as follows:
# original definition, in /lib/foo.rb:
class Foo
def bar(baz)
do_stuff
end
end
# redefinition, in /test/add_instrumentation_to_foo.rb:
Foo.class_eval do
original_bar = instance_method(:bar)
def bar(baz)
TracedObject.install!
original_bar.bind(self).call(baz)
TracedObject.uninstall!
end
end
You'd need to write the install! and uninstall methods, but they should be pretty trivial: just set or unset a class variable and check for it in the instrumentation logic.
It is, and you can get a full description of how to do it in section 8.9 of The Ruby Programming Language. Running the code on each invocation of the method involves sending the method to a TracedObject class that has an implementation for method_missing. Whenever it receives a message, it invokes method_missing and executes whatever code you have assigned to it. (This is, of course, for general tracing).
That's the general description of the procedure for doing it, you can consult the book for details.
What about (just tries)
class User
def initialize(name)
@name = name
end
def say_hello
puts "hello #{@name}"
end
def say_hi(friend)
puts "hi #{@name} from #{friend}"
end
def say_bye(a, b = 'Anna')
puts "bye #{a} and #{b}"
end
end
User.class_eval do
User.instance_methods(false).each do |method|
original = instance_method(method)
define_method method do |*options|
parameters = original.parameters
if parameters.empty?
original.bind(self).call
else
original.bind(self).call(*options)
end
puts __method__
end
end
end
user = User.new("John")
user.say_hello
user.say_hi("Bob")
user.say_bye("Bob")
user.say_bye("Bob", "Lisa")
outputs:
hello John
say_hello
hi John from Bob
say_hi
bye Bob and Anna
say_bye
bye Bob and Lisa
say_bye