Created
April 25, 2009 01:56
-
-
Save kch/101456 to your computer and use it in GitHub Desktop.
dynamically define a method that takes a block in ruby 1.8; inspired by the pragprog metaprogramming screencasts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment