Modules is a way to achieve Polymorphism is Ruby. A module is a collection of behaviors that can be included in another class via mixins.
Modules are usefull because Ruby is a single inheritance language: a class can only inherits from one superclass. This limitation makes it difficult to design accurately a problem. Modules let the programmer mix in behaviors to achieve what would be otherwise impossible with a single inheritance. A class can sub-class from only one parent (superclass) but it can mix in as many modules as it likes.
Module cannot be instantiated (no object can be created from a module). They are only used for mixins and namespacing.
Mixins
Mixins comes from “mixed in”: a module is mixed in (mixin) to a class using the include
method invocation.
As Ruby’s class can only inherits from one superclass, one can use module and mixins to group common behaviors to create a more flexible design.
module Speakable
def speak(sound)
puts sound
end
end
class Flamingo
include Speakable
end
johnny = Flamingo.new
johnny.speak('Gwa gwa!') # => Gwa gwa!
See Method Lookup Path for how Ruby lookup methods of module mixed in to a class.
Namespacing
Namespacing means grouping similar classes under a common module. Using namespacing has two advantages:
- Better organize and recognize related classes in our code
- Reduce the likelihood of our custom classes to collide with classes of the same name in the codebase (specially true when using a lot of gems)
module Mammal
class Dog
end
class Cat
end
end
olive = Mammal::Dog.new
felix = Mammal::Cat.new
Classes in a module are called using two colons: ::
.
Container (for methods)
Using modules as a container for methods (called module methods) let us define methods that quite don’t match any class and/or module in our codebase.
module Speakable
# Other methods
def self.out_of_place_method(num)
num**2
end
end
result = Speakable.out_of_place_method(4) # Preferred way to call the method
result = Speakable::out_of_place_method(4)