ActiveRecord, spec'ing find has right :order parameter

I’m wanting to write a spec that a model is applying an :order option
to a find call, but I don’t want to completely specify all of the find
parameters.

So I want to write something like this, say in a controller spec

User.should_receive(:find).with(:all, hash_with_at_least(:order =>
‘user.name ASC’))
get ‘index’, :sort => ‘up’

This ability to partially specify the contents of a hash argument
seems to be generally useful, particularly for Rails, and was
wondering if anyone had done this. I don’t think it would be too hard.


Rick DeNatale

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

On Wed, Mar 5, 2008 at 12:28 PM, Rick DeNatale [email protected]
wrote:

This ability to partially specify the contents of a hash argument
seems to be generally useful, particularly for Rails, and was
wondering if anyone had done this. I don’t think it would be too hard.

And by the way, here’s my sketch of how to do this, just looking not
to reinvent the wheel:

class HashWithAtLeast

def initialize(aHash)
@expected = aHash
end

def ==(other)
@expected.each do |key, value|
return false unless other[key] == value
end
true
end

def to_s
“Hash with at least (@expected.inspect)”
end
end

def hash_with_at_least(hash)
HashWithAtLeast.new(hash)
end

describe HashWithAtLeast do
it “should match the same hash” do
hash_with_at_least(:a => 2).should == {:a => 2}
end

it “should match a hash with an extra key/value” do
hash_with_at_least(:a => 2).should == {:a => 2, :b => 3}
end

it “should not match a hash with a missing key” do
hash_with_at_least(:a => 2).should_not == {:b => 2}
hash_with_at_least(:a => 2, :b => 3).should_not == {:a => 2}
end

it “should not match a hash with the wrong value for a key” do
hash_with_at_least(:a => 2).should_not == {:a => 3}
hash_with_at_least(:a => 2, :b => 3).should_not == {:a => 0, :b =>
3}
end

end

describe HashWithAtLeast, “in a message expectation” do
before(:all) do
@foo = Object.new
end

it “should match exact” do
@foo.should_receive(:bar).with(hash_with_at_least(:a => 2))
@foo.bar(:a => 2)
end

it “should allow extra keys” do
@foo.should_receive(:bar).with(hash_with_at_least(:a => 2))
@foo.bar(:a => 2, :b => 3)
end
end


Rick DeNatale

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

On Mar 5, 2008, at 9:43 AM, Rick DeNatale wrote:

And by the way, here’s my sketch of how to do this, just looking not
to reinvent the wheel:

Are you aware that Rails extends Hash with a few extra methods:

mymac:~/rails/myproj $ script/console
Loading development environment (Rails 2.0.2)

a = {:foo=>‘bar’, :zoo => ‘zar’}
=> {:foo=>“bar”, :zoo=>“zar”}

a.except(:foo)
=> {:zoo=>“zar”}

What’s cool about this is that you can specify a fully valid hash once
in a before block, then reuse it, omitting k/v pairs in order to
verify behavior of missing-value conditions.

This doesn’t exactly answer your need, but perhaps it will help.

On Wed, Mar 5, 2008 at 1:31 PM, David C. [email protected]
wrote:

So I want to write something like this, say in a controller spec

User.should_receive(:find).with(:all, hash_with_at_least(:order =>
‘user.name ASC’))
get ‘index’, :sort => ‘up’

I really like this idea. What about something more general that can
handle the first n args too?

That’s a horse of a different color I think. It would need to dig
into MessageExpectation#with and/or the way ArgumentExpectations are
built.

Dealing with it an argument at a time is easy since it just needs ==
to ‘do the right thing’ on an argument ‘proxy’.


Rick DeNatale

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

On Mar 5, 2008, at 11:43 AM, “Rick DeNatale” [email protected]
wrote:

‘user.name ASC’))
get ‘index’, :sort => ‘up’

I really like this idea. What about something more general that can
handle the first n args too?

On Mar 5, 2008, at 2:57 PM, “Rick DeNatale” [email protected]
wrote:

option
I really like this idea. What about something more general that can
handle the first n args too?

That’s a horse of a different color I think. It would need to dig
into MessageExpectation#with and/or the way ArgumentExpectations are
built.

Dealing with it an argument at a time is easy since it just needs ==
to ‘do the right thing’ on an argument ‘proxy’.

Agreed.

I think hash_with would be clear enough and a bit more terse. Agree?

On 3/5/08, David C. [email protected] wrote:

