On Aug 1, 2010, at 9:43 AM, David Chelimsky wrote: > > On Jul 31, 2010, at 1:06 PM, Myron Marston wrote: > >>> You can still get the same outcome, but you have to implement it in the >>> group like this: >> >>> unless defined?(:foo) >>> def foo; "foo"; end >>> end >> >> Good point--I hadn't thought of that. The one issue I see with it is >> that the author of the shared example group may not have knowledge of >> which helper methods consumers will need to override. > > That's no different from methods that have default values for arguments: > > def foo(bar, baz = :default) > > If you provide only 1 arg, all is well, but the first one is required. Here's > the same idea expressed in a group: > > shared_examples_for "foo" do > unless defined?(:bar) > raise "you need to supply a bar() method" > end > > unless defined?(:baz) > def baz; :default; end > end > end > >> So he/she >> either defines all helper methods that way, or guesses about which >> ones to define that way (and potentially guesses wrong). >> >>> Maybe a DSL method while I'm working on it? Maybe: >>> >>> default_helper(:foo) do >>> "foo" >>> end >>> >>> WDYT? >> >> If we go the route of having the customization block evaluated first, >> then I like the idea, but I'm generally wary of adding more DSL >> methods to RSpec. I think we should be careful to only add new DSL >> methods that many people will find useful. If you find it useful, >> it's very easy to use it in your project without it being part of >> RSpec: just define default_helper in a module, and use config.extend >> YourModule in the RSpec.configuration block. (Note that I'm _not_ >> against adding this to RSpec: I just want to be sure we don't add a >> bunch of DSL methods that have limited usefulness.) >> >> Looking back at the initial example that prompted the thread, it looks >> to me like the primary use case for evaluating the customization block >> first is so that you can parameterize the shared example group's >> example descriptions. (There may be other use cases for defining a >> class-level helper methods, but none springs to mind). I also do this >> frequently. Often times I have something like this: >> >> [:foo, :bar, :baz].each do |method| >> it "does something for #{method}" do >> subject.send(method).should ... >> end >> end >> >> In this case I'm using the method parameter at the class level (to >> interpolate into the description string) and at the instance level >> (within the example itself). >> >> If we evaluated the customization block first, it would allow this, >> but you'd have to define both an instance and class helper: >> >> it_should_behave_like "something" do >> def self.method_name; :foo; end >> def method_name; :foo; end >> end >> >> I think this is a clunky way to essentially pass a parameter to the >> shared example group. Better would be something like this: >> >> it_should_behave_like "something" do >> providing :method_name, :foo >> end >> >> The instance of the shared example group provides :foo as the value of >> the method_name parameter. providing simply defines a class and an >> instance helper method with the given value. >> >> I've written up an untested gist with a start for the code that would >> implement this: >> >> http://gist.github.com/502409 >> >> I think there's value in evaluating the customization block first and >> value in evaluating it last. We can get the best of both worlds if we >> limit what's evaluated first to a subset (say, a few DSL methods, and >> maybe all class method definitions), extract it, and evaluate that >> first, then evaluate the shared block first, then evaluate the >> customization block. The gist demonstrates this as well. This may >> confuse people, but it does give us the best of both worlds, I think. > > Agreed on both points: best of both worlds and confusing :) > > When I said "maybe a DSL" I was thinking only in the context of the shared > group, not in the consuming group. > > What makes the example in your gist confusing to me is that we start to get > into a different mental model of what a shared group is. Based on recent > changes, for me, it's just a nested example group, which has well understood > scoping rules. This introduces a new set of scoping rules that not only make > this use case confusing, but it will lead to an expectation that this DSL be > made available in other constructs. > > The particular issue of simple values being used in the docstrings and the > examples themselves (i.e. exposed to everything in the block scope) could be > handled like this: > > shared_examples_for "blah" do |a,b| > ... > end > > it_should_behave_like "blah", 1, 2 > > That wouldn't have worked with the old implementation, but it would work > perfectly well now. This would also "just work" with hash-as-keyword-args: > > shared_examples_for "blah" do |options| > it "blah #{options[:a]}" do > .. > end > end > > it_should_behave_like "blah", :a => 1 > > Now you can do this: > > [1,2,3].each do |n| > it_should_behave_like "blah", :a => n > end > > And we can still use the customization block to define methods, hooks > (before/after) and let(). Now it just feels like the rest of RSpec.
Here's one way the measurement example could work in this format: http://gist.github.com/503432 > > Thoughts? > > > >> >> Myron >> >> >> On Jul 31, 12:56 am, Ashley Moran <ashley.mo...@patchspace.co.uk> >> wrote: >>> On 31 Jul 2010, at 1:10 AM, David Chelimsky wrote: >>> >>>> You can still get the same outcome, but you have to implement it in the >>>> group like this: >>> >>>> unless defined?(:foo) >>>> def foo; "foo"; end >>>> end >>> >>> Maybe a DSL method while I'm working on it? Maybe: >>> >>> default_helper(:foo) do >>> "foo" >>> end >>> >>> WDYT? >>> >>>> I think it's a good trade-off to put that burden on the group (and it's >>>> author) rather that the consumers of the group. >>> >>> Agreed, it'd cause a lot of duplication of effort the other way round. >>> >>> --http://www.patchspace.co.uk/http://www.linkedin.com/in/ashleymoran >>> >>> _______________________________________________ >>> rspec-users mailing list >>> rspec-us...@rubyforge.orghttp://rubyforge.org/mailman/listinfo/rspec-users >> _______________________________________________ >> rspec-users mailing list >> rspec-users@rubyforge.org >> http://rubyforge.org/mailman/listinfo/rspec-users > _______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users