What is the difference between include and extend in Ruby?
What you have said is correct. However, there is more to it than that.
If you have a class Klazz
and module Mod
, including Mod
in Klazz
gives instances of Klazz
access to Mod
's methods. Or you can extend Klazz
with Mod
giving the class Klazz
access to Mod
's methods. But you can also extend an arbitrary object with o.extend Mod
. In this case the individual object gets Mod
's methods even though all other objects with the same class as o
do not.
What is the difference between include module and extend module in Ruby?
I wrote a blog posting about this a long time ago here.
When you're "including" a module, the module is included as if the methods were defined at the class that's including them, you could say that it's copying the methods to the including class.
When you're "extending" a module, you're saying "add the methods of this module to this specific instance". When you're inside a class definition and say "extend" the "instance" is the class object itself, but you could also do something like this (as in my blog post above):
module MyModule
def foo
puts "foo called"
end
end
class A
end
object = A.new
object.extend MyModule
object.foo #prints "foo called"
So, it's not exactly a class method, but a method to the "instance" which you called "extend". As you're doing it inside a class definition and the instance in there is the class itself, it "looks like" a class method.
Extend and Include
module Foo
def self.included(base)
base.extend Foo::ClassMethods
end
module ClassMethods
def guitar
"gently weeps"
end
end
end
class Bar
include Foo
end
puts Bar.guitar
What is the difference between include and require in Ruby?
What's the difference between
"include" and "require" in Ruby?Answer:
The include and require methods do
very different things.The require method does what include
does in most other programming
languages: run another file. It also
tracks what you've required in the
past and won't require the same file
twice. To run another file without
this added functionality, you can use
the load method.The include method takes all the
methods from another module and
includes them into the current module.
This is a language-level thing as
opposed to a file-level thing as with
require. The include method is the
primary way to "extend" classes with
other modules (usually referred to as
mix-ins). For example, if your class
defines the method "each", you can
include the mixin module Enumerable
and it can act as a collection. This
can be confusing as the include verb
is used very differently in other
languages.
Source
So if you just want to use a module, rather than extend it or do a mix-in, then you'll want to use require
.
Oddly enough, Ruby's require
is analogous to C's include
, while Ruby's include
is almost nothing like C's include
.
Ruby mixins: extend and include
The difference is that include
will add the included class to the ancestors of the including class, whereas extend
will add the extended class to the ancestors of the extending classes' singleton class. Phew. Let's first observe what happens:
Bacon.ancestors
#=> [Bacon, Object, Kernel, BasicObject]
Bacon.singleton_class.ancestors
#=> [Bar, Baz, Class, Module, Object, Kernel, BasicObject]
Bacon.new.singleton_class.ancestors
#=> [Bacon, Object, Kernel, BasicObject]
Bacon.is_a? Bar
#=> true
Bacon.new.is_a? Bar
#=> false
And for the Egg
class
Egg.ancestors
#=> [Egg, Bar, Baz, Object, Kernel, BasicObject]
Egg.singleton_class.ancestors
#=> [Class, Module, Object, Kernel, BasicObject]
Egg.new.singleton_class.ancestors
#=> [Egg, Bar, Baz, Object, Kernel, BasicObject]
Egg.is_a? Bar
#=> false
Egg.new.is_a? Bar
#=> true
So what foo.is_a? Klass
actually does is to check whether foo.singleton_class.ancestors
contains Klass
. The other thing happening is that all the ancestors of a class become ancestors of an instances' singleton class when the instance is created. So this will evaluate to true for all newly created instances of any class:
Egg.ancestors == Egg.new.singleton_class.ancestors
So what does all this mean? extend
and include
do the same thing on different levels, i hope the following example makes this clear as both ways to extend a class are essentially equivalent:
module A
def foobar
puts 'foobar'
end
end
class B
extend A
end
class C
class << self
include A
end
end
B.singleton_class.ancestors == C.singleton_class.ancestors
#=> true
where class << self
is just the odd syntax to get to the singleton class. So extend
really just is a shorthand for include
in the singleton class.
include vs. extend and Comparable module in Ruby
Include is for adding methods to an instance of a class and extend is for adding class methods:
http://www.railstips.org/blog/archives/2009/05/15/include-vs-extend-in-ruby/
Both :> and :between are methods.
The difference is here:
If you see Class0 methods you have :>, :>=, :<, :<= defined as class methods.
When Class2 extend Comparable it will get the between? method as class method.
In the second case you have Class0 and Class1 instances, so the a instance of Class0 doesn't have the :>, :>=, :<, :<=, :between? methods defined as instance methods. Once you include the comparable Module in Class1, it will get all this methods as instance methods from Module, so you will have all [:>, :>=, :<, :<=, :between?] methods available in the instance b.
This is why you get those results.
I found another nice explanation of include VS extend here:
http://aaronlasseigne.com/2012/01/17/explaining-include-and-extend/
ActiveSupport::Concern should be included or extended
You need to extend the module with ActiveSupport::Concern
in order for the ActiveSupport::Concern#included
and #class_methods
methods to work properly.
These two methods are after all pretty much the only reason for its existance.
module A
extend ActiveSupport::Concern
# raises ArgumentError (wrong number of arguments (given 0, expected 1))
included do
puts "Hello World"
end
end
module B
extend ActiveSupport::Concern
included do
puts "Hello World"
end
end
class C
include B
end
# Outputs Hello World
Check out what happens if we inspect the included
method:
module AB
include ActiveSupport::Concern
puts method(:included).source_location # nil
end
module ABC
extend ActiveSupport::Concern
puts method(:included).source_location # .../ruby/gems/2.7.0/gems/activesupport-6.0.2.1/lib/active_support/concern.rb
end
When we extend the module with ActiveSupport::Concern
we are putting it on the ancestors chain of ABC
, thus the methods of ActiveSupport::Concern
are available as module methods of ABC
. This does not happen when you use include
and the included
method called is actually Module#included from the Ruby core.
Ruby extend & include tracing code
When you extend
a module, the methods in that module become "class methods"**. So, when you extend Inventoryable
, create
becomes available as a method on the Shirt
class.
When you include
a module, the methods in that module become "instance methods"**. So, when you include Inventoryable
, create
is not available on the Shirt
class (but is available on an instance of Shirt
).
To make create
available on the Shirt
class when using include
, you can use the included
hook. That might look something like:
module Inventoryable
module ClassMethods
def create
puts "create!"
end
end
module InstanceMethods
end
def self.included(receiver)
receiver.extend ClassMethods
receiver.include InstanceMethods
end
end
Then if you do:
class Shirt
include Invetoryable
end
You can do:
> Shirt.create
create!
=> nil
** The ruby purists in the crowd will correctly point out that, in ruby, everything is an instance method and that there are no class methods. That is formally 100% correct, but we'll use the colloquial meaning of class
and instance
methods here.
Related Topics
How to Avoid Nomethoderror For Missing Elements in Nested Hashes, Without Repeated Nil Checks
Ruby 1.9: Invalid Byte Sequence in Utf-8
What Are All the Common Ways to Read a File in Ruby
Ruby Multiline Block Without Do End
Submit Post Data from Controller to Another Website in Rails
What's Different Between Each and Collect Method in Ruby
Understanding the "||" or Operator in If Conditionals in Ruby
How Does the Magic Comment ( # Encoding: Utf-8 ) in Ruby Work
Ruby 2.0 Rails Gem Install Error "Cannot Load Such File - Openssl"
Protected and Private Methods in Rails
How to Find Where a Method Is Defined At Runtime
Look Up All Descendants of a Class in Ruby
Best Way to Create Custom Config Options For My Rails App
How to Get a Specific Output Iterating a Hash in Ruby
Suppress Ruby Warnings When Running Specs