[rspec-users] array order-agnostic matching?

James OBrien james at rapleaf.com
Tue Feb 1 12:01:51 EST 2011


additionally,

since my

*foo.should_receive(...

*expectation
*
*is actually in a private helper method ('expect_call') on the example group
I will need to pull this code up into a block, since not all callers pass a
hash with :some_key set

viz:

#helper_method
*def expect_call
  foo.should_receiver(:bar) do |hash|
    yield hash
  end
end*

then those examples which dont care about my array ordering problem (or
rather care that it is in order!) can just do:

*expect_call do |actual_hash|
  actual_hash.should == {:some => 'expected_value', :other => [4,5,6]}
end*

and the one case that does care can do:

*expect_call do |actual_hash|
    actual = **actual_hash[:some_key]
    **actual_hash**[:some_key] = nil
    **actual_hash.should == {
      :my => 'expected'
      :other => 1
      :ields => :in_the_hash
    }
    actual.should =~ [1,2,3]
** end*

does this sound sensible?

Thanks so much again - I have your book :) and although I'm new to it I
really enjoy rspec!

On Tue, Feb 1, 2011 at 8:51 AM, James OBrien <james at rapleaf.com> wrote:

> ooops, that sent itself early...
>
> . . .
>
> there are other entries in the hash so presumably I will need something
> like this
>
> foo.should_receive(:bar) do |hash|
>     actual = hash[:some_key]
>     *hash[:some_key] = nil*
>     hash.should == {
>       :my => 'expected'
>       :other => 1
>       :ields => :in_the_hash
>     }
>     actual.should =~ [1,2,3]
>
>   end
>
> i.e. I assert :some_key and 'the rest' separately.
>
> There isn't a way to do this simpler is there?
>
> Thanks again David!
>
>
> On Tue, Feb 1, 2011 at 8:46 AM, James OBrien <james at rapleaf.com> wrote:
>
>> Awesome, thanks David!
>>
>> there are other entries in the hash so presumably I will need something
>> like this
>>
>> i.e.
>>
>>
>>   foo.should_receive(:bar) do |hash|
>>     actual = hash[:some_key]
>>
>>     hash[:some_key].should =~ [1,2,3]
>>     hash.shoul
>>   end
>>
>>
>>
>>
>> On Tue, Feb 1, 2011 at 4:43 AM, David Chelimsky <dchelimsky at gmail.com>wrote:
>>
>>>
>>> On Feb 1, 2011, at 3:40 AM, James OBrien wrote:
>>>
>>> hey, thanks for reading:
>>>
>>> I have a problem which can be reduced to this,
>>>
>>> from within an example of mine I call the helper 'expect_call' which is
>>> defined thus:
>>>
>>> def expect_call(*hash*)*
>>>   *obj.should_receive(:some_
>>> method).with(*hash*)*
>>> *end
>>>
>>> and in one of my examples the 'expected' hash is strictly defined as
>>> follows
>>>
>>> expect_call(*{
>>>    :some_key => [1,2,3]
>>> }*)
>>>
>>> however my spec fails because it is actually called with
>>>
>>> *{
>>>    :some_key => [1,3,2]
>>> }
>>>
>>> *or maybe
>>>
>>> *{
>>>    :some_key => [2,3,1]
>>> }
>>>
>>> *or
>>>
>>> *{
>>>    :some_key => [2,1,3]
>>> }
>>>
>>> *i.e. the array part is not in the order i 'expect' BUT i don't actually
>>> care about the order. So I would like to be able to change my one example to
>>> something like this:
>>>
>>> expect_call(*{
>>>    *:some_key => [1,2,3]*.ignoring_order
>>> }*)
>>>
>>> does such a concept exist or do I have to change the implementation of
>>> expect_call to use some sort of custom matcher - I am reluctant to do this
>>> since this method is called in other cases where maybe (for arguments sake)
>>> I DO care about array ordering within the hash.
>>>
>>>
>>> rspec-expectations lets you do this:
>>>
>>>   foo.bar.should =~ [1,2,3]
>>>
>>> This passes as long as the array contains exactly those three elements in
>>> any order. You can use this now in conjunction with rspec-mocks, like this:
>>>
>>>   foo.should_receive(:bar) do |hash|
>>>     hash[:some_key].should =~ [1,2,3]
>>>   end
>>>
>>> It's a bit more verbose than what you're looking for, but it can get you
>>> there with rspec as/is today.
>>>
>>> Going forward, we might want to consider an array_including argument
>>> matcher for rspec-mocks. We already have a hash_including matcher that works
>>> like this:
>>>
>>>   foo.should_receive(:bar).with(hash_including(:a => 'b'))
>>>
>>> Similarly we could have:
>>>
>>>   foo.should_receive(:bar).with(array_including(1,2,3))
>>>
>>> The only problem with this is the name: array_including could mean
>>> different things (ordered/unordered, only these elements or subset, etc).
>>> The hash_including matcher is specifically about a subset of a hash. But
>>> perhaps we could extend this with something like you proposed above:
>>>
>>>   foo.should_receive(:bar).with(array_including(1,2,3))
>>>   foo.should_receive(:bar).with(array_including(1,2,3).ingoring_order)
>>>
>>>   foo.should_receive(:bar).with(array_including(1,2,3).only.ingoring_order)
>>>
>>> The thing is, I'm not sure this is any better than the example I gave
>>> above, which is very precise and works today. Thoughts/opinions welcome.
>>>
>>> Hope someone can solve this for me - MUCH appreciation.
>>>
>>>
>>> As an aside, when passing a hash as an argument you don't need to use
>>> curly braces, as long as the hash is the last argument to the method. These
>>> two are equivalent:
>>>
>>>   expect_call(1, :a, {:some_key => 'some value'})
>>>   expect_call(1, :a, :some_key => 'some value')
>>>
>>> HTH,
>>> David
>>>
>>>
>>>
>>>
>>> _______________________________________________
>>> rspec-users mailing list
>>> rspec-users at rubyforge.org
>>> http://rubyforge.org/mailman/listinfo/rspec-users
>>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20110201/5aa990a5/attachment.html>


More information about the rspec-users mailing list