What is the best way to verify that yield is called?

Hello all,
What is the best way to verify that a method yields a block that is
passed in?

Before I added any ‘yield’ to my method I created this spec:

  it "should yield a message_delivery object" do
    create_message_in_factory do |message_delivery|
      message_delivery.should be_instance_of(MessageDelivery)
    end
  end

This passed without me modifying my method which is not what I was
hoping for. So I tried this spec and it gave me red:

  it "should yield the given block" do
    @block_yieled = false
    create_message_in_factory do |message_delivery|
      @block_yieled = true
    end
    @block_yieled.should be_true
  end

Seems kinda hackish, but it did work. Is this the best way to spec this
or is there already a matcher for this?

If there isn’t currently a matcher would be the above way be a good way
to create a custom matcher?

Thanks for your thoughts,

Ben

On Wed, Apr 9, 2008 at 1:29 AM, Ben M. [email protected] wrote:

  end
  end

Seems kinda hackish, but it did work. Is this the best way to spec this
or is there already a matcher for this?

Another approach might be:

it "should yield the given block" do
    block_body = mock("block body")
    block_body.should_receive(:got_here)
    create_message_in_factory_do | message_delivery |
        block_body.got_here
    end

end


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Seems kinda hackish, but it did work. Is this the best way to spec this
end
end

Thanks Rick!
Both of these way work but I think they are both too ugly and should be
created into a more expressive matcher.
Given the above two options can anyone see an advantage to one way or
the other? Or maybe another option is out there that is better?

Thanks,
Ben

On Wed, Apr 9, 2008 at 10:59 AM, Ben M. [email protected] wrote:

        block_body.got_here

created into a more expressive matcher.
What are you looking to specify and how do you envision the syntax?

I’m thinking something like:

obj.should yield_with(no_args).on(:message)

def message
yield
end

list.should yield_with(1).then(2).then(3).on(:each)

def each
yield 1
yield 2
yield 3
end

That all make sense?

On Wed, Apr 9, 2008 at 11:54 AM, David C. [email protected]
wrote:

list.should yield_with(1).then(2).then(3).on(:each)

def each
yield 1
yield 2
yield 3
end

That all make sense?

Sorta, but what about arguments to the message?

def message(x, y, z)
yield x+y+z
end

obj.receiving(:message).with(1,2,3).should yield(6)

(1…3).receiving(:each_with_index).should
yield_with([1,0]).then([2,1]).then([3,2])

or

(1…3).receiving(:each_with_index).should yield_with([1,0],([2,1],[3,2])

(1…3).receiving(:inject).with(0).should yield_with ???

Now it gets tricky since the sequence of yielded values depends on the
block .

I don’t know that I like where this is going.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

On Wed, Apr 9, 2008 at 12:33 PM, Rick DeNatale [email protected]
wrote:

end

or

(1…3).receiving(:each_with_index).should yield_with([1,0],([2,1],[3,2])

(1…3).receiving(:inject).with(0).should yield_with ???

Now it gets tricky since the sequence of yielded values depends on the block .

I don’t know that I like where this is going.

Agreed, this could get hairy. Perhaps we should chalk this up to
implementation detail?

Looking back at the OP:

it “should yield a message_delivery object” do
create_message_in_factory do |message_delivery|
message_delivery.should be_instance_of(MessageDelivery)
end
end

How about something more like this as an idiom:

it “should yield a message_delivery object” do
create_message_in_factory do |message_delivery|
return message_delivery
end.should be_instance_of(MessageDelivery)
end

This still uses the contents of the blog to set an expectation, but is
perhaps more expressive about the fact that we’re not really
interested in the contents of the block as much as we are what the end
result is.

WDYT?

David C. wrote:

def message

(1…3).receiving(:each_with_index).should
I don’t know that I like where this is going.
end
end

How about something more like this as an idiom:

it “should yield a message_delivery object” do
create_message_in_factory do |message_delivery|
return message_delivery
end.should be_instance_of(MessageDelivery)
end

That makes sense for the cases when an object is yielded but what would
you do if no object is yielded and the block is just suppose to execute?

I guess you could do:

  it "should yield the given block" do
    some_method do
      return 42
    end.should == 42
  end

But this does not look any better than the two previously suggested ways
IMO.

This still uses the contents of the blog to set an expectation, but is
perhaps more expressive about the fact that we’re not really
interested in the contents of the block as much as we are what the end
result is.

WDYT?

In the case where the an object is yielded I do like you suggestion
because it covers everything. I just don’t know about when no object is
yielded.

I guess if a matcher is not possible I will have to settle for one of
the approaches above when no object is yielded.

Any more thoughts on the subject?

Thanks,

Ben

Rick DeNatale wrote:

yield
end

list.should yield_with(1).then(2).then(3).on(:each)

def each
yield 1
yield 2
yield 3
end

Hmmm… I didn’t think about multiple yields…

Or maybe:

obj.when_sent(:message, 1,2,3).should yield(6)

I don’t know if the extra ‘with’ layer is needed since the sending of
messages to objects is a very commonly used idiom in ruby.
To keep the rspec syntax consistent your suggestion may be better so I
could see it either way.

(1…3).receiving(:each_with_index).should
yield_with([1,0]).then([2,1]).then([3,2])

or

(1…3).receiving(:each_with_index).should yield_with([1,0], [2,1],[3,2])

The multiple args in the yield/yield_with call is more consistent with
the way rspec’s mocking of return values work (i.e.
mock.shou…and_return([1,2],[0,4]) )
than the ‘then’ syntax suggested above.
I guess I could go either way on this one as well.

(1…3).receiving(:inject).with(0).should yield_with ???

Now it gets tricky since the sequence of yielded values depends on the block .

I don’t know that I like where this is going.

My original goal was only to ease the pain on my eyes for the the simple
cases. I never considered the more involved cases, so you make a good
point. I can’t think of an eloquent way of handling this.
I don’t think a matcher could ever handle all of the cases.

Hmmm…

-Ben

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs