The difference between using include and extend when including modules in a Class
19 Jan 2017We’ve seen the use of include for including methods from a module into a Class. The following shows three modules included into Class A:
module B
def b
:b
end
end
module C
def c
:c
end
end
module D
def d
:d
end
end
class A
include B
include C
include D
end
Include turns the methods inside the module into instance methods for that class:
puts A.new.b >> b
puts A.new.c >> c
puts A.new.d >> d
However you can also change the methods into class methods by using extend:
module B
def b
:b
end
end
module C
def c
:c
end
end
module D
def d
:d
end
end
class A
extend B
extend C
extend D
end
puts A.b >> b
puts A.c >> c
puts A.d >> d
Notice how we didn’t have to change the method definitions inside the module to self.method. This is because modules have no sense of Class, they’re just buckets for methods. They are called ‘mixins’ because they mix methods into wherever they are included or extended into.
Our team architect Adam Zaninovich gives the analogy of modules being ‘viruses’ and classes being ‘hosts’. Modules ‘infect’ classes with their ‘methods’ (in a good way in this case), in the sense that viruses inject their dna into host cells.
I wrote include in class A three times which is repetitive. If you find that you are including modules in a class many times you can avoid this by using the self.included module method.
module B
def self.included(klass)
klass.include C
klass.include D
end
def b
:b
end
end
module C
def c
:c
end
end
module D
def d
:d
end
end
class A
include B
end
puts A.new.b >> b
puts A.new.c >> c
puts A.new.d >> d
Now there is only ‘include B’ inside class A. Whenever B is included in a Class, it calls self.included which passes in the class A as an argument. “self.included” then included modules C and D into the klass passed as the argument which in our case is class A.
Also, the self.included method comes in handy when you want your module to have BOTH instance and class methods. The following module C demonstrates the conventional way to specify both instance and class methods inside a module.
module C
def self.included(base)
base.extend(ClassMethods)
end
def c
:c
end
module ClassMethods
def b
:b
end
end
end
class A
include C
end
puts A.new.c >> c
puts A.b >> b