Last updated on June 30th, 2024 at 03:03 pm
Table of Contents
In addition to Classes, Ruby has the concept of modules.
What are Modules?
Taken from GitHub, the purpose of modules are:
Modules serve two purposes in Ruby, namespacing and mix-in functionality.
A namespace can be used to organize code by package or functionality that separates common names from interference by other packages. For example, the IRB namespace provides functionality for irb that prevents a collision for the common name “Context”.
Mix-in functionality allows sharing common methods across multiple classes or modules. Ruby comes with the Enumerable mix-in module which provides many enumeration methods based on the each
method and Comparable allows comparison of objects based on the <=>
comparison method.
Note that there are many similarities between modules and classes. Besides the ability to mix-in a module, the description of modules below also applies to classes.
Creating Modules
A module is created as one would expect in Ruby. Simply declare it as you would a class.
module ModuleName
# Module contents
end
Similar to Classes, you can nest modules
module OuterModule
module InnerModule
end
end
or
module OuterModule::InnerModule
end
However, be aware that if you declare module OuterModule::InnerModule
before you declare module OuterModule
, you will get a NameError because OuterModule won’t be found. That is, you cannot implicitly define modules.
Additionally, you need to be aware that if you nest the modules using ::
instead of cascading declarations, you lose the ability to access variables that are defined within the scope of the top level modules. For example,
module OuterModule
myVar = "abc"
module InnerModule
puts myVar # outputs "abc"
end
end
vs
module OuterModule
myVar = "abc"
end
module OuterModule::InnerModule
puts myVar # raises NameError
end
Extending Modules
You can extend a Module in the same manner that you can extend a Class. Simply open it up again.
module MyModule
myVar = "123"
end
module MyModule
def my_method
puts myVar
end
end
As with classes, it is strongly suggested that you don’t modify Modules that you didn’t create. Any changes to the inherited Module can potentially have knock-on effects in your declarations.
Methods in Modules
A method is defined in a Module no differently than within a class. It is accessed, however, without requiring an object.
module MyModule
myVar = "abc"
end
class MyClass
include MyModule
puts myVar # outputs "abc"
end
Module Method Visibility
As with Class methods, you can also control Module method visibility. See the section Classes and Methods for more detail.
Adding Modules to a Class
Including Modules
The most common mechanism to add modules in your class or module is to include
it.
module Greetable
def greet
puts "Hello!"
end
end
class Person
include Greetable
end
person = Person.new
person.greet # Output: Hello!
Prepending Modules
The prepend
method is similar to include
, but it places the module’s methods before the class’s own methods in the method lookup chain. This means that methods in the module will override methods in the class if they share the same name.
module Greetable
def greet
puts "Hello from Greetable!"
end
end
class Person
prepend Greetable
def greet
puts "Hello from Person!"
end
end
person = Person.new
person.greet # Output: Hello from Greetable!
Extending Modules
You can also extend
your class with the module methods. The difference between including and extending is that when a module is included, it needs to be called on a class object. When you extend the module into the class, it is a singleton and does not require the instantiation of the object to be used.
module Greetable
def greet
puts "Hello!"
end
end
class Person
extend Greetable
end
Person.greet # Output: Hello!
Introspection
The Module#included
and Module#method_added
hooks in Ruby allow you to define behavior that is triggered when a module is included in a class or when a method is added to a module, respectively.
Included
The included
method is a callback that gets invoked when the module is included in another module or class. This is useful for setting up additional behavior or configuration when a module is included.
module Trackable
def self.included(base)
puts "#{base} has included Trackable"
base.extend(ClassMethods)
end
def track
puts "Tracking instance method"
end
module ClassMethods
def track_all
puts "Tracking class method"
end
end
end
class User
include Trackable
end
user = User.new
user.track # Output: Tracking instance method
User.track_all # Output: Tracking class method
# Output during inclusion: User has included Trackable
Method Added
The method_added
method is a callback that gets invoked whenever a new method is added to the module or class. This can be used for logging, modifying methods, or adding additional functionality dynamically.
module Logger
def self.method_added(method_name)
puts "New method added: #{method_name}"
end
def log(message)
puts "Log: #{message}"
end
end
class Application
extend Logger
def self.start
puts "Starting application"
end
end
# Output: New method added: start
Application.start
# Output: Starting application