Recall that if a module M1 is included or extended (or prepended) by a module M2, M1's instance methods are brought into M2, either as instance methods (if including) or as module methods (if extending). If M1 contains module methods (methods invoked on M1) they are skipped over by both include and extend. As classes are modules, this applies when M2 is a class.
module M1
def i() end
def self.m() end
end
M1.instance_methods
#=> [:i]
M1.methods(false)
#=> [:m]
module M2; end
M2.extend M1
M2.instance_methods
#=> []
M2.methods & [:i, :m]
#=> [:i]
module M3; end
M3.include M1
M3.instance_methods
#=> [:i]
M3.methods & [:i, :m]
#=> []
We see that neither M2 nor M3 contains a method :m. Now consider the following.
module A
def a
puts 'hi'
end
end
module B
extend A
end
B.instance_methods
#=> []
B.methods & [:a]
#=> [:a]
As expected, B contains no instance methods and its module methods include :a. From the earlier discussion it follows that including or extending B into another module (or class) C brings no instance methods or methods into C.
To add to the functionality of A, B must include (or prepend) A.
module B
include A
def b
puts 'ho'
end
end
B.instance_methods
#=> [:b, :a]
B.methods & [:a, :b]
#=> []
C may then include or extend B, depending on requirements.
One may ask whether there is any reason to define module methods if they are disregarded when the module is included or extended by another module. The answer is that they are simply helper methods that behave as functions in non-OOP languages. An example is the module Math, which contains module methods only. They are therefore invoked on the module; for example,
Math.sqrt(2)
#=> 1.4142135623730951
extendit will create class, not instance, methods. Although you can also create class methods viaincludetoo using a bit of extra magic by the way of theincludedmethod which can thenextendthe target class with a nested module by convention calledClassMethods.