[rspec-devel] should_yield (is it needed?)
martin.emde at gmail.com
Tue Dec 1 16:27:52 EST 2009
I was a bit unclear about which one I'm advocating. I can see many ways to
achieve this that would be clear in different circumstances and I haven't
really put my weight behind one yet.
David Chelimsky wrote:
> I don't see how we can fail this example:
> describe "foo" do
> def foo; # do nothing; end
> it "yields" do
> foo &should_yield
> In this case the proc returned by should_yield is never invoked, which
> means we have no way of hooking into RSpec to declare that it should be.
> Sort of a catch 22.
should_yield is first invoked with "&should_yield". The should_yield method
is called and returns an object responding to #to_proc. The & calls #to_proc
on our object which returns a block that calls our expected method when it's
Here's my implementation. I actually think it is pretty cool, whether or not
it's the "right" solution:
Now just some thoughts on syntax...
What a "should yield" expectation is really testing is an "anonymous
function" call. Particularly, we're asserting that #call is called on our
"block" object in some form (yield or #call). In ruby, our "anonymous
functions" are blocks. The implementation and usage is then very similar to
a should_receive. If I were to structure this like a should receive, I would
expect something like this.
# should_receive style implementation.
block = mock_block.should_receive_yield.with(1,2,3)
This actually shows that we're making a block with expectations on it, and
then we're passing the block in a familiar format "&block" which most
rubyists will recognize. It could even be shortened by people who understand
what they're doing to something like this:
This opens up a really comfortable feeling language where you can even have
return values from the block in a way that makes sense.
# this block doubles the number passed in
block = mock_block.should_receive_yield.with(1,2,3).and_return(2,4,6)
[1,2,3].map(&block).should == [2,4,6]
My only concern for the & syntax is just how confusing it is to most people.
This is really just stepping back a bit to expose my implementation a bit
more. In my implementation the "mock_block.should_recieve_yield" is just
"should_yield" which does the mock_block part behind the scenes. Thoughts?
P.S. Peter, your implementation reads well but the method(args) will call
the method right away without a block. That's the catch here that makes this
a tricky thing to spec.
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the rspec-devel