Reputation: 1641
I'm using Ruby 1.9.2-p180. The following piece of code throws the error:
"test.rb:20:in `': undefined local variable or method `val' for main:Object (NameError)"
Is there a way that I could make the monkeypatching work to return val
?
class Test
def m
"m"
end
end
def inject(testObj, val)
def testObj.m
val
end
testObj
end
t = Test.new
puts t.m
puts inject(t, val).m
Upvotes: 0
Views: 87
Reputation: 369430
The immediate problem is that in line 20 you are calling
puts inject(t, val).m
I.e. you are passing val
as an argument to inject
, but you never actually defined val
. You need to pass an actual value, for example:
puts inject(t, 'Hello, World!').m
Or define val
first:
val = 42
puts inject(t, val).m
However, if you do this, you will get a new error:
NameError: undefined local variable or method `val' for #<Test:0x007fa1228439b8>
The reason for this is that in Ruby, only blocks can be closures. Methods do not close over their surrounding lexical environment.
Which means that here:
def inject(testObj, val)
def testObj.m
val
end
testObj
end
you have
val
in inject
val
in testObj.m
If you want to have access to the surrounding scope, you need to use a block. Thankfully, there is a (family of) methods that take blocks and define methods:
def inject(testObj, val)
testObj.define_singleton_method(:m) do
val
end
testObj
end
Now, everything works as expected:
puts inject(t, 'Hello, World!').m
# Hello, World!
Upvotes: 3