-
-
Notifications
You must be signed in to change notification settings - Fork 356
and_yield
not using default block argument when no argument given.
#714
Conversation
Using ruby 2.1.2 ```ruby default_arg = Object.new obj = Object.new allow(obj).to receive(:a_message).and_yield expect(default_arg).to receive(:bar) obj.a_message do |receiver=default_arg| receiver.bar end ``` The above code fails with: ``` Failure/Error: obj.a_message do |receiver=default_arg| #<Object:0x007fe3ac1ce408> yielded || to block with arity of 1 ``` The block has a arity of 0 or 1 not 1. So I would expect that when no argument is given to `and_yield` it would use the default block argument.
Thanks, I'll look into this. |
(I verified this failed as described FWIW) |
So the problem is that ruby provides no way to differentiate between a block arg that has a default and a block arg that does not:
This is because procs/blocks have an implicit default of
...so Lambdas, on the other hand, do differentiate:
...since this generally represents a mistake. I believe it's an old feature (from rspec-1, before my involvement with the project) that probably arose at a time when ruby didn't even allow blocks to have default arguments, so your use case wasn't on the radar. Given the history here, how things currently work, and the fact that ruby provides no way to differentiate args with user-provided defaults vs not...I'm not sure what to do here. Maybe we should consider dropping the error entirely or making it opt-in via a config option, but I'd want more community feedback before going that route. For now you can work around this by passing your own implementation as a block. For example, here's a passing version of the failing spec from this PR: it "yields the default argument when the argument is not given" do
default_arg = Object.new
obj = Object.new
allow(obj).to receive(:a_message) { |&blk| blk.call }
expect(default_arg).to receive(:bar)
obj.a_message do |receiver=default_arg|
receiver.bar
end
end |
Hmm, maybe we can leverage something like this: https://github.com/schneems/proc_to_lambda |
Convert it to a lambda internally? Would that work? |
It appears to:
I don't think I'd want to call the converted lambda (there appears to be some issues with |
We'd only have to convert it to check the param counts right? |
Basically...that's what I was trying to say. |
I've got a fix in rspec/rspec-support#83. #719 is building against that branch. |
Thanks for looking into this and for coming up with a solution so quickly! On Thursday, 19 June 2014, Myron Marston [email protected] wrote:
|
There's a very odd ruby bug that makes this unsafe to use, as its usage mutates the behavior of the block: https://bugs.ruby-lang.org/issues/9967 Unfortunately, this un-fixes rspec/rspec-mocks#714, but we've got to do it.
@tom025 -- unfortunately, there's a very odd bug in ruby that's forcing us to revert the fix we did for this: https://bugs.ruby-lang.org/issues/9967 I plan to cut rspec-support 3.0.2 with that reversion later today. So we're back to square one with this :(. Any ideas? |
There's a very odd ruby bug that makes this unsafe to use, as its usage mutates the behavior of the block: https://bugs.ruby-lang.org/issues/9967 Unfortunately, this un-fixes rspec/rspec-mocks#714, but we've got to do it.
Fixes rspec/rspec-mocks#714. --- This commit was imported from rspec/rspec-support@95e85f3.
There's a very odd ruby bug that makes this unsafe to use, as its usage mutates the behavior of the block: https://bugs.ruby-lang.org/issues/9967 Unfortunately, this un-fixes rspec/rspec-mocks#714, but we've got to do it. --- This commit was imported from rspec/rspec-support@17c5b46.
Using ruby 2.1.2
The above code fails with:
The block has a arity of 0 or 1 not 1. So I would expect that when no argument
is given to
and_yield
it would use the default block argument.I have a supplied a test that exposes this but I'm not sure how to fix this.