Table of contentsClick link to navigate to the desired location
This content has been automatically translated from Ukrainian.
In Ruby, modules are used to reuse code. Addition method module affects where and how methods from the module become available.
include - adds methods as instance methods
- Module methods are becoming available for all class objects.
- Used when they want the methods to be in class instances.
module Greetings
def hello
"Hi!"
end
end
class User
include Greetings
end
u = User.new
u.hello # => "Hi!"
Module methods appear in the ancestral chain of the class (ancestors) after the class itself, that is, you can override them in the class. But let's take a closer look at it. In Ruby, every class has chain of ancestors (ancestors) - the order in which Ruby searches for methods when called on an object.
module Greetings
def hello
"Hi from module"
end
end
class User
include Greetings
def hello
"Hi from class"
end
end
p User.ancestors
# => [User, Greetings, Object, Kernel, BasicObject]
When you make include Greetings, Ruby inserts the module after class in the chain of ancestors. Or if it's easier to remember - above class.
This means that class methods overlap module methods, if they have the same names.
u = User.new u.hello # => "Hi from class"
Ruby first searches for the method in the class itself (User). Then, if it does not find it, it checks the modules in the chain (Greetings), then the ancestors (Object, Kernel).
extend - adds methods as class methods
- Module methods are becoming available directly on the classroom, not on instances.
- Convenient for adding "class methods" without explicit self.method.
module Tools
def info
"Class method!"
end
end
class User
extend Tools
end
User.info # => "Class method!"
User.new.info # => NoMethodError
Ruby actually adds methods in the singleton class of the object (the class itself is an object).
prepend - Adds pre-class methods in the ancestral chain
- Module methods are emerging before the class in the chain of ancestors.
- This means that module methods can override class methods.
module Greetings
def hello
"Hello from module"
end
end
class User
prepend Greetings
def hello
"Hello from class"
end
end
p User.ancestors
# => [Greetings, User, Object, Kernel, BasicObject]
Key point: Greetings is in front of the User class.
Ruby looks for methods in the order that ancestors shows.
So when you call u.hello, Ruby first sees the method in the Greetings module, and only then in the User class.
u = User.new u.hello # => "Hello from module"
Using super in the module
If the module is called super, Ruby will go further along the chain of ancestors and will execute the class method:
module Greetings
def hello
super + "and module"
end
end
class User
prepend Greetings
def hello
"Hello from class"
end
end
u = User.new
u.hello # => "Hello from class and module"
Why so?
- Ruby calls hello in the Greetings module (because it is the first in ancestors).
- There is a super. Ruby searches for the following method in the ancestral chain, that is, in the User class.
- The class method returns "Hello from class", then "and module" is added.
In short
include -> module methods become methods copies class, module after class in the chain of ancestors.
extend -> module methods become methods class or specific object (singleton class).
prepend -> module methods become methods copies, but before class in the chain of ancestors, that is, they have priority over class methods.
This post doesn't have any additions from the author yet.