[rspec-users] Evaluating shared example customisation block before shared block

David Chelimsky dchelimsky at gmail.com
Fri Jul 30 10:03:41 EDT 2010


On Jul 30, 2010, at 5:13 AM, Ashley Moran wrote:

> Hi
> 
> I finally looked into why this is not currently possibly in RSpec 2 (beta 19):
> 
>  shared_examples_for "Etymology" do
>    describe "The etymology of foo" do
>      it "is followed by #{after_foo}" do
>        # ...
>      end
>    end
>  end
> 
>  describe "foo", focus: true do
>    it_should_behave_like "Etymology" do
>      def self.after_foo
>        "bar"
>      end
>    end
>  end
> 
> It's because of the current implementation of ExampleGroup.define_shared_group_method, which evaluates the shared example block before the customisation block:
> 
>   shared_group = describe("#{report_label} \#{name}", &shared_block)
>   shared_group.class_eval(&customization_block) if customization_block
> 
> (This is behaviour I found surprising.)
> 
> However, with a little more metaprogramming jiggery-pokery, you can have them evaluated in the other order:
> 
>  module RSpec
>    module Core
>      class ExampleGroup
>        # ...
> 
>        def self.define_shared_group_method(new_name, report_label=nil)
>          report_label = "it should behave like" unless report_label
>          module_eval(<<-END_RUBY, __FILE__, __LINE__)
>            def self.#{new_name}(name, &customization_block)
>              shared_block = world.shared_example_groups[name]
>              raise "Could not find shared example group named \#{name.inspect}" unless shared_block
> 
>              compound_block = lambda do |*args|
>                module_eval &customization_block if customization_block
>                module_eval &shared_block
>              end
> 
>              shared_group = describe("#{report_label} \#{name}", &compound_block)
>              shared_group
>            end
>          END_RUBY
>        end
> 
>        # ...
>      end
>    end
>  end
> 

Or ...

      def self.define_shared_group_method(new_name, report_label=nil)
        report_label = "it should behave like" unless report_label
        module_eval(<<-END_RUBY, __FILE__, __LINE__)
          def self.#{new_name}(name, &customization_block)
            shared_block = world.shared_example_groups[name]
            raise "Could not find shared example group named \#{name.inspect}" unless shared_block

            describe "#{report_label} \#{name}" do
              module_eval &customization_block if customization_block
              module_eval &shared_block
            end
          end
        END_RUBY
      end

> Would this be a useful improvement to RSpec 2?

Yes

> Any opinions on the order of the block evaluation for shared examples

Makes perfect sense to me. Wanna make a patch with an additional scenario in the cuke?

> 
> Cheers
> Ash
> 
> -- 
> http://www.patchspace.co.uk/
> http://www.linkedin.com/in/ashleymoran
> 
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users



More information about the rspec-users mailing list