Backport #8341
closedblock_given? (and the actual block) persist between calls to a proc created from a method (using method().to_proc()).
Description
Confirmed on both 2.0.0 and 1.9.2-p290. A testcase (utilizing RSpec) is attached, but the behavior is easy to demonstrate without a testcase or RSpec.
First, we define a method that can optionally accept a block.
def foo
if block_given?
yield
else
puts "No block given."
end
end
Then, we convert the method to a proc and store it in a variable.
method_to_proc = method(:foo).to_proc
Now, we try calling method_to_proc without a block, getting the expected result:
method_to_proc.call
=> No block given.¶
We call it again, this time with a block, and again get the expected result:
method_to_proc.call { puts "Block given." }
=> Block given.¶
But when we call it a third time, again with no block...
method_to_proc.call
=> Block given.¶
...it remembers the previous proc that was passed in.
If we then call it with a new proc, it overwrites the old proc as expected (this is not tested in the testcase, which only tests block_given?):
method_to_proc.call { puts "New block given." }
=> New block given.¶
The testcase verifies this behavior, and also that the behavior does not occur when calling a method in the usual way, or when using method() but not to_proc(), or when using method().to_proc() but not storing the result in the same variable (the last of which isn't that surprising but is included for completeness).
I cannot see any reason that this should be expected behavior. Either block_given? should work the same way in method.to_proc()s as it does in method()s, or it should always return false, and it certainly shouldn't "remember" the last block used.
Files