module Tracy def self.included k k.extend ClassMethods end module ClassMethods def method_added m wrap_method(m) end def previous_method_name(m) :"previous #{m}" end def suppressing_wrap_method @_wrap_method_suppressed = true yield ensure @_wrap_method_suppressed = false end def wrap_method m return if @_wrap_method_suppressed suppressing_wrap_method do alias_method previous_method_name(m), m alias_method m, :_call_original_method_with_tracing end end def alias_method m0, m1 return super unless method_defined? previous_method_name(m1) suppressing_wrap_method do super super previous_method_name(m0), previous_method_name(m1) end end def define_method m, &b super wrap_method(m) end end def _call_original_method_with_tracing *a, &b m = caller(0).first =~ /`(.+)'$/ && $1 puts ">>>> calling #{m}" m0 = self.class.previous_method_name(m) rv = send m0, *a, &b puts "<<<< returning #{rv.inspect}" rv end end class Foo include Tracy def bar v yield * v end def << x bar(6){x} end alias_method :baz, :<< end r = Foo.new puts r.bar(5){6} puts r << 4 puts r.baz(4) m = "nomnom `' `nomnom" (class << r; self end).send(:define_method, m) { "LOLZ" } puts r.send(m)