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 <[email protected]>
>> 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
>>> [email protected]http://rubyforge.org/mailman/listinfo/rspec-users
>> _______________________________________________
>> rspec-users mailing list
>> [email protected]
>> http://rubyforge.org/mailman/listinfo/rspec-users
>
_______________________________________________
rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users