hi, i want to make a behavior shared between models, the examples need to create new instances etc. Is there a way to pass the model class to the shared behavior? -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/rspec-users/attachments/20071218/5b400cc5/attachment-0001.html
On Dec 18, 2007 11:39 AM, Jonathan Linowes <JONATHAN at linowes.com> wrote:> > hi, i want to make a behavior shared between models, the examples need to > create new instances etc. Is there a way to pass the model class to the > shared behavior?We''re calling these shared example groups now. The way to affect the state within a shared example group is to use before(:each) to set an instance variable: shared_examples_for "models that do stuff" do before(:each) do @instance = @class.new end it "should do something" do @instance.should do_something end end describe Foo do before(:each) do @class = Foo end it_should_behave_like "models that do stuff" end Cheers, David> > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
On Dec 18, 2007, at 12:39 PM, Jonathan Linowes wrote:> hi, i want to make a behavior shared between models, the examples > need to create new instances etc. Is there a way to pass the model > class to the shared behavior?Nope. The only way to do it right now is with an instance variable. The shared behaviours can be thought of modules which are included into the current behaviour - so it should also have access to any methods defined in the example (group) in which it is shared. Scott -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/rspec-users/attachments/20071218/55e1b41b/attachment.html
On Dec 18, 2007 3:37 PM, Scott Taylor <mailing_lists at railsnewbie.com> wrote:> The > shared behaviours can be thought of modules which are included into the > current behaviour - so it should also have access to any methods defined in > the example (group) in which it is shared.You don''t even have to think of it that way - that''s actually what they are - modules that get included. You can actually assign them to a constant and just use Ruby include.
On Dec 18, 2007, at 4:42 PM, David Chelimsky wrote:> On Dec 18, 2007 3:37 PM, Scott Taylor > <mailing_lists at railsnewbie.com> wrote: >> The >> shared behaviours can be thought of modules which are included >> into the >> current behaviour - so it should also have access to any methods >> defined in >> the example (group) in which it is shared. > > You don''t even have to think of it that way - that''s actually what > they are - modules that get included. You can actually assign them to > a constant and just use Ruby include.Although we''ve talked about the implementation changing, which would cause those who use them as modules to have broken specs. Scott
On Dec 18, 2007 3:53 PM, Scott Taylor <mailing_lists at railsnewbie.com> wrote:> > > On Dec 18, 2007, at 4:42 PM, David Chelimsky wrote: > > > On Dec 18, 2007 3:37 PM, Scott Taylor > > <mailing_lists at railsnewbie.com> wrote: > >> The > >> shared behaviours can be thought of modules which are included > >> into the > >> current behaviour - so it should also have access to any methods > >> defined in > >> the example (group) in which it is shared. > > > > You don''t even have to think of it that way - that''s actually what > > they are - modules that get included. You can actually assign them to > > a constant and just use Ruby include. > > Although we''ve talked about the implementation changing, which would > cause those who use them as modules to have broken specs.It would, but we stopped talking about it :) It actually works quite well this way. The change came up, iirc, in the conversation about parameterizing it_should_behave_like, right? I''ve got a solution for that worked out, but I haven''t applied it yet because I want to discuss it a bit: You''d use it like this: shared_examples_for "anything" do it "should do stuff" do @thing.should do_stuff end end describe SpecificThing do it_should_behave_like "anything", :thing => SpecificThing.new end Now comes the tricky part. This can work one of two ways. In either case it turns :thing into an instance variable @thing. The question is whether that instance variable is assigned in the scope of the SpecificThing example group or in a scope created especially to run the shared examples. Each choice presents usability confusion in my view. Imagine this scenario: shared_examples_for "anything" do it "should do stuff" do @thing.should do_stuff end it "should be like another thing" do @thing.should be_like(@other_thing) end end describe SpecificThing do before(:each) do @thing = SpecificThing.new end it_should_behave_like "anything", :other_thing => SpecificThing.new it "should not be unlike other thing" do @thing.should_not be_unlike(@other_thing) end end If @other_thing is defined in the context of a separate scope just to run the shared examples, the shared examples won''t know about @thing. If @other_thing in the scope of the example group created by "describe SpecificThing," then it''s just confusing to look at - both before(:each) and it_should_behave_like are creating instance variables in the current scope, and it is NOT clear that is what is happening. If we go w/ the separate scope, then the metaphor of it_should_behave_like is wrong, because we''re not talking about something in the current scope that should behave like something else anymore. We''d probably want a different construct to create these, even though the underlying mechanism would be the same. Thoughts? David
On Dec 18, 2007, at 5:12 PM, David Chelimsky wrote:> On Dec 18, 2007 3:53 PM, Scott Taylor > <mailing_lists at railsnewbie.com> wrote: >> >> >> On Dec 18, 2007, at 4:42 PM, David Chelimsky wrote: >> >>> On Dec 18, 2007 3:37 PM, Scott Taylor >>> <mailing_lists at railsnewbie.com> wrote: >>>> The >>>> shared behaviours can be thought of modules which are included >>>> into the >>>> current behaviour - so it should also have access to any methods >>>> defined in >>>> the example (group) in which it is shared. >>> >>> You don''t even have to think of it that way - that''s actually what >>> they are - modules that get included. You can actually assign >>> them to >>> a constant and just use Ruby include. >> >> Although we''ve talked about the implementation changing, which would >> cause those who use them as modules to have broken specs. > > It would, but we stopped talking about it :) > > It actually works quite well this way. The change came up, iirc, in > the conversation about parameterizing it_should_behave_like, right? > I''ve got a solution for that worked out, but I haven''t applied it yet > because I want to discuss it a bit: > > You''d use it like this: > > shared_examples_for "anything" do > it "should do stuff" do > @thing.should do_stuff > end > end > > describe SpecificThing do > it_should_behave_like "anything", :thing => SpecificThing.new > end > > Now comes the tricky part. This can work one of two ways. In either > case it turns :thing into an instance variable @thing. The question is > whether that instance variable is assigned in the scope of the > SpecificThing example group or in a scope created especially to run > the shared examples. Each choice presents usability confusion in my > view. > > Imagine this scenario: > > shared_examples_for "anything" do > it "should do stuff" do > @thing.should do_stuff > end > it "should be like another thing" do > @thing.should be_like(@other_thing) > end > end > > describe SpecificThing do > before(:each) do > @thing = SpecificThing.new > end > it_should_behave_like "anything", :other_thing => SpecificThing.new > > it "should not be unlike other thing" do > @thing.should_not be_unlike(@other_thing) > end > end > > If @other_thing is defined in the context of a separate scope just to > run the shared examples, the shared examples won''t know about @thing. > > If @other_thing in the scope of the example group created by "describe > SpecificThing," then it''s just confusing to look at - both > before(:each) and it_should_behave_like are creating instance > variables in the current scope, and it is NOT clear that is what is > happening. > > If we go w/ the separate scope, then the metaphor of > it_should_behave_like is wrong, because we''re not talking about > something in the current scope that should behave like something else > anymore. We''d probably want a different construct to create these, > even though the underlying mechanism would be the same. > > Thoughts?How about this: Use a separate scope, but copy the instance variables from the calling example group. Any parameters passed into the shared example group will be methods which wrap the values given. This way we don''t have instance variable naming conflicts (like @other_thing, in the example above). On the other hand, this would also mean that shared example groups wouldn''t have the ability to call methods in the calling example group. Thoughts? Scott
On Dec 18, 2007 4:22 PM, Scott Taylor <mailing_lists at railsnewbie.com> wrote:> > > On Dec 18, 2007, at 5:12 PM, David Chelimsky wrote: > > > On Dec 18, 2007 3:53 PM, Scott Taylor > > <mailing_lists at railsnewbie.com> wrote: > >> > >> > >> On Dec 18, 2007, at 4:42 PM, David Chelimsky wrote: > >> > >>> On Dec 18, 2007 3:37 PM, Scott Taylor > >>> <mailing_lists at railsnewbie.com> wrote: > >>>> The > >>>> shared behaviours can be thought of modules which are included > >>>> into the > >>>> current behaviour - so it should also have access to any methods > >>>> defined in > >>>> the example (group) in which it is shared. > >>> > >>> You don''t even have to think of it that way - that''s actually what > >>> they are - modules that get included. You can actually assign > >>> them to > >>> a constant and just use Ruby include. > >> > >> Although we''ve talked about the implementation changing, which would > >> cause those who use them as modules to have broken specs. > > > > It would, but we stopped talking about it :) > > > > It actually works quite well this way. The change came up, iirc, in > > the conversation about parameterizing it_should_behave_like, right? > > I''ve got a solution for that worked out, but I haven''t applied it yet > > because I want to discuss it a bit: > > > > You''d use it like this: > > > > shared_examples_for "anything" do > > it "should do stuff" do > > @thing.should do_stuff > > end > > end > > > > describe SpecificThing do > > it_should_behave_like "anything", :thing => SpecificThing.new > > end > > > > Now comes the tricky part. This can work one of two ways. In either > > case it turns :thing into an instance variable @thing. The question is > > whether that instance variable is assigned in the scope of the > > SpecificThing example group or in a scope created especially to run > > the shared examples. Each choice presents usability confusion in my > > view. > > > > Imagine this scenario: > > > > shared_examples_for "anything" do > > it "should do stuff" do > > @thing.should do_stuff > > end > > it "should be like another thing" do > > @thing.should be_like(@other_thing) > > end > > end > > > > describe SpecificThing do > > before(:each) do > > @thing = SpecificThing.new > > end > > it_should_behave_like "anything", :other_thing => SpecificThing.new > > > > it "should not be unlike other thing" do > > @thing.should_not be_unlike(@other_thing) > > end > > end > > > > If @other_thing is defined in the context of a separate scope just to > > run the shared examples, the shared examples won''t know about @thing. > > > > If @other_thing in the scope of the example group created by "describe > > SpecificThing," then it''s just confusing to look at - both > > before(:each) and it_should_behave_like are creating instance > > variables in the current scope, and it is NOT clear that is what is > > happening. > > > > If we go w/ the separate scope, then the metaphor of > > it_should_behave_like is wrong, because we''re not talking about > > something in the current scope that should behave like something else > > anymore. We''d probably want a different construct to create these, > > even though the underlying mechanism would be the same. > > > > Thoughts? > > > How about this: > > Use a separate scope, but copy the instance variables from the > calling example group. Any parameters passed into the shared example > group will be methods which wrap the values given. This way we > don''t have instance variable naming conflicts (like @other_thing, in > the example above). > > On the other hand, this would also mean that shared example groups > wouldn''t have the ability to call methods in the calling example group. > > Thoughts?Copying instance variables around is nasty business. In fact, we eliminated that from shared behaviours by making them modules that get included! So I would view that as a step backwards from an implementation standpoint, and it still feels like voodoo from a usability standpoint.> > > Scott > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
On 12/18/07, David Chelimsky <dchelimsky at gmail.com> wrote:> On Dec 18, 2007 11:39 AM, Jonathan Linowes <JONATHAN at linowes.com> wrote: > > > > hi, i want to make a behavior shared between models, the examples need to > > create new instances etc. Is there a way to pass the model class to the > > shared behavior? > > We''re calling these shared example groups now. > > The way to affect the state within a shared example group is to use > before(:each) to set an instance variable: > > shared_examples_for "models that do stuff" do > before(:each) do > @instance = @class.new > end > it "should do something" do > @instance.should do_something > end > end > > describe Foo do > before(:each) do > @class = Foo > end > it_should_behave_like "models that do stuff" > endSo I guess this means that the before block for the shared example group gets executed after the example group using it. I don''t recall seeing this documented, although I''m sure that it is. This helps me a lot. Can you do something similar with the new nested example groups? It doesn''t seem so. describe "Shared", :shared => true do before(:each) do @outer = @inner end it "should set @outer to @inner" do @outer.should == @inner end end describe "Sharer" do it_should_behave_like "Shared" it "should set @outer to 1" do @inner = 1 end end describe "Outer" do before(:each) do @outer = @inner end describe "inner one" do before(:each) do @inner = 1 end it "should be set outer to 1" do @outer.should == 1 end end describe "inner two" do before(:each) do @inner = 2 end it "should be set outer to 1" do @outer.should == 2 end end end k$ spec ~/nestedspec.rb FF.. 1) ''inner one should be set outer to 1'' FAILED expected: 1, got: nil (using ==) /Users/rick/nestedspec.rb:16: 2) ''inner two should be set outer to 1'' FAILED expected: 2, got: nil (using ==) /Users/rick/nestedspec.rb:26: Finished in 0.00627 seconds 4 examples, 2 failures -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/
On Dec 18, 2007 4:25 PM, David Chelimsky <dchelimsky at gmail.com> wrote:> > On Dec 18, 2007 4:22 PM, Scott Taylor <mailing_lists at railsnewbie.com> wrote: > > > > > > On Dec 18, 2007, at 5:12 PM, David Chelimsky wrote: > > > > > On Dec 18, 2007 3:53 PM, Scott Taylor > > > <mailing_lists at railsnewbie.com> wrote: > > >> > > >> > > >> On Dec 18, 2007, at 4:42 PM, David Chelimsky wrote: > > >> > > >>> On Dec 18, 2007 3:37 PM, Scott Taylor > > >>> <mailing_lists at railsnewbie.com> wrote: > > >>>> The > > >>>> shared behaviours can be thought of modules which are included > > >>>> into the > > >>>> current behaviour - so it should also have access to any methods > > >>>> defined in > > >>>> the example (group) in which it is shared. > > >>> > > >>> You don''t even have to think of it that way - that''s actually what > > >>> they are - modules that get included. You can actually assign > > >>> them to > > >>> a constant and just use Ruby include. > > >> > > >> Although we''ve talked about the implementation changing, which would > > >> cause those who use them as modules to have broken specs. > > > > > > It would, but we stopped talking about it :) > > > > > > It actually works quite well this way. The change came up, iirc, in > > > the conversation about parameterizing it_should_behave_like, right? > > > I''ve got a solution for that worked out, but I haven''t applied it yet > > > because I want to discuss it a bit: > > > > > > You''d use it like this: > > > > > > shared_examples_for "anything" do > > > it "should do stuff" do > > > @thing.should do_stuff > > > end > > > end > > > > > > describe SpecificThing do > > > it_should_behave_like "anything", :thing => SpecificThing.new > > > end > > > > > > Now comes the tricky part. This can work one of two ways. In either > > > case it turns :thing into an instance variable @thing. The question is > > > whether that instance variable is assigned in the scope of the > > > SpecificThing example group or in a scope created especially to run > > > the shared examples. Each choice presents usability confusion in my > > > view. > > > > > > Imagine this scenario: > > > > > > shared_examples_for "anything" do > > > it "should do stuff" do > > > @thing.should do_stuff > > > end > > > it "should be like another thing" do > > > @thing.should be_like(@other_thing) > > > end > > > end > > > > > > describe SpecificThing do > > > before(:each) do > > > @thing = SpecificThing.new > > > end > > > it_should_behave_like "anything", :other_thing => SpecificThing.new > > > > > > it "should not be unlike other thing" do > > > @thing.should_not be_unlike(@other_thing) > > > end > > > end > > > > > > If @other_thing is defined in the context of a separate scope just to > > > run the shared examples, the shared examples won''t know about @thing. > > > > > > If @other_thing in the scope of the example group created by "describe > > > SpecificThing," then it''s just confusing to look at - both > > > before(:each) and it_should_behave_like are creating instance > > > variables in the current scope, and it is NOT clear that is what is > > > happening. > > > > > > If we go w/ the separate scope, then the metaphor of > > > it_should_behave_like is wrong, because we''re not talking about > > > something in the current scope that should behave like something else > > > anymore. We''d probably want a different construct to create these, > > > even though the underlying mechanism would be the same. > > > > > > Thoughts? > > > > > > How about this: > > > > Use a separate scope, but copy the instance variables from the > > calling example group. Any parameters passed into the shared example > > group will be methods which wrap the values given. This way we > > don''t have instance variable naming conflicts (like @other_thing, in > > the example above). > > > > On the other hand, this would also mean that shared example groups > > wouldn''t have the ability to call methods in the calling example group. > > > > Thoughts? > > Copying instance variables around is nasty business. In fact, we > eliminated that from shared behaviours by making them modules that get > included! So I would view that as a step backwards from an > implementation standpoint, and it still feels like voodoo from a > usability standpoint.Well - THAT was nothing but negative. Let me add some positive to balance things: As I think about it, I''m more inclined to make this a completely different method, as I suggested as an option earlier. Something that says "run in another scope with these variables." That way there''s no magic and consequently no confusion. Suggestions?
On Dec 18, 2007 4:30 PM, Rick DeNatale <rick.denatale at gmail.com> wrote:> On 12/18/07, David Chelimsky <dchelimsky at gmail.com> wrote: > > On Dec 18, 2007 11:39 AM, Jonathan Linowes <JONATHAN at linowes.com> wrote: > > > > > > hi, i want to make a behavior shared between models, the examples need to > > > create new instances etc. Is there a way to pass the model class to the > > > shared behavior? > > > > We''re calling these shared example groups now. > > > > The way to affect the state within a shared example group is to use > > before(:each) to set an instance variable: > > > > shared_examples_for "models that do stuff" do > > before(:each) do > > @instance = @class.new > > end > > it "should do something" do > > @instance.should do_something > > end > > end > > > > describe Foo do > > before(:each) do > > @class = Foo > > end > > it_should_behave_like "models that do stuff" > > end > > So I guess this means that the before block for the shared example > group gets executed after the example group using it. I don''t recall > seeing this documented, although I''m sure that it is. > > This helps me a lot. > > Can you do something similar with the new nested example groups? It > doesn''t seem so. > > describe "Shared", :shared => true do > > before(:each) do > @outer = @inner > end > > it "should set @outer to @inner" do > @outer.should == @inner > end > end > > describe "Sharer" do > it_should_behave_like "Shared" > > it "should set @outer to 1" do > @inner = 1 > end > end > > describe "Outer" do > before(:each) do > @outer = @inner > end > > describe "inner one" do > before(:each) do > @inner = 1 > end > > it "should be set outer to 1" do > @outer.should == 1 > end > end > > describe "inner two" do > before(:each) do > @inner = 2 > end > > it "should be set outer to 1" do > @outer.should == 2 > end > end > end > > k$ spec ~/nestedspec.rb > FF.. > > 1) > ''inner one should be set outer to 1'' FAILED > expected: 1, > got: nil (using ==) > /Users/rick/nestedspec.rb:16: > > 2) > ''inner two should be set outer to 1'' FAILED > expected: 2, > got: nil (using ==) > /Users/rick/nestedspec.rb:26: > > Finished in 0.00627 seconds > > 4 examples, 2 failuresThat''s actually as it should be. The common use case for nested is that you create something in the outer group and expand its definition in the inner group. describe Thing do before(:each) { @thing = Thing.new } describe "with special magic powers" do before(:each) { @thing.grant_special_magic_powers } it "should be able to conjure up world peace" do @thing.should be_able_to_conjure_up_world_peace end end end This requires running the befores in the outer groups first, which is the opposite of what your example would require. Make sense? David
On 12/18/07, David Chelimsky <dchelimsky at gmail.com> wrote:> You''d use it like this: > > shared_examples_for "anything" do > it "should do stuff" do > @thing.should do_stuff > end > end > > describe SpecificThing do > it_should_behave_like "anything", :thing => SpecificThing.new > end > > Now comes the tricky part. This can work one of two ways. In either > case it turns :thing into an instance variable @thing. The question is > whether that instance variable is assigned in the scope of the > SpecificThing example group or in a scope created especially to run > the shared examples. Each choice presents usability confusion in my > view. > > Imagine this scenario: > > shared_examples_for "anything" do > it "should do stuff" do > @thing.should do_stuff > end > it "should be like another thing" do > @thing.should be_like(@other_thing) > end > end > > describe SpecificThing do > before(:each) do > @thing = SpecificThing.new > end > it_should_behave_like "anything", :other_thing => SpecificThing.new > > it "should not be unlike other thing" do > @thing.should_not be_unlike(@other_thing) > end > end > > If @other_thing is defined in the context of a separate scope just to > run the shared examples, the shared examples won''t know about @thing. > > If @other_thing in the scope of the example group created by "describe > SpecificThing," then it''s just confusing to look at - both > before(:each) and it_should_behave_like are creating instance > variables in the current scope, and it is NOT clear that is what is > happening. > > If we go w/ the separate scope, then the metaphor of > it_should_behave_like is wrong, because we''re not talking about > something in the current scope that should behave like something else > anymore. We''d probably want a different construct to create these, > even though the underlying mechanism would be the same. > > Thoughts?How about something like (following the example of things like the :include option in ActiveRecord::Base#find: it_should_behave_like "anything", :except_that => { :thing => SpecificThing.new} -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/
On Dec 18, 2007 4:38 PM, Rick DeNatale <rick.denatale at gmail.com> wrote:> How about something like (following the example of things like the > :include option in ActiveRecord::Base#find: > > it_should_behave_like "anything", :except_that => { :thing => > SpecificThing.new}That''s a little better, but I''m really leaning towards a different method name. Don''t know what it is yet. Awaiting suggestions :)
On Dec 18, 2007, at 5:31 PM, David Chelimsky wrote:> On Dec 18, 2007 4:25 PM, David Chelimsky <dchelimsky at gmail.com> wrote: >> >> On Dec 18, 2007 4:22 PM, Scott Taylor >> <mailing_lists at railsnewbie.com> wrote: >>> >>> >>> On Dec 18, 2007, at 5:12 PM, David Chelimsky wrote: >>> >>>> On Dec 18, 2007 3:53 PM, Scott Taylor >>>> <mailing_lists at railsnewbie.com> wrote: >>>>> >>>>> >>>>> On Dec 18, 2007, at 4:42 PM, David Chelimsky wrote: >>>>> >>>>>> On Dec 18, 2007 3:37 PM, Scott Taylor >>>>>> <mailing_lists at railsnewbie.com> wrote: >>>>>>> The >>>>>>> shared behaviours can be thought of modules which are included >>>>>>> into the >>>>>>> current behaviour - so it should also have access to any methods >>>>>>> defined in >>>>>>> the example (group) in which it is shared. >>>>>> >>>>>> You don''t even have to think of it that way - that''s actually >>>>>> what >>>>>> they are - modules that get included. You can actually assign >>>>>> them to >>>>>> a constant and just use Ruby include. >>>>> >>>>> Although we''ve talked about the implementation changing, which >>>>> would >>>>> cause those who use them as modules to have broken specs. >>>> >>>> It would, but we stopped talking about it :) >>>> >>>> It actually works quite well this way. The change came up, iirc, in >>>> the conversation about parameterizing it_should_behave_like, right? >>>> I''ve got a solution for that worked out, but I haven''t applied >>>> it yet >>>> because I want to discuss it a bit: >>>> >>>> You''d use it like this: >>>> >>>> shared_examples_for "anything" do >>>> it "should do stuff" do >>>> @thing.should do_stuff >>>> end >>>> end >>>> >>>> describe SpecificThing do >>>> it_should_behave_like "anything", :thing => SpecificThing.new >>>> end >>>> >>>> Now comes the tricky part. This can work one of two ways. In either >>>> case it turns :thing into an instance variable @thing. The >>>> question is >>>> whether that instance variable is assigned in the scope of the >>>> SpecificThing example group or in a scope created especially to run >>>> the shared examples. Each choice presents usability confusion in my >>>> view. >>>> >>>> Imagine this scenario: >>>> >>>> shared_examples_for "anything" do >>>> it "should do stuff" do >>>> @thing.should do_stuff >>>> end >>>> it "should be like another thing" do >>>> @thing.should be_like(@other_thing) >>>> end >>>> end >>>> >>>> describe SpecificThing do >>>> before(:each) do >>>> @thing = SpecificThing.new >>>> end >>>> it_should_behave_like "anything", :other_thing => >>>> SpecificThing.new >>>> >>>> it "should not be unlike other thing" do >>>> @thing.should_not be_unlike(@other_thing) >>>> end >>>> end >>>> >>>> If @other_thing is defined in the context of a separate scope >>>> just to >>>> run the shared examples, the shared examples won''t know about >>>> @thing. >>>> >>>> If @other_thing in the scope of the example group created by >>>> "describe >>>> SpecificThing," then it''s just confusing to look at - both >>>> before(:each) and it_should_behave_like are creating instance >>>> variables in the current scope, and it is NOT clear that is what is >>>> happening. >>>> >>>> If we go w/ the separate scope, then the metaphor of >>>> it_should_behave_like is wrong, because we''re not talking about >>>> something in the current scope that should behave like something >>>> else >>>> anymore. We''d probably want a different construct to create these, >>>> even though the underlying mechanism would be the same. >>>> >>>> Thoughts? >>> >>> >>> How about this: >>> >>> Use a separate scope, but copy the instance variables from the >>> calling example group. Any parameters passed into the shared >>> example >>> group will be methods which wrap the values given. This way we >>> don''t have instance variable naming conflicts (like @other_thing, in >>> the example above). >>> >>> On the other hand, this would also mean that shared example groups >>> wouldn''t have the ability to call methods in the calling example >>> group. >>> >>> Thoughts? >> >> Copying instance variables around is nasty business. In fact, we >> eliminated that from shared behaviours by making them modules that >> get >> included! So I would view that as a step backwards from an >> implementation standpoint, and it still feels like voodoo from a >> usability standpoint. > > Well - THAT was nothing but negative. > > Let me add some positive to balance things: > > As I think about it, I''m more inclined to make this a completely > different method, as I suggested as an option earlier. Something that > says "run in another scope with these variables." That way there''s no > magic and consequently no confusion.I''m with you on that one. I don''t like "it_should_behave_like" much anyway - I end up aliasing it in a few different forms: it_should_behave_like_a it_should_behave_like_the and so on. Anyway - how do the nested behaviours work right now? Are instance variables being copied? Methods? Scott
On 12/18/07, David Chelimsky <dchelimsky at gmail.com> wrote:> That''s actually as it should be. The common use case for nested is > that you create something in the outer group and expand its definition > in the inner group. > > describe Thing do > before(:each) { @thing = Thing.new } > > describe "with special magic powers" do > before(:each) { @thing.grant_special_magic_powers } > it "should be able to conjure up world peace" do > @thing.should be_able_to_conjure_up_world_peace > end > end > end > > This requires running the befores in the outer groups first, which is > the opposite of what your example would require. > > Make sense?Yes and it helps clarify my questions about how nested groups were different, if at all, from shared groups. -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/
On Dec 18, 2007 4:45 PM, Scott Taylor <mailing_lists at railsnewbie.com> wrote:> > > On Dec 18, 2007, at 5:31 PM, David Chelimsky wrote: > > > On Dec 18, 2007 4:25 PM, David Chelimsky <dchelimsky at gmail.com> wrote: > >> > >> On Dec 18, 2007 4:22 PM, Scott Taylor > >> <mailing_lists at railsnewbie.com> wrote: > >>> > >>> > >>> On Dec 18, 2007, at 5:12 PM, David Chelimsky wrote: > >>> > >>>> On Dec 18, 2007 3:53 PM, Scott Taylor > >>>> <mailing_lists at railsnewbie.com> wrote: > >>>>> > >>>>> > >>>>> On Dec 18, 2007, at 4:42 PM, David Chelimsky wrote: > >>>>> > >>>>>> On Dec 18, 2007 3:37 PM, Scott Taylor > >>>>>> <mailing_lists at railsnewbie.com> wrote: > >>>>>>> The > >>>>>>> shared behaviours can be thought of modules which are included > >>>>>>> into the > >>>>>>> current behaviour - so it should also have access to any methods > >>>>>>> defined in > >>>>>>> the example (group) in which it is shared. > >>>>>> > >>>>>> You don''t even have to think of it that way - that''s actually > >>>>>> what > >>>>>> they are - modules that get included. You can actually assign > >>>>>> them to > >>>>>> a constant and just use Ruby include. > >>>>> > >>>>> Although we''ve talked about the implementation changing, which > >>>>> would > >>>>> cause those who use them as modules to have broken specs. > >>>> > >>>> It would, but we stopped talking about it :) > >>>> > >>>> It actually works quite well this way. The change came up, iirc, in > >>>> the conversation about parameterizing it_should_behave_like, right? > >>>> I''ve got a solution for that worked out, but I haven''t applied > >>>> it yet > >>>> because I want to discuss it a bit: > >>>> > >>>> You''d use it like this: > >>>> > >>>> shared_examples_for "anything" do > >>>> it "should do stuff" do > >>>> @thing.should do_stuff > >>>> end > >>>> end > >>>> > >>>> describe SpecificThing do > >>>> it_should_behave_like "anything", :thing => SpecificThing.new > >>>> end > >>>> > >>>> Now comes the tricky part. This can work one of two ways. In either > >>>> case it turns :thing into an instance variable @thing. The > >>>> question is > >>>> whether that instance variable is assigned in the scope of the > >>>> SpecificThing example group or in a scope created especially to run > >>>> the shared examples. Each choice presents usability confusion in my > >>>> view. > >>>> > >>>> Imagine this scenario: > >>>> > >>>> shared_examples_for "anything" do > >>>> it "should do stuff" do > >>>> @thing.should do_stuff > >>>> end > >>>> it "should be like another thing" do > >>>> @thing.should be_like(@other_thing) > >>>> end > >>>> end > >>>> > >>>> describe SpecificThing do > >>>> before(:each) do > >>>> @thing = SpecificThing.new > >>>> end > >>>> it_should_behave_like "anything", :other_thing => > >>>> SpecificThing.new > >>>> > >>>> it "should not be unlike other thing" do > >>>> @thing.should_not be_unlike(@other_thing) > >>>> end > >>>> end > >>>> > >>>> If @other_thing is defined in the context of a separate scope > >>>> just to > >>>> run the shared examples, the shared examples won''t know about > >>>> @thing. > >>>> > >>>> If @other_thing in the scope of the example group created by > >>>> "describe > >>>> SpecificThing," then it''s just confusing to look at - both > >>>> before(:each) and it_should_behave_like are creating instance > >>>> variables in the current scope, and it is NOT clear that is what is > >>>> happening. > >>>> > >>>> If we go w/ the separate scope, then the metaphor of > >>>> it_should_behave_like is wrong, because we''re not talking about > >>>> something in the current scope that should behave like something > >>>> else > >>>> anymore. We''d probably want a different construct to create these, > >>>> even though the underlying mechanism would be the same. > >>>> > >>>> Thoughts? > >>> > >>> > >>> How about this: > >>> > >>> Use a separate scope, but copy the instance variables from the > >>> calling example group. Any parameters passed into the shared > >>> example > >>> group will be methods which wrap the values given. This way we > >>> don''t have instance variable naming conflicts (like @other_thing, in > >>> the example above). > >>> > >>> On the other hand, this would also mean that shared example groups > >>> wouldn''t have the ability to call methods in the calling example > >>> group. > >>> > >>> Thoughts? > >> > >> Copying instance variables around is nasty business. In fact, we > >> eliminated that from shared behaviours by making them modules that > >> get > >> included! So I would view that as a step backwards from an > >> implementation standpoint, and it still feels like voodoo from a > >> usability standpoint. > > > > Well - THAT was nothing but negative. > > > > Let me add some positive to balance things: > > > > As I think about it, I''m more inclined to make this a completely > > different method, as I suggested as an option earlier. Something that > > says "run in another scope with these variables." That way there''s no > > magic and consequently no confusion. > > I''m with you on that one. I don''t like "it_should_behave_like" much > anyway - I end up aliasing it in a few different forms: > > it_should_behave_like_a > it_should_behave_like_the > > and so on. > > Anyway - how do the nested behaviours work right now? Are instance > variables being copied? Methods?They are subclasses!!!! It''s pretty sweet. We can thank Brian (and Aslak, too) for getting us there. Basically there is no copying, just inheriting or, in the case of shared, mixing in. Ruby does the rest for free.> > > Scott > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
On Dec 18, 2007 4:46 PM, Rick DeNatale <rick.denatale at gmail.com> wrote:> On 12/18/07, David Chelimsky <dchelimsky at gmail.com> wrote: > > > That''s actually as it should be. The common use case for nested is > > that you create something in the outer group and expand its definition > > in the inner group. > > > > describe Thing do > > before(:each) { @thing = Thing.new } > > > > describe "with special magic powers" do > > before(:each) { @thing.grant_special_magic_powers } > > it "should be able to conjure up world peace" do > > @thing.should be_able_to_conjure_up_world_peace > > end > > end > > end > > > > This requires running the befores in the outer groups first, which is > > the opposite of what your example would require. > > > > Make sense? > > Yes and it helps clarify my questions about how nested groups were > different, if at all, from shared groups.My response to scott''s mail should enlighten that a bit as well. Nested groups are subclasses of the outer groups. Shared groups get mixed in.> > > -- > Rick DeNatale > > My blog on Ruby > http://talklikeaduck.denhaven2.com/ > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >