[rspec-users] Odd parameter munging with with()

David Chelimsky dchelimsky at gmail.com
Thu Feb 15 10:09:15 EST 2007


On 2/15/07, Jerry West <jerry.west at ntlworld.com> wrote:
>
>  James,
>
>  the gem is converting your hash to an array of arrays when it builds the
> mock expectation.  This is really an artifact of Ruby's hash/array handling
> - the code in the gem looks perfectly reasonable, it just has this
> side-effect.
>
>  If you check out
> $GEM_DIR/rspec-0.7.5.1/lib/spec/mocks/message_expectation.rb
> you will see that #with() passes your hash to a new instance of
> ArgumentExpectation, which is defined in
> $GEM_DIR/rspec-0.7.5.1/lib/spec/mocks/argument_expectation.rb
> .   There you will see that a hash is a LiteralArgConstraint (as opposed to
> :anything, :numeric, and the other parameters that #with() accepts).  The
> interesting code is around line 89 in #process_arg_constraints() where your
> hash is converted one item at a time using the normal Ruby Enumerable
> routine #collect().  Which is where the side-effect happens.
>
>  Try this in irb:
>
>  $ irb
> irb(main):001:0> @params = {:cn => "Bilbo Baggins", :telephoneNumber =>
> "416-277-4418", :mail => "bilbo at baggins.com"}
>
>  irb(main):002:0> @params.collect{|c| c}
>  => [[:cn, "Bilbo Baggins"], [:telephoneNumber, "416-277-4418"], [:mail,
> "bilbo at baggins.com"]]
>  irb(main):003:0>
>
>  and you will see that your hash has been converted into the array of
> arrays.  That's what happening in the gem once you strip away
> #convert_constraint() etc.
>
>  You have a choice of workarounds; the simplest of which is a separate array
> @params_for_mock_user = @params.collect ; (null body returns each element as
> above) and then
> User.should_receive(:update_attributes).with(@params_for_mock_user).
>
>  It might be worth filing an RFE on this as it's counter-intuitive and
> likely to bite others as well

Jerry - thanks for explaining this.
James - an RFE would be great.

Cheers,
David

>
>  Hope this helps.
>
>  Rgds,
>    Jerry
>
>
>
>  James Hughes wrote:
>  Hi,
>
> I have this setup block:
>
>  setup do
>  session[:login] = 'jhughes'
>  @user = mock("user")
>  User.stub!(:find).and_return(@user)
>  @params = {:cn => "Bilbo Baggins",
>  :telephoneNumber => "416-277-4418",
>  :mail => "bilbo at baggins.com"}
>  end
>
> And then this spec:
>
>  specify "should update and save the attributes for user" do
> @user.should_receive(:update_attributes).with(@params).and_return(true)
>  post :update, :id => "jhughes", :user => @params
>  end
>
> This fails like this:
>
> Mock 'user' expected :update_attributes with ([:telephoneNumber,
> "416-277-4418"], [:mail, "bilbo at baggins.com"], [:cn, "Bilbo Baggins"])
> but received it with ({"cn"=>"Bilbo Baggins",
> "telephoneNumber"=>"416-277-4418",
> "mail"=>"bilbo at baggins.com"})
>
> Puzzling, especially since inspecting the @params variable just before
> the should_receive shows the expected hash.
>
> What am I doing wrong?
>
> James
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>
>
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>


More information about the rspec-users mailing list