Created
October 21, 2010 17:30
-
-
Save mxgrn/638919 to your computer and use it in GitHub Desktop.
Wrong scope of yield?
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
# (Ruby version: 1.9.2) | |
# | |
##### A million-dollar question: why the following isn't working? | |
# | |
# | |
class A | |
def self.metamethod(name) | |
define_method(name) do | |
yield | |
end | |
end | |
end | |
class B < A | |
def m1 | |
"from m1" | |
end | |
metamethod :my_method do | |
m1 | |
end | |
end | |
B.new.my_method #=> undefined local variable or method ‘m1’ for B:Class (* B:Class ??? *) | |
# | |
# | |
########### ...while the following does! ############# | |
# | |
# | |
class A | |
def self.metamethod(name) | |
define_singleton_method(name) do | |
yield | |
end | |
end | |
end | |
class B < A | |
def self.m1 | |
"from m1" | |
end | |
metamethod :my_method do | |
m1 | |
end | |
end | |
B.my_method #=> "from m1" |
I'm not sure where you want to use it for (sorry, wasn't at rar10 today).
You can always use instance_eval but you'll need to use something like alias_method_chain to add stuff to the original method.
class A
def self.metamethod
instance_eval do
yield
#alias_method_chain stuff
end
end
end
class B < A
def m1
"from m1"
end
metamethod do
def my_method
m1
end
end
end
B.new.my_method
The solution was using instance_eval instead of yield:
class A
def self.metamethod(name, &block)
define_method(name) do
instance_eval(&block)
end
end
end
class B < A
def m1
"from m1"
end
metamethod :my_method do
m1
end
end
B.new.my_method #=> "from m1"
Nice!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Right, this makes sense, I guess. Do you know a way to call yield on the instance of A? Thanks!