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
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type"> </head> <body bgcolor="#ffffff" text="#000000"> James,<br> <br> 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.<br> <br> If you check out <tt>$GEM_DIR/rspec-0.7.5.1/lib/spec/mocks/message_expectation.rb</tt> you will see that <tt>#with()</tt> passes your hash to a new instance of <i>ArgumentExpectation,</i> which is defined in <tt>$GEM_DIR/rspec-0.7.5.1/lib/spec/mocks/argument_expectation.rb</tt> . There you will see that a hash is a <i>LiteralArgConstraint</i> (as opposed to <font color="#3366ff">:anything,</font> <font color="#3366ff">:numeric</font>, and the other parameters that <tt>#with()</tt> accepts). The interesting code is around line 89 in <tt>#process_arg_constraints()</tt> where your hash is converted one item at a time using the normal Ruby <i>Enumerable</i> routine <tt>#collect()</tt>. Which is where the side-effect happens.<br> <br> Try this in irb:<br> <br> <pre>$ irb irb(main):001:0> @params = {:cn => "Bilbo Baggins", :telephoneNumber => "416-277-4418", :mail => <a class="moz-txt-link-rfc2396E" href="mailto:bilbo@baggins.com">"bilbo@baggins.com"</a>} </pre> <pre>irb(main):002:0> @params.collect{|c| c}</pre> <pre>=> [[:cn, "Bilbo Baggins"], [:telephoneNumber, "416-277-4418"], [:mail, <a class="moz-txt-link-rfc2396E" href="mailto:bilbo@baggins.com">"bilbo@baggins.com"</a>]]</pre> <pre>irb(main):003:0> </pre> <br> 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 <tt>#convert_constraint()</tt> etc.<br> <br> You have a choice of workarounds; the simplest of which is a separate array <tt>@params_for_mock_user = @params.collect</tt> ; (null body returns each element as above) and then <tt>User.should_receive(:update_attributes).with(@params_for_mock_user).<br> <br> </tt>It might be worth <a href="http://rubyforge.org/tracker/?atid=3152&group_id=797&func=browse">filing an RFE</a> on this as it''s counter-intuitive and likely to bite others as well<br> <tt><br> </tt>Hope this helps.<br> <br> Rgds,<br> Jerry<br> <br> <br> James Hughes wrote: <blockquote cite="mid765a2c230702141600j33b98be7w22dab72e5c2cbc10@mail.gmail.com" type="cite"> <pre wrap="">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 => <a class="moz-txt-link-rfc2396E" href="mailto:bilbo@baggins.com">"bilbo@baggins.com"</a>} 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, <a class="moz-txt-link-rfc2396E" href="mailto:bilbo@baggins.com">"bilbo@baggins.com"</a>], [:cn, "Bilbo Baggins"]) but received it with ({"cn"=>"Bilbo Baggins", "telephoneNumber"=>"416-277-4418", "mail"=><a class="moz-txt-link-rfc2396E" href="mailto:bilbo@baggins.com">"bilbo@baggins.com"</a>}) 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 <a class="moz-txt-link-abbreviated" href="mailto:rspec-users@rubyforge.org">rspec-users@rubyforge.org</a> <a class="moz-txt-link-freetext" href="http://rubyforge.org/mailman/listinfo/rspec-users">http://rubyforge.org/mailman/listinfo/rspec-users</a> </pre> </blockquote> </body> </html>
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 wellJerry - 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 >
On 2/15/07, David Chelimsky <dchelimsky at gmail.com> wrote:> 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.Ok, I''ll take a crack at it after I''ve had a chance to assimilate Jerry''s explanation. (Thanks, Jerry.) James
Hi again, 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).Ok, this works (once I figured out that you have to send the @params_for_mock_user with the post as well, duh;), but I have another method that does this: user_klass = params[:user].delete(:ou).capitalize.constantize @user = user_klass.create(params[:user]) When the spec runs I''m calling delete on an array instead of the expected hash, which returns nil. Jerry, you mentioned a choice of workarounds: anything come to mind that might work around this?> > It might be worth filing an RFE on this as it''s counter-intuitive and > likely to bite others as well >I''m writing this up right now.. James> 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 >
On 2/15/07, Jerry West <jerry.west at ntlworld.com> wrote:> > It might be worth filing an RFE on this as it''s counter-intuitive and > likely to bite others as wellHello again, In trying to create some simple code that would reproduce this without all the rails dependencies for an RFE, I came up with this: class Test def Test.amethod params true end end context "passing a hash to #with" do specify "should pass a hash to #with" do @params = { :param1 => "foo", :param2 => "bar"} Test.should_receive(:amethod).with(@params).and_return(true) Test.amethod @params end end I thought this was conceptually the same as my failing spec from the original post, but obviously it''s not, as it passes. Can anyone explain what the difference is? thanks, James> 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
On 2/19/07, James Hughes <hughes.james at gmail.com> wrote:> On 2/15/07, Jerry West <jerry.west at ntlworld.com> wrote: > > > > It might be worth filing an RFE on this as it''s counter-intuitive and > > likely to bite others as well > > Hello again, > > In trying to create some simple code that would reproduce this without > all the rails dependencies for an RFE, I came up with this: > > class Test > def Test.amethod params > true > end > end > context "passing a hash to #with" do > specify "should pass a hash to #with" do > @params = { :param1 => "foo", > :param2 => "bar"} > Test.should_receive(:amethod).with(@params).and_return(true) > Test.amethod @params > end > end > > I thought this was conceptually the same as my failing spec from the > original post, but obviously it''s not, as it passes. Can anyone > explain what the difference is?The difference that I see is that the new example passes @params directly to Test.amethod, whereas the earlier example uses "post :update". So I''m guessing that the problem is related specifically to how "post :update" packages up the arguments to pass to the model. WDYT?> > thanks, > James > > > 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 >
On 2/19/07, David Chelimsky <dchelimsky at gmail.com> wrote:> On 2/19/07, James Hughes <hughes.james at gmail.com> wrote: > > On 2/15/07, Jerry West <jerry.west at ntlworld.com> wrote: > > > > > > It might be worth filing an RFE on this as it''s counter-intuitive and > > > likely to bite others as well > > > > Hello again, > > > > In trying to create some simple code that would reproduce this without > > all the rails dependencies for an RFE, I came up with this: > > > > class Test > > def Test.amethod params > > true > > end > > end > > context "passing a hash to #with" do > > specify "should pass a hash to #with" do > > @params = { :param1 => "foo", > > :param2 => "bar"} > > Test.should_receive(:amethod).with(@params).and_return(true) > > Test.amethod @params > > end > > end > > > > I thought this was conceptually the same as my failing spec from the > > original post, but obviously it''s not, as it passes. Can anyone > > explain what the difference is? > > The difference that I see is that the new example passes @params > directly to Test.amethod, whereas the earlier example uses "post > :update". So I''m guessing that the problem is related specifically to > how "post :update" packages up the arguments to pass to the model. > > WDYT?If the failure message is to be believed, it''s #with that is packaging up the arguments in an odd way. Take a look at the failure message again:> > > 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"})See what I mean? (I just checked, and post was doing one modification to @params: it was changing the keys from symbols to strings. However, changing the @params keys to strings in the spec still produces the same error as above, so that''s not the problem.) For final proof, here''s the output from a couple of print statements, one in the spec just before post(), and one in the controller action, just before calling update_attributes: ............in spec {"cn"=>"Bilbo Baggins", "telephoneNumber"=>"416-277-4418", "mail"=>"bilbo at baggins.com"} in controller {"cn"=>"Bilbo Baggins", "telephoneNumber"=>"416-277-4418", "mail"=>"bilbo at baggins.com"} So, I still say my app code and my reduction look conceptually the same, but I''m stumped as to why they don''t behave the same way (not to mention I don''t understand the need for #with to mangle it''s args as it does). James
On 2/19/07, James Hughes <hughes.james at gmail.com> wrote:> On 2/19/07, David Chelimsky <dchelimsky at gmail.com> wrote: > > On 2/19/07, James Hughes <hughes.james at gmail.com> wrote: > > > On 2/15/07, Jerry West <jerry.west at ntlworld.com> wrote: > > > > > > > > It might be worth filing an RFE on this as it''s counter-intuitive and > > > > likely to bite others as well > > > > > > Hello again, > > > > > > In trying to create some simple code that would reproduce this without > > > all the rails dependencies for an RFE, I came up with this: > > > > > > class Test > > > def Test.amethod params > > > true > > > end > > > end > > > context "passing a hash to #with" do > > > specify "should pass a hash to #with" do > > > @params = { :param1 => "foo", > > > :param2 => "bar"} > > > Test.should_receive(:amethod).with(@params).and_return(true) > > > Test.amethod @params > > > end > > > end > > > > > > I thought this was conceptually the same as my failing spec from the > > > original post, but obviously it''s not, as it passes. Can anyone > > > explain what the difference is? > > > > The difference that I see is that the new example passes @params > > directly to Test.amethod, whereas the earlier example uses "post > > :update". So I''m guessing that the problem is related specifically to > > how "post :update" packages up the arguments to pass to the model. > > > > WDYT? > > If the failure message is to be believed, it''s #with that is packaging > up the arguments in an odd way. > Take a look at the failure message again: > > > > > 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"}) > > See what I mean? (I just checked, and post was doing one modification > to @params: it was changing the keys from symbols to strings. However, > changing the @params keys to strings in the spec still produces the > same error as above, so that''s not the problem.) For final proof, > here''s the output from a couple of print statements, one in the spec > just before post(), and one in the controller action, just before > calling update_attributes: > > ............in spec > {"cn"=>"Bilbo Baggins", "telephoneNumber"=>"416-277-4418", > "mail"=>"bilbo at baggins.com"} > in controller > {"cn"=>"Bilbo Baggins", "telephoneNumber"=>"416-277-4418", > "mail"=>"bilbo at baggins.com"} > > So, I still say my app code and my reduction look conceptually the > same, but I''m stumped as to why they don''t behave the same way (not to > mention I don''t understand the need for #with to mangle it''s args as > it does).RSpec is doing the comparison correctly. The Rails version is comparing a Hash with stringified keys w/ a Hash w/ symbols as keys, whereas the other version is comparing the exact same Hash (w/ symbol keys) with itself. The bug is really in the message. I''m fixing the message so it''ll correctly show you the expected Hash, but IMO RSpec shouldn''t be messing around w/ keys. WDYT? David> > James > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type"> </head> <body bgcolor="#ffffff" text="#000000"> <br> <blockquote cite="mid765a2c230702192014j7a365acfg3563a61301413815@mail.gmail.com" type="cite"> <pre wrap="">(not to mention I don''t understand the need for #with to mangle it''s args as it does).</pre> </blockquote> Ah, now you''re asking. <br> <br> <tt>#with</tt> needs to cope with a number of different types of arguments. It could do this by using a case statement or just if/else If there were only two options which could be passed in, that might have been the best way to do it. But actually, the interface for #with is really quite complex, taking different types of arguments that need different treatment. However, although the arguments are different, the things that need to be done to/with them are the same. <br> <br> Since, we''re using an object oriented language, it''s considered good practice to implement this form of polymorphism<sup>[1]</sup> by delegation - we leave the details of implementation to someone else! Essentially, we''re defining an API and implementing a different class (<tt>LiteralArgConstraint,</tt> <tt>NumericArgConstraint,</tt> <tt>RegexArgConstraint</tt>, etc) for each possibility (a.k.a. duck-typing<sup>[2]</sup>)<i> </i>. <br> <br> This simplifies the handling code immensely - all it does is iterate over the arguments and ask the correct constraint handler to do the right thing. Regretably the way it does this iteration has the unfortunate side effect we are seeing. This would probably happen even if David hadn''t chosen to ''mangle the args'' as he does. It''s a side-effect of <tt>Hash#each</tt>.<br> <br> Polymorphic delegation also makes the code more scalable (we only have to implement a new constraint handler when someone comes up with a super new idea (e.g. <tt>DuckTypeArgConstraint</tt>); and easier to maintain (code is localised and hopefully it''s easier to find and fix bugs). There is an argument that the extra layer introduced adds complexity, but IMHO once you understand the paradigm, its interpretation is obvious and the tradeoffs are appropriate. Spaghetti code is a nightmare to maintain!<br> <br> Rgds,<br> Jerry<br> <br> [1] Polymorphic - having more than one form. So polymorphism in a method is the ability to deal with arguments of different types. Polymorphism in a class (well, classes) is the ability of different classes to respond to the same method call, to do what is expected of them each in their own distinctly different way. This is the posh term for what every Ruby programmer instinctively knows because they see it every time they use Enumerable#each on Hash, Array, or String for example.<br> <br> [2] The term is a reference to the <u>duck test </u>— "If it walks like a duck and quacks like a duck, it must be a duck". <br> <br> Check out Wikipedia on the subjects of polymorphism and duck-typing, though the articles are a bit too academic for my taste - and I''m a teacher!<br> <br> If you wanted to, you might submit a HashArgConstraint class as a possible patch to <tt>lib/specs/mocks/argument_epectation.rb</tt>. This would ''know'' that it would receive an array of arrays and adjust its expectation accordingly. Or have I just slipped into teaching mode again? Sorry.<br> </body> </html>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type"> </head> <body bgcolor="#ffffff" text="#000000"> <br> <blockquote cite="mid765a2c230702192014j7a365acfg3563a61301413815@mail.gmail.com" type="cite"> <pre wrap=""> So, I still say my app code and my reduction look conceptually the same, but I''m stumped as to why they don''t behave the same way </pre> </blockquote> David seems to have picked that up. Ignore my blatherings about HashArgConstraint (though the rest is valid).<br> <br> Here''s another twist under Rails 1.2.2 (which may not be supported but works fine for what I am doing so far). <br> <br> Basically, a different <u>expectation</u> seems to be set up depending on whether the argument to get/post is a variable or not. That cannot be right. What am I missing?<br> <br> <tt>require File.dirname(__FILE__) + ''/../spec_helper''<br> <br> class TestController < ActionController::Base<br> def index() self.amethod(params) end<br> end<br> <br> context ''a test controller'' do<br> controller_name :test<br> <br> setup do<br> @plist = { "id" => "1", "param2" => "bar" }<br> controller.should_receive(:amethod).with(@plist).and_return(true)<br> end<br> <br> specify "should pass a hash to #with (1)" do<br> get :index, "id" => "1", "param2" => "bar"<br> end<br> specify "should pass a hash to #with (2)" do<br> get :index, { "id" => "1", "param2" => "bar" }<br> end<br> specify "should pass a hash to #with (3)" do<br> get :index, @plist<br> end<br> end<br> <br> </tt><tt>$ spec -cfs spec/controllers/test_controller_spec.rb <br> /usr/bin/spec:17:Warning: require_gem is obsolete. Use gem instead.<br> /home/jjw/rails/playground/config/boot.rb:29:Warning: require_gem is obsolete. Use gem instead.<br> <br> a test controller<br> - should pass a hash to #with (1) (FAILED - 1)<br> - should pass a hash to #with (2) (FAILED - 2)<br> - should pass a hash to #with (3) (FAILED - 3)<br> <br> 1)<br> ''a test controller should pass a hash to #with (1)'' FAILED <b>(ignore the failure, look at the expectation)</b><br> #<TestController:0xb70a1df8> expected :amethod with (["param2", "bar"], ["id", "1"]) but received it with ({"action"=>"index", "id"=>"1", "param2"=>"bar", "controller"=>"test"})<br> (eval):3:in `amethod''<br> ./spec/controllers/test_controller_spec.rb:4:in `index''<br> /usr/local/lib/site_ruby/1.8/benchmark.rb:300:in `measure''<br> ./spec/controllers/test_controller_spec.rb:13:<br> <br> 2)<br> ''a test controller should pass a hash to #with (2)'' FAILED </tt><tt><b>(ignore the failure, look at the expectation)</b></tt><br> <tt>#<TestController:0xb7093820> expected :amethod with (["param2", "bar"], ["id", "1"]) but received it with ({"action"=>"index", "id"=>"1", "param2"=>"bar", "controller"=>"test"})<br> (eval):3:in `amethod''<br> ./spec/controllers/test_controller_spec.rb:4:in `index''<br> /usr/local/lib/site_ruby/1.8/benchmark.rb:300:in `measure''<br> ./spec/controllers/test_controller_spec.rb:18:<br> <br> 3)<br> ''a test controller should pass a hash to #with (3)'' FAILED </tt><tt><b>(ignore the failure, look at the expectation)</b></tt><br> <tt>#<TestController:0xb708cf34> expected :amethod with (<b>[:only_path, true]</b>, ["param2", "bar"], ["id", "1"], <b>[:action, :index]</b>) but received it with ({"action"=>"index", "id"=>"1", "param2"=>"bar", "controller"=>"test"})<br> (eval):3:in `amethod''<br> ./spec/controllers/test_controller_spec.rb:4:in `index''<br> /usr/local/lib/site_ruby/1.8/benchmark.rb:300:in `measure''<br> ./spec/controllers/test_controller_spec.rb:23:<br> <br> Finished in 0.022612 seconds<br> <br> 3 specifications, 3 failures<br> <br> <br> </tt>Where the heck did the :only_path stuff come from in the expectation for case 3?? They weren''t there in ArgumentExpectation#initialize.<br> <br> As expected, creating the ''right'' expectation (<tt>@plist = { "id" => "1","param2" => "bar", "action" => "index", "controller" => "test" } ) </tt>allows the spec to pass in cases 1 & 2, but #3 still fails.<br> <br> rgds from "Confused of Hampshire".<br> <br> <br> <tt><br> </tt> </body> </html>
On 2/20/07, Jerry West <jerry.west at ntlworld.com> wrote:> > > > So, I still say my app code and my reduction look conceptually the > same, but I''m stumped as to why they don''t behave the same way > > David seems to have picked that up. Ignore my blatherings about > HashArgConstraint (though the rest is valid). > > Here''s another twist under Rails 1.2.2 (which may not be supported but > works fine for what I am doing so far). > > Basically, a different expectation seems to be set up depending on whether > the argument to get/post is a variable or not. That cannot be right. What > am I missing? > > require File.dirname(__FILE__) + ''/../spec_helper'' > > class TestController < ActionController::Base > def index() self.amethod(params) end > end > > context ''a test controller'' do > controller_name :test > > setup do > @plist = { "id" => "1", "param2" => "bar" } > > controller.should_receive(:amethod).with(@plist).and_return(true) > end > > specify "should pass a hash to #with (1)" do > get :index, "id" => "1", "param2" => "bar" > end > specify "should pass a hash to #with (2)" do > get :index, { "id" => "1", "param2" => "bar" } > end > specify "should pass a hash to #with (3)" do > get :index, @plist > end > end > > $ spec -cfs spec/controllers/test_controller_spec.rb > /usr/bin/spec:17:Warning: require_gem is obsolete. Use gem instead. > /home/jjw/rails/playground/config/boot.rb:29:Warning: > require_gem is obsolete. Use gem instead. > > a test controller > - should pass a hash to #with (1) (FAILED - 1) > - should pass a hash to #with (2) (FAILED - 2) > - should pass a hash to #with (3) (FAILED - 3) > > 1) > ''a test controller should pass a hash to #with (1)'' FAILED (ignore the > failure, look at the expectation) > #<TestController:0xb70a1df8> expected :amethod with (["param2", "bar"], > ["id", "1"]) but received it with ({"action"=>"index", "id"=>"1", > "param2"=>"bar", "controller"=>"test"}) > (eval):3:in `amethod'' > ./spec/controllers/test_controller_spec.rb:4:in `index'' > /usr/local/lib/site_ruby/1.8/benchmark.rb:300:in `measure'' > ./spec/controllers/test_controller_spec.rb:13: > > 2) > ''a test controller should pass a hash to #with (2)'' FAILED (ignore the > failure, look at the expectation) > #<TestController:0xb7093820> expected :amethod with (["param2", "bar"], > ["id", "1"]) but received it with ({"action"=>"index", "id"=>"1", > "param2"=>"bar", "controller"=>"test"}) > (eval):3:in `amethod'' > ./spec/controllers/test_controller_spec.rb:4:in `index'' > /usr/local/lib/site_ruby/1.8/benchmark.rb:300:in `measure'' > ./spec/controllers/test_controller_spec.rb:18: > > 3) > ''a test controller should pass a hash to #with (3)'' FAILED (ignore the > failure, look at the expectation) > #<TestController:0xb708cf34> expected :amethod with ([:only_path, true], > ["param2", "bar"], ["id", "1"], [:action, :index]) but received it with > ({"action"=>"index", "id"=>"1", "param2"=>"bar", "controller"=>"test"}) > (eval):3:in `amethod'' > ./spec/controllers/test_controller_spec.rb:4:in `index'' > /usr/local/lib/site_ruby/1.8/benchmark.rb:300:in `measure'' > ./spec/controllers/test_controller_spec.rb:23: > > Finished in 0.022612 seconds > > 3 specifications, 3 failures > > > Where the heck did the :only_path stuff come from in the expectation for > case 3?? They weren''t there in ArgumentExpectation#initialize. > > As expected, creating the ''right'' expectation (@plist = { "id" => > "1","param2" => "bar", "action" => "index", "controller" => "test" } ) > allows the spec to pass in cases 1 & 2, but #3 still fails.Here''s the same output w/ the latest trunk. Note that it shows #with correctly receiving a Hash now. 1) Spec::Mocks::MockExpectationError in ''a test controller should pass a hash to #with (1)'' #<TestController:0x2578854> expected :amethod with ({"param2"=>"bar", "id"=>"1"}) but received it with ({"action"=>"index", "id"=>"1", "param2"=>"bar", "controller"=>"test"}) ./spec/controllers/temp_spec.rb:4:in `index'' ./spec/controllers/temp_spec.rb:16: 2) Spec::Mocks::MockExpectationError in ''a test controller should pass a hash to #with (2)'' #<TestController:0x2516ec4> expected :amethod with ({"param2"=>"bar", "id"=>"1"}) but received it with ({"action"=>"index", "id"=>"1", "param2"=>"bar", "controller"=>"test"}) ./spec/controllers/temp_spec.rb:4:in `index'' ./spec/controllers/temp_spec.rb:19: 3) Spec::Mocks::MockExpectationError in ''a test controller should pass a hash to #with (3)'' #<TestController:0x2461d58> expected :amethod with ({:only_path=>true, "param2"=>"bar", "id"=>"1", :action=>:index}) but received it with ({"action"=>"index", "id"=>"1", "param2"=>"bar", "controller"=>"test"}) ./spec/controllers/temp_spec.rb:4:in `index'' ./spec/controllers/temp_spec.rb:22: I have NO idea yet about :only_path. I''ll keep you posted...> > rgds from "Confused of Hampshire". > > > > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
On 2/20/07, David Chelimsky <dchelimsky at gmail.com> wrote:> On 2/20/07, Jerry West <jerry.west at ntlworld.com> wrote: > > > > > > > > So, I still say my app code and my reduction look conceptually the > > same, but I''m stumped as to why they don''t behave the same way > > > > David seems to have picked that up. Ignore my blatherings about > > HashArgConstraint (though the rest is valid). > > > > Here''s another twist under Rails 1.2.2 (which may not be supported but > > works fine for what I am doing so far). > > > > Basically, a different expectation seems to be set up depending on whether > > the argument to get/post is a variable or not. That cannot be right. What > > am I missing? > > > > require File.dirname(__FILE__) + ''/../spec_helper'' > > > > class TestController < ActionController::Base > > def index() self.amethod(params) end > > end > > > > context ''a test controller'' do > > controller_name :test > > > > setup do > > @plist = { "id" => "1", "param2" => "bar" } > > > > controller.should_receive(:amethod).with(@plist).and_return(true) > > end > > > > specify "should pass a hash to #with (1)" do > > get :index, "id" => "1", "param2" => "bar" > > end > > specify "should pass a hash to #with (2)" do > > get :index, { "id" => "1", "param2" => "bar" } > > end > > specify "should pass a hash to #with (3)" do > > get :index, @plist > > end > > end > > > > $ spec -cfs spec/controllers/test_controller_spec.rb > > /usr/bin/spec:17:Warning: require_gem is obsolete. Use gem instead. > > /home/jjw/rails/playground/config/boot.rb:29:Warning: > > require_gem is obsolete. Use gem instead. > > > > a test controller > > - should pass a hash to #with (1) (FAILED - 1) > > - should pass a hash to #with (2) (FAILED - 2) > > - should pass a hash to #with (3) (FAILED - 3) > > > > 1) > > ''a test controller should pass a hash to #with (1)'' FAILED (ignore the > > failure, look at the expectation) > > #<TestController:0xb70a1df8> expected :amethod with (["param2", "bar"], > > ["id", "1"]) but received it with ({"action"=>"index", "id"=>"1", > > "param2"=>"bar", "controller"=>"test"}) > > (eval):3:in `amethod'' > > ./spec/controllers/test_controller_spec.rb:4:in `index'' > > /usr/local/lib/site_ruby/1.8/benchmark.rb:300:in `measure'' > > ./spec/controllers/test_controller_spec.rb:13: > > > > 2) > > ''a test controller should pass a hash to #with (2)'' FAILED (ignore the > > failure, look at the expectation) > > #<TestController:0xb7093820> expected :amethod with (["param2", "bar"], > > ["id", "1"]) but received it with ({"action"=>"index", "id"=>"1", > > "param2"=>"bar", "controller"=>"test"}) > > (eval):3:in `amethod'' > > ./spec/controllers/test_controller_spec.rb:4:in `index'' > > /usr/local/lib/site_ruby/1.8/benchmark.rb:300:in `measure'' > > ./spec/controllers/test_controller_spec.rb:18: > > > > 3) > > ''a test controller should pass a hash to #with (3)'' FAILED (ignore the > > failure, look at the expectation) > > #<TestController:0xb708cf34> expected :amethod with ([:only_path, true], > > ["param2", "bar"], ["id", "1"], [:action, :index]) but received it with > > ({"action"=>"index", "id"=>"1", "param2"=>"bar", "controller"=>"test"}) > > (eval):3:in `amethod'' > > ./spec/controllers/test_controller_spec.rb:4:in `index'' > > /usr/local/lib/site_ruby/1.8/benchmark.rb:300:in `measure'' > > ./spec/controllers/test_controller_spec.rb:23: > > > > Finished in 0.022612 seconds > > > > 3 specifications, 3 failures > > > > > > Where the heck did the :only_path stuff come from in the expectation for > > case 3?? They weren''t there in ArgumentExpectation#initialize. > > > > As expected, creating the ''right'' expectation (@plist = { "id" => > > "1","param2" => "bar", "action" => "index", "controller" => "test" } ) > > allows the spec to pass in cases 1 & 2, but #3 still fails. > > Here''s the same output w/ the latest trunk. Note that it shows #with > correctly receiving a Hash now. > > 1) > Spec::Mocks::MockExpectationError in ''a test controller should pass a > hash to #with (1)'' > #<TestController:0x2578854> expected :amethod with ({"param2"=>"bar", > "id"=>"1"}) but received it with ({"action"=>"index", "id"=>"1", > "param2"=>"bar", "controller"=>"test"}) > ./spec/controllers/temp_spec.rb:4:in `index'' > ./spec/controllers/temp_spec.rb:16: > > 2) > Spec::Mocks::MockExpectationError in ''a test controller should pass a > hash to #with (2)'' > #<TestController:0x2516ec4> expected :amethod with ({"param2"=>"bar", > "id"=>"1"}) but received it with ({"action"=>"index", "id"=>"1", > "param2"=>"bar", "controller"=>"test"}) > ./spec/controllers/temp_spec.rb:4:in `index'' > ./spec/controllers/temp_spec.rb:19: > > 3) > Spec::Mocks::MockExpectationError in ''a test controller should pass a > hash to #with (3)'' > #<TestController:0x2461d58> expected :amethod with ({:only_path=>true, > "param2"=>"bar", "id"=>"1", :action=>:index}) but received it with > ({"action"=>"index", "id"=>"1", "param2"=>"bar", > "controller"=>"test"}) > ./spec/controllers/temp_spec.rb:4:in `index'' > ./spec/controllers/temp_spec.rb:22: > > I have NO idea yet about :only_path. I''ll keep you posted...OK, I now have SOME idea, but I''m still trying to figure out specifics. The following passes. Note that it uses @plist.dup each time. require File.dirname(__FILE__) + ''/../spec_helper'' class TestController < ActionController::Base def index() self.amethod(params) end end context ''a test controller'' do controller_name :test setup do @plist = { "id" => "1", "param2" => "bar" , "controller" => "test", "action" => "index" } controller.should_receive(:amethod).with(@plist.dup).and_return(true) end specify "should pass a hash to #with (1)" do get :index, "id" => "1", "param2" => "bar" end specify "should pass a hash to #with (2)" do get :index, { "id" => "1", "param2" => "bar" } end specify "should pass a hash to #with (3)" do get :index, @plist.dup end end If you search through Rails you''ll find dozens of instances of :only_path. So the problem SEEMS to be that by the time we reach the third spec, @plist has been touched by Rails. BTW - here''s a variation that passes and allows you to deal only w/ the subset of keys you want. context ''a test controller'' do controller_name :test setup do controller.should_receive(:amethod).and_return(true) { |params| params["id"].should == "1" params["param2"].should == "bar" } end specify "should pass a hash to #with (1)" do get :index, "id" => "1", "param2" => "bar" end specify "should pass a hash to #with (2)" do get :index, { "id" => "1", "param2" => "bar" } end specify "should pass a hash to #with (3)" do @plist = { "id" => "1", "param2" => "bar" } get :index, @plist.dup end end Cheers, David> > > > > rgds from "Confused of Hampshire". > > > > > > > > > > _______________________________________________ > > rspec-users mailing list > > rspec-users at rubyforge.org > > http://rubyforge.org/mailman/listinfo/rspec-users > > >
On 2/20/07, David Chelimsky <dchelimsky at gmail.com> wrote:> On 2/20/07, David Chelimsky <dchelimsky at gmail.com> wrote: > > On 2/20/07, Jerry West <jerry.west at ntlworld.com> wrote: > > > > > > > > > > > > So, I still say my app code and my reduction look conceptually the > > > same, but I''m stumped as to why they don''t behave the same way > > > > > > David seems to have picked that up. Ignore my blatherings about > > > HashArgConstraint (though the rest is valid). > > > > > > Here''s another twist under Rails 1.2.2 (which may not be supported but > > > works fine for what I am doing so far). > > > > > > Basically, a different expectation seems to be set up depending on whether > > > the argument to get/post is a variable or not. That cannot be right. What > > > am I missing? > > > > > > require File.dirname(__FILE__) + ''/../spec_helper'' > > > > > > class TestController < ActionController::Base > > > def index() self.amethod(params) end > > > end > > > > > > context ''a test controller'' do > > > controller_name :test > > > > > > setup do > > > @plist = { "id" => "1", "param2" => "bar" } > > > > > > controller.should_receive(:amethod).with(@plist).and_return(true) > > > end > > > > > > specify "should pass a hash to #with (1)" do > > > get :index, "id" => "1", "param2" => "bar" > > > end > > > specify "should pass a hash to #with (2)" do > > > get :index, { "id" => "1", "param2" => "bar" } > > > end > > > specify "should pass a hash to #with (3)" do > > > get :index, @plist > > > end > > > end > > > > > > $ spec -cfs spec/controllers/test_controller_spec.rb > > > /usr/bin/spec:17:Warning: require_gem is obsolete. Use gem instead. > > > /home/jjw/rails/playground/config/boot.rb:29:Warning: > > > require_gem is obsolete. Use gem instead. > > > > > > a test controller > > > - should pass a hash to #with (1) (FAILED - 1) > > > - should pass a hash to #with (2) (FAILED - 2) > > > - should pass a hash to #with (3) (FAILED - 3) > > > > > > 1) > > > ''a test controller should pass a hash to #with (1)'' FAILED (ignore the > > > failure, look at the expectation) > > > #<TestController:0xb70a1df8> expected :amethod with (["param2", "bar"], > > > ["id", "1"]) but received it with ({"action"=>"index", "id"=>"1", > > > "param2"=>"bar", "controller"=>"test"}) > > > (eval):3:in `amethod'' > > > ./spec/controllers/test_controller_spec.rb:4:in `index'' > > > /usr/local/lib/site_ruby/1.8/benchmark.rb:300:in `measure'' > > > ./spec/controllers/test_controller_spec.rb:13: > > > > > > 2) > > > ''a test controller should pass a hash to #with (2)'' FAILED (ignore the > > > failure, look at the expectation) > > > #<TestController:0xb7093820> expected :amethod with (["param2", "bar"], > > > ["id", "1"]) but received it with ({"action"=>"index", "id"=>"1", > > > "param2"=>"bar", "controller"=>"test"}) > > > (eval):3:in `amethod'' > > > ./spec/controllers/test_controller_spec.rb:4:in `index'' > > > /usr/local/lib/site_ruby/1.8/benchmark.rb:300:in `measure'' > > > ./spec/controllers/test_controller_spec.rb:18: > > > > > > 3) > > > ''a test controller should pass a hash to #with (3)'' FAILED (ignore the > > > failure, look at the expectation) > > > #<TestController:0xb708cf34> expected :amethod with ([:only_path, true], > > > ["param2", "bar"], ["id", "1"], [:action, :index]) but received it with > > > ({"action"=>"index", "id"=>"1", "param2"=>"bar", "controller"=>"test"}) > > > (eval):3:in `amethod'' > > > ./spec/controllers/test_controller_spec.rb:4:in `index'' > > > /usr/local/lib/site_ruby/1.8/benchmark.rb:300:in `measure'' > > > ./spec/controllers/test_controller_spec.rb:23: > > > > > > Finished in 0.022612 seconds > > > > > > 3 specifications, 3 failures > > > > > > > > > Where the heck did the :only_path stuff come from in the expectation for > > > case 3?? They weren''t there in ArgumentExpectation#initialize. > > > > > > As expected, creating the ''right'' expectation (@plist = { "id" => > > > "1","param2" => "bar", "action" => "index", "controller" => "test" } ) > > > allows the spec to pass in cases 1 & 2, but #3 still fails. > > > > Here''s the same output w/ the latest trunk. Note that it shows #with > > correctly receiving a Hash now. > > > > 1) > > Spec::Mocks::MockExpectationError in ''a test controller should pass a > > hash to #with (1)'' > > #<TestController:0x2578854> expected :amethod with ({"param2"=>"bar", > > "id"=>"1"}) but received it with ({"action"=>"index", "id"=>"1", > > "param2"=>"bar", "controller"=>"test"}) > > ./spec/controllers/temp_spec.rb:4:in `index'' > > ./spec/controllers/temp_spec.rb:16: > > > > 2) > > Spec::Mocks::MockExpectationError in ''a test controller should pass a > > hash to #with (2)'' > > #<TestController:0x2516ec4> expected :amethod with ({"param2"=>"bar", > > "id"=>"1"}) but received it with ({"action"=>"index", "id"=>"1", > > "param2"=>"bar", "controller"=>"test"}) > > ./spec/controllers/temp_spec.rb:4:in `index'' > > ./spec/controllers/temp_spec.rb:19: > > > > 3) > > Spec::Mocks::MockExpectationError in ''a test controller should pass a > > hash to #with (3)'' > > #<TestController:0x2461d58> expected :amethod with ({:only_path=>true, > > "param2"=>"bar", "id"=>"1", :action=>:index}) but received it with > > ({"action"=>"index", "id"=>"1", "param2"=>"bar", > > "controller"=>"test"}) > > ./spec/controllers/temp_spec.rb:4:in `index'' > > ./spec/controllers/temp_spec.rb:22: > > > > I have NO idea yet about :only_path. I''ll keep you posted... > > OK, I now have SOME idea, but I''m still trying to figure out > specifics. The following passes. Note that it uses @plist.dup each > time. > > require File.dirname(__FILE__) + ''/../spec_helper'' > > class TestController < ActionController::Base > def index() self.amethod(params) end > end > > context ''a test controller'' do > controller_name :test > > setup do > @plist = { "id" => "1", "param2" => "bar" , "controller" => > "test", "action" => "index" } > controller.should_receive(:amethod).with(@plist.dup).and_return(true) > end > > specify "should pass a hash to #with (1)" do > get :index, "id" => "1", "param2" => "bar" > end > > specify "should pass a hash to #with (2)" do > get :index, { "id" => "1", "param2" => "bar" } > end > > specify "should pass a hash to #with (3)" do > get :index, @plist.dup > end > end > > If you search through Rails you''ll find dozens of instances of > :only_path. So the problem SEEMS to be that by the time we reach the > third spec, @plist has been touched by Rails. > > BTW - here''s a variation that passes and allows you to deal only w/ > the subset of keys you want. > > context ''a test controller'' do > controller_name :test > > setup do > controller.should_receive(:amethod).and_return(true) { |params| > params["id"].should == "1" > params["param2"].should == "bar" > } > end > > specify "should pass a hash to #with (1)" do > get :index, "id" => "1", "param2" => "bar" > end > > specify "should pass a hash to #with (2)" do > get :index, { "id" => "1", "param2" => "bar" } > end > > specify "should pass a hash to #with (3)" do > @plist = { "id" => "1", "param2" => "bar" } > get :index, @plist.dup > end > endOK - I figured it out. Because the third spec is passing the actual Hash instance to "get :index", Rails gets a direct reference to it and can do what it wants. If you''re interested in details in this case, take a look at test_process.rb:430/431. So the lesson here is don''t use expectation objects as parameters to your system as the system may produce unwanted side effects. Cheers, David> > Cheers, > David > > > > > > > > > rgds from "Confused of Hampshire". > > > > > > > > > > > > > > > _______________________________________________ > > > rspec-users mailing list > > > rspec-users at rubyforge.org > > > http://rubyforge.org/mailman/listinfo/rspec-users > > > > > >
On 2/20/07, David Chelimsky <dchelimsky at gmail.com> wrote:> > Here''s the same output w/ the latest trunk. Note that it shows #with > correctly receiving a Hash now.David, thanks. I updated to latest trunk and can now pass the same params hash to both #with and #post and get the expected results. Note that I didn''t have to deal with the :only_path stuff as I was looking at params[:user] and not just params.> > 1) > Spec::Mocks::MockExpectationError in ''a test controller should pass a > hash to #with (1)'' > #<TestController:0x2578854> expected :amethod with ({"param2"=>"bar", > "id"=>"1"}) but received it with ({"action"=>"index", "id"=>"1", > "param2"=>"bar", "controller"=>"test"}) > ./spec/controllers/temp_spec.rb:4:in `index'' > ./spec/controllers/temp_spec.rb:16: > > 2) > Spec::Mocks::MockExpectationError in ''a test controller should pass a > hash to #with (2)'' > #<TestController:0x2516ec4> expected :amethod with ({"param2"=>"bar", > "id"=>"1"}) but received it with ({"action"=>"index", "id"=>"1", > "param2"=>"bar", "controller"=>"test"}) > ./spec/controllers/temp_spec.rb:4:in `index'' > ./spec/controllers/temp_spec.rb:19: > > 3) > Spec::Mocks::MockExpectationError in ''a test controller should pass a > hash to #with (3)'' > #<TestController:0x2461d58> expected :amethod with ({:only_path=>true, > "param2"=>"bar", "id"=>"1", :action=>:index}) but received it with > ({"action"=>"index", "id"=>"1", "param2"=>"bar", > "controller"=>"test"}) > ./spec/controllers/temp_spec.rb:4:in `index'' > ./spec/controllers/temp_spec.rb:22: > > I have NO idea yet about :only_path. I''ll keep you posted... > > > > > rgds from "Confused of Hampshire". > > > > > > > > > > _______________________________________________ > > 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 >
On 2/20/07, David Chelimsky <dchelimsky at gmail.com> wrote:> Here''s the same output w/ the latest trunk. Note that it shows #with > correctly receiving a Hash now.Ok, just one more comment here and then I''ll shut up. David, I just now noticed your comment on the RFE: "I''ve fixed the message so it will show you the two hashes (expected and actual), but I think that getting RSpec to make decisions about stringifying keys would be a mistake. To that end, I think the right thing is for you to change your spec to expect a Hash with stringy keys." You''re right, changing the hash to have string keys was not a burden but doing this had zero effect on whether the spec passed or not; my point all along (and sorry if this was never made clear enough) was that it did seem like a burden to convert my hash to an array of 2-element arrays in order for the spec to pass. Not to mention, this would break any code under test that was expecting to deal with a hash (as in the #delete example that I mentioned in a separate mail). Anyways, thanks again for looking into this. As an aside, I''m really enjoying using rspec! James> > 1) > Spec::Mocks::MockExpectationError in ''a test controller should pass a > hash to #with (1)'' > #<TestController:0x2578854> expected :amethod with ({"param2"=>"bar", > "id"=>"1"}) but received it with ({"action"=>"index", "id"=>"1", > "param2"=>"bar", "controller"=>"test"}) > ./spec/controllers/temp_spec.rb:4:in `index'' > ./spec/controllers/temp_spec.rb:16: > > 2) > Spec::Mocks::MockExpectationError in ''a test controller should pass a > hash to #with (2)'' > #<TestController:0x2516ec4> expected :amethod with ({"param2"=>"bar", > "id"=>"1"}) but received it with ({"action"=>"index", "id"=>"1", > "param2"=>"bar", "controller"=>"test"}) > ./spec/controllers/temp_spec.rb:4:in `index'' > ./spec/controllers/temp_spec.rb:19: > > 3) > Spec::Mocks::MockExpectationError in ''a test controller should pass a > hash to #with (3)'' > #<TestController:0x2461d58> expected :amethod with ({:only_path=>true, > "param2"=>"bar", "id"=>"1", :action=>:index}) but received it with > ({"action"=>"index", "id"=>"1", "param2"=>"bar", > "controller"=>"test"}) > ./spec/controllers/temp_spec.rb:4:in `index'' > ./spec/controllers/temp_spec.rb:22: > > I have NO idea yet about :only_path. I''ll keep you posted... > > > > > rgds from "Confused of Hampshire". > > > > > > > > > > _______________________________________________ > > 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 >
On 2/20/07, James Hughes <hughes.james at gmail.com> wrote:> On 2/20/07, David Chelimsky <dchelimsky at gmail.com> wrote: > > Here''s the same output w/ the latest trunk. Note that it shows #with > > correctly receiving a Hash now. > > Ok, just one more comment here and then I''ll shut up. David, I just > now noticed your comment on the RFE: > > "I''ve fixed the message so it will show you the two hashes (expected > and actual), but I think that getting RSpec to make decisions about > stringifying keys would be a mistake. To that end, I think the right > thing is for you to change your spec to expect a Hash with stringy > keys." > > You''re right, changing the hash to have string keys was not a burden > but doing this had zero effect on whether the spec passed or not; my > point all along (and sorry if this was never made clear enough) was > that it did seem like a burden to convert my hash to an array of > 2-element arrays in order for the spec to pass. Not to mention, this > would break any code under test that was expecting to deal with a hash > (as in the #delete example that I mentioned in a separate mail).OK - now I''m confused. As I understand it, the problem was that the failure message was incorrectly displaying a Hash as an Array of 2-element Arrays. This was ONLY in the message, which was only invoked after the Hash''s had been correctly compared. There was never an Array of Array''s being compared. With that understanding, I don''t see how the spec could have passed simply by saying #with([[][]]). Please help me understand.> > Anyways, thanks again for looking into this. As an aside, I''m really > enjoying using rspec!Glad to hear it. And thanks for the feedback in general. Cheers, David> > James > > > > > > 1) > > Spec::Mocks::MockExpectationError in ''a test controller should pass a > > hash to #with (1)'' > > #<TestController:0x2578854> expected :amethod with ({"param2"=>"bar", > > "id"=>"1"}) but received it with ({"action"=>"index", "id"=>"1", > > "param2"=>"bar", "controller"=>"test"}) > > ./spec/controllers/temp_spec.rb:4:in `index'' > > ./spec/controllers/temp_spec.rb:16: > > > > 2) > > Spec::Mocks::MockExpectationError in ''a test controller should pass a > > hash to #with (2)'' > > #<TestController:0x2516ec4> expected :amethod with ({"param2"=>"bar", > > "id"=>"1"}) but received it with ({"action"=>"index", "id"=>"1", > > "param2"=>"bar", "controller"=>"test"}) > > ./spec/controllers/temp_spec.rb:4:in `index'' > > ./spec/controllers/temp_spec.rb:19: > > > > 3) > > Spec::Mocks::MockExpectationError in ''a test controller should pass a > > hash to #with (3)'' > > #<TestController:0x2461d58> expected :amethod with ({:only_path=>true, > > "param2"=>"bar", "id"=>"1", :action=>:index}) but received it with > > ({"action"=>"index", "id"=>"1", "param2"=>"bar", > > "controller"=>"test"}) > > ./spec/controllers/temp_spec.rb:4:in `index'' > > ./spec/controllers/temp_spec.rb:22: > > > > I have NO idea yet about :only_path. I''ll keep you posted... > > > > > > > > rgds from "Confused of Hampshire". > > > > > > > > > > > > > > > _______________________________________________ > > > 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 > > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
On 2/20/07, David Chelimsky <dchelimsky at gmail.com> wrote:> On 2/20/07, James Hughes <hughes.james at gmail.com> wrote: > > On 2/20/07, David Chelimsky <dchelimsky at gmail.com> wrote: > > > Here''s the same output w/ the latest trunk. Note that it shows #with > > > correctly receiving a Hash now. > > > > Ok, just one more comment here and then I''ll shut up. David, I just > > now noticed your comment on the RFE: > > > > "I''ve fixed the message so it will show you the two hashes (expected > > and actual), but I think that getting RSpec to make decisions about > > stringifying keys would be a mistake. To that end, I think the right > > thing is for you to change your spec to expect a Hash with stringy > > keys." > > > > You''re right, changing the hash to have string keys was not a burden > > but doing this had zero effect on whether the spec passed or not; my > > point all along (and sorry if this was never made clear enough) was > > that it did seem like a burden to convert my hash to an array of > > 2-element arrays in order for the spec to pass. Not to mention, this > > would break any code under test that was expecting to deal with a hash > > (as in the #delete example that I mentioned in a separate mail). > > OK - now I''m confused.It would appear that I am the one who is confused. I had a distinct memory of my spec still failing after I had changed the keys to strings, but I just reverted to r1514 to double check that, and indeed, it passed with string keys, and failed with symbol keys. I got so caught up in chasing down all the possible combinations of how to do this that I somehow convinced myself that the keys issue was a red herring. My apologies. At least you fixed the message bug ;) James