Module and Class in Ruby

dieutb
3 min readMay 28, 2021
  • As we can see, Class actually inherit from Module.
  • RUBY doesn’t allow multiple inheritances. To achieve that we can use the mixin facilities by importing the module.

MODULE

  • There are 3 ways to import a mixin facility to a classinclude,prepend, extend. Let see what difference between them.

1. include

  • is the most used and the simplest way of importing module code. When calling it in a class definition, Ruby will insert the module into the ancestry chain of the class, just after it.
module T1; end
module T2; end
module T3; end
class A
include T1
include T2
end
A.ancestors #=> [A, T2, T1, Object, Kernel, BasicObject]
Object.class_eval do
include T3
end
A.ancestors #=> [A, T2, T1, Object, T3, Kernel, BasicObject]
  • Import instance methods, instance variables from module to the class. It means the class’s instances can have module methods (only instance methods, not class methods), instance variables.
  • class also can access module’s class_variable, but not class_instance_variable.
  • No import class methods

2. prepend

  • the same method as include but the module will be inserted to the beginning of the ancestry line
module T1
def t
'method t of module T1'
end
end
module T2
def t
'method t of module T2'
end
end
class A
prepend T1
include T2
def t
'method t of class A'
end
end
A.ancestors #=> [T1, A, T2, Object, Kernel, BasicObject]
A.new.t #=> it would print 'method t of module T1'. Because when call a method, ruby will seek it from the beginning of the chain. If the T1 doesn't have "t" method, it continues search on the next one on the right.

3. extend

  • When a class extends a module, only the module’s instance methods are imported to its singleton class, both module’s class methods and the variables aren’t imported.
  • With extend, the module would not be inserted into the class’s ancestry chain.
module T1
def method_1
'method 01'
end
end
module T2
end
class A
extend T1
include T2
end
A.ancestors #=> [A, T2, Object, Kernel, BasicObject]
A.singleton_methods
=> [:method_1]

4. callback and one-time import

  • Ruby support callback include, prepend, extend a module.
  • a module can only import one time to the ancestry chain.
module T
def self.included(klass)
p "callback when included module T from #{klass.name}"
end
def self.prepended(klass)
p "callback when prepended module T from #{klass.name}"
end
def self.extended(klass)
p "callback when extended module T from #{klass.name}"
end
end
class A
include T
prepend T
extend T
end
#=> "callback when included module T from A"
#=> "callback when prepended module T from A"
#=> "callback when extended module T from A"
a.ancestors
#=> [A, T, Object, Kernel, BasicObject]
class B < A
include T # Because T already exist on the ancestry chain, then no action happen, but the callback still fire
end
#=> "callback when included module T from B"
b.ancestors
#=> [B, A, T, Object, Kernel, BasicObject]

Class

  • When class A inherits from class B, A inherits all methods and variables from B (both private, protected, public)
  • What difference between private, protected, public variable/method?

Constant Table and Nested Constant

  • As default, both class and module have their access to their internal constants that have been stored in constant table. We can check the accessible constant by the method constants
  • When calling a constant inside a nested, Ruby will look at the nesting constant of the scope

References:

--

--

dieutb

passion in finding solutions and research some things relate to technical and helpful in life. Also strongly interest in foods, travel, and gentle music :)