[rspec-users] Understanding of extend/include

316 views
Skip to first unread message

Gordon

unread,
Dec 4, 2011, 7:15:08 PM12/4/11
to rspec...@rubyforge.org, anex...@gmail.com
hi, there

I have been looking at
https://www.relishapp.com/rspec/rspec-core/docs/helper-methods/define-helper-methods-in-a-module.

This is the documentation for usage of extend and include.

In the section, "Scenario: extend a module in only some example
groups",
I refer to the setup in RSpec.configure, "c.extend Helpers, :foo
=> :bar"
implies that the methods in Helpers are available to examples with the
metadata, ":foo=>:bar".

------------- Extract start ---------------

describe "an example group with matching metadata", :foo => :bar do
puts "In a matching group, help is #{help}"

it "does not have access to the helper methods defined in the
module" do
expect { help }.to raise_error(NameError)
end
end

------------- Extract end ---------------

Question: Why is the example expected to fail (ie.
raise_error(NameError))
when the meta data matches and it's expected to pass?
_______________________________________________
rspec-users mailing list
rspec...@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users

David Chelimsky

unread,
Dec 4, 2011, 7:53:16 PM12/4/11
to rspec-users
On Dec 4, 2011, at 6:15 PM, Gordon wrote:

> hi, there
>
> I have been looking at
> https://www.relishapp.com/rspec/rspec-core/docs/helper-methods/define-helper-methods-in-a-module.
>
> This is the documentation for usage of extend and include.
>
> In the section, "Scenario: extend a module in only some example
> groups",
> I refer to the setup in RSpec.configure, "c.extend Helpers, :foo
> => :bar"
> implies that the methods in Helpers are available to examples with the
> metadata, ":foo=>:bar".
>
> ------------- Extract start ---------------
>
> describe "an example group with matching metadata", :foo => :bar do
> puts "In a matching group, help is #{help}"
>
> it "does not have access to the helper methods defined in the
> module" do
> expect { help }.to raise_error(NameError)
> end
> end
>
> ------------- Extract end ---------------
>
> Question: Why is the example expected to fail (ie.
> raise_error(NameError))
> when the meta data matches and it's expected to pass?

In Ruby, when we include modules in classes, their methods are available in instances of those classes.

module Helper
def help
:available
end
end

class Foo
include Helper
end

foo = Foo.new
foo.help # => :available

We can also make the same methods available by extending an instance of a class.

class Bar
end

bar = Bar.new
bar.extend(Helper)
bar.help # => :available

Now the tricky part is that classes are objects as well - instances of the Class class. This means that when you extend a class, its methods are available as class methods, not as instance methods:

class Baz
extend Helper
end

Baz.help # => :available
Baz.new.help # => ERROR!!!!!!!

In RSpec, an example group is a class, whereas an example is (effectively) an instance of that class. This is not 100% accurate, but let's go with that metaphor for the moment. When you say "config.include SomeModule", it gets included into example groups, making its methods available within examples (instances of the group). When you say "config.extend SomeModule", it extends the example group, making its methods available within at the group level, but not within the examples.

In the scenario you cite, the module is used to extend the example group matching :foo => :bar (the first group), so it is available at the group level, as demonstrated by `puts "In a matching group, help is #{help}"` printing out "In a matching group, help is available", but is not available in the other group, as demonstrated by `puts "In a non-matching group, help is #{help rescue 'not available'}"` printing out "In a non-matching group, help is not available", and it is not available to examples (instances) in either group, as demonstrated by `expect { help }.to raise_error(NameError)` passing in both examples.

HTH,
David

Gordon Yeong

unread,
Dec 4, 2011, 10:39:06 PM12/4/11
to rs...@googlegroups.com
Makes sense. From your explaination and examples,

1) when include is being used, helper methods of a module can ALSO be accessed by the example groups. Hence, 

 class Baz
   include Helper
 end

 Baz.help # => :available
 Baz.new.help # => :avalable


2) when exclude is being used, it's only limited to only 1 'level' of the extension (ie. either the class or the instantiation of the class (object)). 

Am I right?

David Chelimsky

unread,
Dec 4, 2011, 10:59:22 PM12/4/11
to rs...@googlegroups.com
On Dec 4, 2011, at 9:39 PM, Gordon Yeong wrote:

> Makes sense. From your explanation and examples,


>
> 1) when include is being used, helper methods of a module can ALSO be accessed by the example groups. Hence,
>
> class Baz
> include Helper
> end
>
> Baz.help # => :available
> Baz.new.help # => :avalable

Nope. Only the examples (instances) e.g. Baz.new.help.

> 2) when exclude is being used, it's only limited to only 1 'level' of the extension (ie. either the class or the instantiation of the class (object)).

extend, not exclude.

No - extend adds methods of the module to the example group - never the example. Since nested example groups are subclasses of their parents, they are also available in nested groups, but not in any examples.

> Am I right?

Guess not :)

You can prove this all out by trying different combos yourself and seeing what's available when/where.

Cheers,
David

Gordon Yeong

unread,
Dec 5, 2011, 12:03:51 AM12/5/11
to rs...@googlegroups.com
David, you're quite right. 


I found the following definition for both in http://marakana.com/bookshelf/ruby_tutorial/modules.html very helpful.
  • include - mixes in a module into the class' objects (instantiations)
  • extend - mixes in a module's into self and the module's methods are available as class methods

I have also posted the question which ultimately leads to finding out the differences between include and extend in the rspec google group.

I wrote a few test scripts to learn about this more.

I have updated my little blog to document what I have learnt today


Reply all
Reply to author
Forward
0 new messages