User.should_receive(:find).with(:all, hash_with_at_least(:order =>
Dealing with it an argument at a time is easy since it just needs ==
to ‘do the right thing’ on an argument ‘proxy’.

Agreed.

I think hash_with would be clear enough and a bit more terse. Agree?

Well that name has been bandied about for other purposes
http://www.google.com/search?q=hash_with

Maybe options_with since I think Rails tends to call a trailing hash
argument options, or looking ahead to ruby 1.9, keywords_with

These still don’t really feel exactly right to me though since they
don’t carry the connotation that other key/values are acceptable.

Another alternatives, which trade off slightly less brevity for a bit
more clarity, might be hash_including

Personally, since most folks use capable editors, I’m less concerned
with minimizing keystrokes, for example in textmate, a longer and
clearer version can be had for the cost of an esc key or a snippet.


Rick DeNatale

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

On Mar 5, 2008, at 6:22 PM, “Rick DeNatale” [email protected]
wrote:

wrote:

built.
hash_with - Google Search

Maybe options_with since I think Rails tends to call a trailing hash
argument options, or looking ahead to ruby 1.9, keywords_with

These still don’t really feel exactly right to me though since they
don’t carry the connotation that other key/values are acceptable.

Another alternatives, which trade off slightly less brevity for a bit
more clarity, might be hash_including

I like that. Have at it.

Cheers,
David

On Wed, Mar 5, 2008 at 12:28 PM, Rick DeNatale [email protected]
wrote:

This ability to partially specify the contents of a hash argument
seems to be generally useful, particularly for Rails, and was
wondering if anyone had done this. I don’t think it would be too hard.

Are you just wanting Mocha parameter matching?

User.should_receive(:find).with(:all, has_entry(:order => ‘user.name
ASC’))
get ‘index’, :sort => ‘up’

Pat M. wrote:

[email protected]

into MessageExpectation#with and/or the way ArgumentExpectations are
Well that name has been bandied about for other purposes

Pat


rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users

I thought the same thing, but I have also wanted to only check certain
keys in a hash before so I think that is really what this discussion is
about. Whether or not that logic should be in the model is somewhat
inconsequential because the functionality that is being proposed could
be used elsewhere. I think having this would allow specs to be more
flexible and not tie them to the implementation as much in some cases.

-Ben

On Wed, Mar 5, 2008 at 4:22 PM, Rick DeNatale [email protected]
wrote:

So I want to write something like this, say in a controller spec
built.
hash_with - Google Search
Personally, since most folks use capable editors, I’m less concerned
with minimizing keystrokes, for example in textmate, a longer and
clearer version can be had for the cost of an esc key or a snippet.

Am I the only one that hates this whole thing and thinks it ought to be
User.should_receive(:all_sorted_by_name)

?

Pat

On Thu, Mar 6, 2008 at 1:01 AM, Pat M. [email protected] wrote:

On Mar 5, 2008, at 11:43 AM, “Rick DeNatale”

parameters.
That’s a horse of a different color I think. It would need to dig

more clarity, might be hash_including

Personally, since most folks use capable editors, I’m less concerned
with minimizing keystrokes, for example in textmate, a longer and
clearer version can be had for the cost of an esc key or a snippet.

Am I the only one that hates this whole thing and thinks it ought to be
User.should_receive(:all_sorted_by_name) ?

But wouldn’t you want that spec’d on the model?

On Thu, Mar 6, 2008 at 1:21 AM, Ben M. [email protected] wrote:

[email protected] wrote:

find

I think hash_with would be clear enough and a bit more terse. Agree?
Another alternatives, which trade off slightly less brevity for a bit

keys in a hash before so I think that is really what this discussion is
about. Whether or not that logic should be in the model is somewhat
inconsequential because the functionality that is being proposed could
be used elsewhere. I think having this would allow specs to be more
flexible and not tie them to the implementation as much in some cases.

+1

David

On Thu, Mar 6, 2008 at 5:50 AM, David C. [email protected]
wrote:

On Thu, Mar 6, 2008 at 1:01 AM, Pat M. [email protected] wrote:

On Wed, Mar 5, 2008 at 12:28 PM, Rick DeNatale <[email protected]

wrote:
So I want to write something like this, say in a controller spec

User.should_receive(:find).with(:all, hash_with_at_least(:order =>
‘user.name ASC’))
get ‘index’, :sort => ‘up’

Am I the only one that hates this whole thing and thinks it ought to be
User.should_receive(:all_sorted_by_name) ?

But wouldn’t you want that spec’d on the model?

Yes, but my spec would hit the db. (1) I feel icky specifying the
call to find so precisely (2) the behavior that I want is to find
stuff in a certain order, the fact that it uses AR is an
implementation detail (3) “don’t mock APIs you don’t own”

However I can also +1 Ben M.'s reply that partial hash matching is
an interesting problem in its own right.

Pat

On Thu, Mar 6, 2008 at 12:52 AM, Zach D. [email protected]
wrote:

get ‘index’, :sort => ‘up’
RSpec has similar parameter matching:
http://blog.davidchelimsky.net/articles/2007/02/25/matchers-doing-double-duty

That’s why Rick is talking about writing a parameter matcher :slight_smile: