<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type"> <title></title> </head> <body bgcolor="#ffffff" text="#000000"> Q. Why does code which defines a context work in the <tt>controller_spec</tt> file and not in a ''require''d helper file?<br> <br> A. Because spec uses the filename to tell it what type of context (:controller, :model) it is creating.<br> <br> Fix: use the (undocumented?) second parameter to <tt>#context(), </tt><b><tt>:context_type => :controller.<br> <br> </tt></b>Quite how this works, I do not know; the rdocs don''t mention it and according to the source context doesn''t take a second argument (except a block). My Ruby-fu isn''t up to explaining it; if anyone else would like to do so that would be nice.<b><br> </b><br> Hope this helps someone else save a half hour or so.<br> <br> Rgds,<br> Jerry<br> <br> Further details:<br> <br> If I define a method which dynamically constructs a context in my controller_spec.rb file it works fine:<br> <br> <tt>def restful_edit_specs(resource)<br> context "GET /#{resource}/:id;edit (:edit)" do <br> controller_name resource<br> <br> resource = resource.to_s<br> sym = resource.singularize<br> klass = resource.classify<br> <br> setup do<br> @mock = mock_model sym # based on <a class="moz-txt-link-freetext" href="http://metaclass.org/2006/12/22/making-a-mockery-of-activerecord">http://metaclass.org/2006/12/22/making-a-mockery-of-activerecord</a><br> @model = Object.const_get(klass)<br> @model.should_receive(:find).with(@mock.id).and_return(@mock)<br> end<br> <br> def do_get() get :edit, :id => @mock.id end<br> <br> specify "should be successful" do<br> do_get<br> response.should_be_success<br> end<br> specify "should render edit.rhtml" do<br> do_get<br> controller.should_render :edit<br> end<br> specify "should find the #{klass} requested" do<br> @model.should_receive(:find).and_return(@mock)<br> do_get<br> end<br> specify "should assign the found #{klass} for the view" do<br> do_get<br> assigns(sym).should_equal @mock<br> end<br> end<br> end<br> <br> restful_edit_specs(:assessments)<br> <br> </tt>This all works fine when defined in the xx_controller_spec.rb file.<br> <br> But if I move the exact same code to a helper file and require it, spec gets confused:<br> <br> <tt>.../rspec-0.7.5.1/lib/spec/expectations/sugar.rb:13:in `call'': undefined method `controller_name'' for #<Spec::Runner::ContextEvalModule:0xb70496a8> (NoMethodError)<br> ... etc etc...<br> </tt><br> Clearly, there''s some magic involved which means the context does not know what it''s about (it was at this point in typing my original plea for help that I remembered seeing the :context_type parameter in the specs for the rspec_on_rails plugin itself).<br> <br> Changing the context line to<br> <br> <tt> </tt><b><tt>context "GET /#{resource}/:id;edit (:edit)", </tt><tt>:context_type => :controller do<br> <br> </tt></b>allows the specs to function as ex-spec-ted.<b><tt><br> </tt></b> </body> </html>
On 2/15/07, Jerry West <jerry.west at ntlworld.com> wrote:> > Q. Why does code which defines a context work in the controller_spec file > and not in a ''require''d helper file? > > A. Because spec uses the filename to tell it what type of context > (:controller, :model) it is creating. > > Fix: use the (undocumented?) second parameter to #context(), :context_type > => :controller. > > Quite how this works, I do not know; the rdocs don''t mention it and > according to the source context doesn''t take a second argument (except a > block). My Ruby-fu isn''t up to explaining it; if anyone else would like to > do so that would be nice. > > Hope this helps someone else save a half hour or so. > > Rgds, > Jerry > > Further details: > > If I define a method which dynamically constructs a context in my > controller_spec.rb file it works fine: > > def restful_edit_specs(resource) > context "GET /#{resource}/:id;edit (:edit)" do > controller_name resource > > resource = resource.to_s > sym = resource.singularize > klass = resource.classify > > setup do > @mock = mock_model sym # based on > http://metaclass.org/2006/12/22/making-a-mockery-of-activerecord > @model = Object.const_get(klass) > @model.should_receive(:find).with(@mock.id).and_return(@mock) > end > > def do_get() get :edit, :id => @mock.id end > > specify "should be successful" do > do_get > response.should_be_success > end > specify "should render edit.rhtml" do > do_get > controller.should_render :edit > end > specify "should find the #{klass} requested" do > @model.should_receive(:find).and_return(@mock) > do_get > end > specify "should assign the found #{klass} for the view" do > do_get > assigns(sym).should_equal @mock > end > end > end > > restful_edit_specs(:assessments) > > This all works fine when defined in the xx_controller_spec.rb file. > > But if I move the exact same code to a helper file and require it, spec > gets confused: > > .../rspec-0.7.5.1/lib/spec/expectations/sugar.rb:13:in > `call'': undefined method `controller_name'' for > #<Spec::Runner::ContextEvalModule:0xb70496a8> > (NoMethodError) > ... etc etc... > > Clearly, there''s some magic involved which means the context does not know > what it''s about (it was at this point in typing my original plea for help > that I remembered seeing the :context_type parameter in the specs for the > rspec_on_rails plugin itself). > > Changing the context line to > > context "GET /#{resource}/:id;edit (:edit)", :context_type => > :controller do > > allows the specs to function as ex-spec-ted.This is one of those "convention over configuration" things. Spec::Rails goes out of its way to provide different contexts for different types of specs, each providing specific facilities that are relevant to that kind of spec (model/view/controller/helper). Put your specs in the right directories and you get the right kind of context. The undocumented-second-parameter was added, as you note, to support our own specs of the plugin. The likelihood is that it will remain, but it is undocumented and subject to change without notice, so you do absorb some risk in using it. What is the value you are looking for by bypassing the convention here? I''m asking because perhaps there is a missing feature we can tease out of this. Cheers, David> > _______________________________________________ > 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"> <title></title> </head> <body bgcolor="#ffffff" text="#000000"> <blockquote type="cite"> <pre wrap="">What is the value you are looking for by bypassing the convention here? I''m asking because perhaps there is a missing feature we can tease out of this. </pre> </blockquote> I was trying to refactor out some shared (restful controller) specs, more as an experiment than anything else. <br> <br> I really do like to be DRY so any essentially identical code (e.g. that generated by rspec_resource) is a candidate to be refactored into a parameter-ised function. Actions like edit and destroy seem hardly to differ between controllers. However, actions like new will tend to set defaults and create usually does some sanity checking, so I''m not sure how successful this refactoring would be in the long run.<br> <br> Refactored code would be in a helper file of course. I put the helper file into my standard ''extensions'' library plugin which is easy to share between rails apps. It appears that spec uses the full directory path to identify the context - so even re-naming the helper file as ''<tt>lib/helper_controller_spec.rb''</tt> is not enough. If I put that same file in the <tt>spec/controllers</tt> directory then the :<tt>context</tt> argument is not necessary. I could live with that if it ever disappeared.<br> <br> Bottom line: No big deal; if it goes it goes, if it stays it''s very occasionally helpful. My vote would be keep it unless it becomes awkward to maintain - extra flexibility can be very useful and if there''s no opportunity cost there''s no reason to bin it.<br> <br> Best wishes,<br> Jerry<br> <br> <br> David Chelimsky wrote: <blockquote cite="mid57c63afe0702151054n2edd3d03j51b2eeb6a1b7bb0d@mail.gmail.com" type="cite"> <pre wrap="">On 2/15/07, Jerry West <a class="moz-txt-link-rfc2396E" href="mailto:jerry.west@ntlworld.com"><jerry.west@ntlworld.com></a> wrote: </pre> <blockquote type="cite"> <pre wrap=""> Q. Why does code which defines a context work in the controller_spec file and not in a ''require''d helper file? A. Because spec uses the filename to tell it what type of context (:controller, :model) it is creating. Fix: use the (undocumented?) second parameter to #context(), :context_type => :controller. Quite how this works, I do not know; the rdocs don''t mention it and according to the source context doesn''t take a second argument (except a block). My Ruby-fu isn''t up to explaining it; if anyone else would like to do so that would be nice. Hope this helps someone else save a half hour or so. Rgds, Jerry Further details: If I define a method which dynamically constructs a context in my controller_spec.rb file it works fine: def restful_edit_specs(resource) context "GET /#{resource}/:id;edit (:edit)" do controller_name resource resource = resource.to_s sym = resource.singularize klass = resource.classify setup do @mock = mock_model sym # based on <a class="moz-txt-link-freetext" href="http://metaclass.org/2006/12/22/making-a-mockery-of-activerecord">http://metaclass.org/2006/12/22/making-a-mockery-of-activerecord</a> @model = Object.const_get(klass) @model.should_receive(:find).with(@mock.id).and_return(@mock) end def do_get() get :edit, :id => @mock.id end specify "should be successful" do do_get response.should_be_success end specify "should render edit.rhtml" do do_get controller.should_render :edit end specify "should find the #{klass} requested" do @model.should_receive(:find).and_return(@mock) do_get end specify "should assign the found #{klass} for the view" do do_get assigns(sym).should_equal @mock end end end restful_edit_specs(:assessments) This all works fine when defined in the xx_controller_spec.rb file. But if I move the exact same code to a helper file and require it, spec gets confused: .../rspec-0.7.5.1/lib/spec/expectations/sugar.rb:13:in `call'': undefined method `controller_name'' for #<Spec::Runner::ContextEvalModule:0xb70496a8> (NoMethodError) ... etc etc... Clearly, there''s some magic involved which means the context does not know what it''s about (it was at this point in typing my original plea for help that I remembered seeing the :context_type parameter in the specs for the rspec_on_rails plugin itself). Changing the context line to context "GET /#{resource}/:id;edit (:edit)", :context_type => :controller do allows the specs to function as ex-spec-ted. </pre> </blockquote> <pre wrap=""><!----> This is one of those "convention over configuration" things. Spec::Rails goes out of its way to provide different contexts for different types of specs, each providing specific facilities that are relevant to that kind of spec (model/view/controller/helper). Put your specs in the right directories and you get the right kind of context. The undocumented-second-parameter was added, as you note, to support our own specs of the plugin. The likelihood is that it will remain, but it is undocumented and subject to change without notice, so you do absorb some risk in using it. What is the value you are looking for by bypassing the convention here? I''m asking because perhaps there is a missing feature we can tease out of this. Cheers, David </pre> <blockquote type="cite"> <pre wrap="">_______________________________________________ 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> <pre wrap=""><!---->_______________________________________________ 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/16/07, Jerry West <jerry.west at ntlworld.com> wrote:> > What is the value you are looking for by bypassing the convention > here? I''m asking because perhaps there is a missing feature we can > tease out of this. > > I was trying to refactor out some shared (restful controller) specs, more > as an experiment than anything else. > > I really do like to be DRY so any essentially identical code (e.g. that > generated by rspec_resource) is a candidate to be refactored into a > parameter-ised function. Actions like edit and destroy seem hardly to > differ between controllers. However, actions like new will tend to set > defaults and create usually does some sanity checking, so I''m not sure how > successful this refactoring would be in the long run.Luke Redpath has some thoughts on this as well: http://www.lukeredpath.co.uk/2007/2/2/refactoring-rest-searching-for-an-abstraction Please do keep us posted on your own experimentation. As Spec::Rails becomes less volatile, I''d like to see plugins emerge that work in conjunction with it (as opposed to beefing up Spec::Rails itself). Perhaps you could be among the first to contribute such to the community.> Refactored code would be in a helper file of course. I put the helper > file into my standard ''extensions'' library plugin which is easy to share > between rails apps. It appears that spec uses the full directory path to > identify the context - so even re-naming the helper file as > ''lib/helper_controller_spec.rb'' is not enough. If I put that same file in > the spec/controllers directory then the :context argument is not necessary. > I could live with that if it ever disappeared.As it turns out, I see that I actually DID document it in the Spec::Rails::Runner::ContextFactory (in trunk), so I had already considered making it official (sorry for not remembering that - there is a lot going on right now and that aspect was low on my radar). So I guess you can go ahead and count on it. Cheers, David> > Bottom line: No big deal; if it goes it goes, if it stays it''s very > occasionally helpful. My vote would be keep it unless it becomes awkward to > maintain - extra flexibility can be very useful and if there''s no > opportunity cost there''s no reason to bin it. > > Best wishes, > Jerry > > > > David Chelimsky wrote: > On 2/15/07, Jerry West <jerry.west at ntlworld.com> wrote: > > > Q. Why does code which defines a context work in the controller_spec file > and not in a ''require''d helper file? > > A. Because spec uses the filename to tell it what type of context > (:controller, :model) it is creating. > > Fix: use the (undocumented?) second parameter to #context(), :context_type > => :controller. > > Quite how this works, I do not know; the rdocs don''t mention it and > according to the source context doesn''t take a second argument (except a > block). My Ruby-fu isn''t up to explaining it; if anyone else would like to > do so that would be nice. > > Hope this helps someone else save a half hour or so. > > Rgds, > Jerry > > Further details: > > If I define a method which dynamically constructs a context in my > controller_spec.rb file it works fine: > > def restful_edit_specs(resource) > context "GET /#{resource}/:id;edit (:edit)" do > controller_name resource > > resource = resource.to_s > sym = resource.singularize > klass = resource.classify > > setup do > @mock = mock_model sym # based on > http://metaclass.org/2006/12/22/making-a-mockery-of-activerecord > @model = Object.const_get(klass) > @model.should_receive(:find).with(@mock.id).and_return(@mock) > end > > def do_get() get :edit, :id => @mock.id end > > specify "should be successful" do > do_get > response.should_be_success > end > specify "should render edit.rhtml" do > do_get > controller.should_render :edit > end > specify "should find the #{klass} requested" do > @model.should_receive(:find).and_return(@mock) > do_get > end > specify "should assign the found #{klass} for the view" do > do_get > assigns(sym).should_equal @mock > end > end > end > > restful_edit_specs(:assessments) > > This all works fine when defined in the xx_controller_spec.rb file. > > But if I move the exact same code to a helper file and require it, spec > gets confused: > > .../rspec-0.7.5.1/lib/spec/expectations/sugar.rb:13:in > `call'': undefined method `controller_name'' for > #<Spec::Runner::ContextEvalModule:0xb70496a8> > (NoMethodError) > ... etc etc... > > Clearly, there''s some magic involved which means the context does not know > what it''s about (it was at this point in typing my original plea for help > that I remembered seeing the :context_type parameter in the specs for the > rspec_on_rails plugin itself). > > Changing the context line to > > context "GET /#{resource}/:id;edit (:edit)", :context_type => > :controller do > > allows the specs to function as ex-spec-ted. > > This is one of those "convention over configuration" things. > Spec::Rails goes out of its way to provide different contexts for > different types of specs, each providing specific facilities that are > relevant to that kind of spec (model/view/controller/helper). Put your > specs in the right directories and you get the right kind of context. > > The undocumented-second-parameter was added, as you note, to support > our own specs of the plugin. The likelihood is that it will remain, > but it is undocumented and subject to change without notice, so you do > absorb some risk in using it. > > What is the value you are looking for by bypassing the convention > here? I''m asking because perhaps there is a missing feature we can > tease out of this. > > Cheers, > David > > > > _______________________________________________ > 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/15/07, David Chelimsky <dchelimsky at gmail.com> wrote:> What is the value you are looking for by bypassing the convention > here? I''m asking because perhaps there is a missing feature we can > tease out of this.David, I make use of the :context_type feature to allow me to maintain separate model unit specs and integration specs. What we term "integration specs" are specs that test a cluster of models (often with a fair amount of necessary DB access), not customer-level acceptance tests (as in the Rails terminology). We found that in order to make those specs run correctly in database transactions, we had to add :context_type => :model to their context declaration. Anyway, looks like :context_type is on it''s way to being fully documented, but I figured I''d let you know why we find it useful in case it might uncover a missing feature. -Bryan