Ruby Cookbook: Modules and Namespaces

Explore Modules and Namespaces in Ruby with these recipes from the Ruby Cookbook.

By Lucas Carlson and Leonard Richardson
August 26, 2015
Details from inside the former GM engine block manufacturing plant Details from inside the former GM engine block manufacturing plant (source: University of Michigan School for Environment and Sustainability)

Modules and Namespaces

A Ruby module is nothing more than a grouping of objects under a single name. The objects may be constants, methods, classes, or other modules.

Modules have two uses. You can use a module as a convenient way to bundle objects together, or you can incorporate its contents into a class with Ruby’s include statement.

Learn faster. Dig deeper. See farther.

Join the O'Reilly online learning platform. Get a free trial today and find answers on the fly, or master something new and useful.

Learn more

When a module is used as a container for objects, it’s called a namespace. Ruby’s Math module is a good example of a namespace: it provides an overarching structure for constants like Math::PI and methods like Math::log, which would otherwise clutter up the main Kernel namespace. We cover this most basic use of modules in Recipes 10.5 and 10.7.

Modules are also used to package functionality for inclusion in classes. The Enumerable module isn’t supposed to be used on its own: it adds functionality to a class like Array or Hash. We cover the use of modules as packaged functionality for existing classes in Recipes 10.1 and 10.4.

Module is actually the superclass of Class, so every Ruby class is also a module. Throughout this book we talk about using methods of Module from within classes. The same methods will work exactly the same way within modules. The only thing you can’t do with a module is instantiate an object from it:

Class.superclass    # => Module
Math.class          # => Module
Math.new
# NoMethodError: undefined method `new' for Math:Module

Simulating Multiple Inheritance with Mixins

Problem

You want to create a class that derives from two or more sources, but Ruby doesn’t support multiple inheritance.

Solution

Suppose you created a class called Taggable that lets you associate tags (short strings of informative metadata) with objects. Every class whose objects should be taggable could derive from Taggable.

This would work if you made Taggable the top-level class in your class structure, but that won’t work in every situation. Eventually you might want to do something like make a string taggable. One class can’t subclass both Taggable and String, so you’d have a problem.

Furthermore, it makes little sense to instantiate and use a Taggable object by itself—there is nothing there to tag! Taggability is more of a feature of a class than a fullfledged class of its own. The Taggable functionality works only in conjunction with some other data structure.

This makes Taggable an ideal candidate for implementation as a Ruby module instead of a class. Once it’s in a module, any class can include it and use the methods it defines:

require 'set' # Deals with a collection of unordered values with no duplicates

# Include this module to make your class taggable. The names of the
# instance variable and the setup method are prefixed with "taggable_"
# to reduce the risk of namespace collision. You must call
# taggable_setup before you can use any of this module's methods.
module Taggable
  attr_accessor :tags

  def taggable_setup
    @tags = Set.new
  end

  def add_tag(tag)
    @tags << tag
  end

  def remove_tag(tag)
    @tags.delete(tag)
  end
end

Here is a taggable string class; it subclasses String, but it also includes the functionality of Taggable:

class TaggableString < String
  include Taggable
  def initialize(*args)
    super
    taggable_setup
  end
end
s = TaggableString.new('It was the best of times, it was the worst of times.')
s.add_tag 'dickens'
s.add_tag 'quotation'
s.tags # =>                       #<Set: {"dickens", "quotation"}>

Discussion

A Ruby class can have only one superclass, but it can include any number of modules. These modules are called mixins. If you write a chunk of code that can add functionality to classes in general, it should go into a mixin module instead of a class.

The only objects that need to be defined as classes are the ones that get instantiated and used on their own (modules can’t be instantiated).

If you’re coming from Java, you might think of a module as being the combination of an interface and its implementation. By including a module, your class implements certain methods, and announces that since it implements those methods it can be treated a certain way.

When a class includes a module with the include keyword, all of the module’s methods and constants are made available from within that class. They’re not copied, as a method is when you alias it. Rather, the class becomes aware of the methods of the module. If a module’s methods are changed later (even during runtime), so are the methods of all the classes that include that module.

Module and class definitions have an almost identical syntax. If you find out after implementing a class that you should have done it as a module, it’s not difficult to translate the class into a module. The main problem areas will be methods defined both by your module and the classes that include it, especially methods like initialize.

Your module can define an initialize method, and it will be called by a class whose constructor includes a super call (see Initializing Instance Variables Defined by a Module for an example), but sometimes that doesn’t work. For instance, Taggable defines a taggable_setup method that takes no arguments. The String class, the superclass of TaggableString, takes one and only one argument. TaggableString can call super within its constructor to trigger both String#initialize and a hypothetical Taggable#initialize, but there’s no way a single super call can pass one argument to one method and zero arguments to another.

That’s why Taggable doesn’t define an initialize method.1 Instead, it defines a taggable_setup method and (in the module documentation) asks everyone who includes the module to call taggable_setup within their initialize method. Your module can define a <module name>setup method instead of initialize, but you need to document it, or your users will be very confused.

It’s okay to expect that any class that includes your module will implement some methods you can’t implement yourself. For instance, all of the methods in the Enumerable module are defined in terms of a method called each, but Enumerable never actually defines each. Every class that includes Enumerable must define what each means within that class before it can use the Enumerable methods.

If you have such undefined methods, it will cut down on confusion if you provide a default implementation that raises a helpful exception:

module Complaint
  def gripe
    voice('In all my years I have never encountered such behavior…')
  end

  def faint_praise
    voice('I am pleased to notice some improvement, however slight…')
  end

  def voice(complaint_text)
    raise NotImplementedError,
    "#{self.class} included the Complaint module but didn't define voice!"
  end
end

class MyComplaint
  include Complaint
end

MyComplaint.new.gripe
# NotImplementedError: MyComplaint included the Complaint module
# but didn't define voice!

If two modules define methods with the same name, and a single class includes both modules, the class will have only one implementation of that method: the one from the module that was included last. The method of the same name from the other module will simply not be available. Here are two modules that define the same method:

module Ayto
  def potato
     'Pohtayto'
  end
end

module Ahto
  def potato
     'Pohtahto'
  end
end

One class can mix in both modules:

class Potato
  include Ayto
  include Ahto
end

But there can be only one potato method for a given class or module:2

Potato.new.potato                             # => "Pohtahto"

This rule sidesteps the fundamental problem of multiple inheritance by letting programmers explicitly choose which ancestor they would like to inherit a particular method from. Nevertheless, it’s good programming practice to give distinctive names to the methods in your modules. This reduces the risk of namespace collisions when a class mixes in more than one module. Collisions can occur, and the later module’s method will take precedence, even if one or both methods are protected or private.

See Also

Extending Specific Objects with Modules

Credit: Phil Tomson

Problem

You want to add instance methods from a module (or modules) to specific objects. You don’t want to mix the module into the object’s class, because you want certain objects to have special abilities.

Solution

Use the Object#extend method.

For example, let’s say we have a mild-mannered Person class:

class Person
  attr_reader :name, :age, :occupation

  def initialize(name, age, occupation)
    @name, @age, @occupation = name, age, occupation
  end

  def mild_mannered?
    true
  end
end

Now let’s create a couple of instances of this class:

jimmy = Person.new('Jimmy Olsen', 21, 'cub reporter')
clark = Person.new('Clark Kent', 35, 'reporter')
jimmy.mild_mannered?                        # => true
clark.mild_mannered?                        # => true

But it happens that some Person objects are not as mild-mannered as they might appear. Some of them have superpowers:

module SuperPowers
  def fly
    'Flying!'
  end

  def leap(what)
     "Leaping #{what} in a single bound!"
  end

  def mild_mannered?
     false
  end

  def superhero_name
    'Superman'
  end
end

If we use include to mix the SuperPowers module into the Person class, it will give every person superpowers. Some people are bound to misuse such power. Instead, we’ll use extend to give superpowers only to certain people:

clark.extend(SuperPowers)
clark.superhero_name                   # => "Superman"
clark.fly                              # => "Flying!"
clark.mild_mannered?                   # => false
jimmy.mild_mannered?                   # => true

Discussion

The extend method is used to mix a module’s methods into an object, while include is used to mix a module’s methods into a class.

The astute reader might point out that classes are actually objects in Ruby. Let’s see what happens when we use extend in a class definition:

class Person
  extend SuperPowers
end

#which is equivalent to:
Person.extend(SuperPowers)

What exactly are we extending here? Within the class definition, extend is being called on the Person class itself; we could have also written self.extend(SuperPowers). We’re extending the Person class with the methods defined in SuperPowers. This means that the methods defined in the SuperPowers module have now become class methods of Person:

Person.superhero_name                        # => "Superman"
Person.fly                                   # => "Flying!"

This is not what we intended in this case. However, sometimes you do want to mix methods into a class, and Class#extend is an easy and powerful way to do it.

See Also

Mixing in Class Methods

Credit: Phil Tomson

Problem

You want to mix class methods into a class, instead of mixing in instance methods.

Solution

The simplest way to accomplish this is to call extend on the class object, as seen in the Discussion of Extending Specific Objects with Modules. Just as you can use extend to add singleton methods to an object, you can use it to add class methods to a class. But that’s not always the best option. Your users may not know that your module provides or even requires some class methods, so they might not extend their class when they should. How can you make an include statement mix in class methods as well?

To begin, within your module define a submodule called ClassMethods, which contains the methods you want to mix into the class:3

module MyLib
  module ClassMethods
    def class_method
      puts "This method was first defined in MyLib::ClassMethods"
    end
  end
end

To make this code work, we must also define the included callback method within the MyLib module. This method is called every time a module is included in the class, and it’s passed the class object in which our module is being included. Within the callback method, we extend that class object with our ClassMethods module, making all of its instance methods into class methods. Continuing the example:

module MyLib
  def self.included(receiver)
    puts "MyLib is being included in #{receiver}!"
    receiver.extend(ClassMethods)
  end
end

Now we can include our MyLib module in a class, and get the contents of ClassMethods mixed in as genuine class methods:

class MyClass
  include MyLib
end
# MyLib is being included in MyClass!

MyClass.class_method
# This method was first defined in MyLib::ClassMethods

Discussion

Module#included is a callback method that is automatically called during the inclusion of a module into a class. The default included implementation is an empty method. In the example, MyLib overrides it to extend the class that’s including the MyLib module with the contents of the MyLib::ClassMethods submodule.

The Object#extend method takes a Module object as a parameter. It mixes all the methods defined in the module into the receiving object. Since classes are themselves objects, and the singleton methods of a Class object are just its class methods, calling extend on a class object fills it up with new class methods.

See Also

Implementing Enumerable: Write One Method, Get 48 Free

Problem

You want to give a class all the useful iterator and iteration-related features of Ruby’s arrays (sort, detect, inject, and so on), but your class can’t be a subclass of Array. You don’t want to define all those methods yourself.

Solution

Implement an each method, then include the Enumerable module. It defines 22 of the most useful iteration methods in terms of the each implementation you provide.

Here’s a class that keeps multiple arrays under the covers. By defining each, it can expose a large interface that lets the user treat it like a single array:

class MultiArray
  include Enumerable

  def initialize(*arrays)
    @arrays = arrays
  end

  def each
    @arrays.each { |a| a.each { |x| yield x } }
  end
end

ma = MultiArray.new([1, 2], [3], [4])
ma.collect # => #<Enumerator:
                        #<MultiArray:0x007fbe0312d720
                            @arrays=[[1, 2], [3], [4]]>:collect>
ma.detect { |x| x > 3 }            # => 4
ma.map { |x| x ** 2 }              # => [1, 4, 9, 16]
ma.each_with_index { |x, i| puts "Element #{i} is #{x}" }
# Element 0 is 1
# Element 1 is 2
# Element 2 is 3
# Element 3 is 4

Discussion

Enumerable is the most common mixin module. It lets you add a lot of behavior to your class for a little investment. Since Ruby relies so heavily on iterator methods, and almost every data structure can be iterated over in some way, it’s no wonder that so many of the classes in Ruby’s standard library include Enumerable: Dir, Hash, Range, and String, just to name a few.

Here’s the complete list of methods you can get by including Enumerable. Many of them are described elsewhere in this book, especially in resource not available. Perhaps the most useful are collect, inject, find_all, and sort_by:

Enumerable.instance_methods.sort
        # => [:all?, :any?, :chunk, :collect, :collect_concat,
              :count, :cycle, :detect, :drop, :drop_while,
              :each_cons, :each_entry, :each_slice,
              :each_with_index, :each_with_object, :entries,
              :find, :find_all, :find_index, :first, :flat_map,
              :grep, :group_by, :include?, :inject, :lazy,
              :map, :max, :max_by, :member?, :min, :min_by,
              :minmax, :minmax_by, :none?, :one?, :partition,
              :reduce, :reject, :reverse_each, :select,
              :slice_before, :sort, :sort_by, :take,
              :take_while, :to_a, :zip]

Although you can get all these methods simply by implementing an each method, some of the methods won’t work unless your each implementation returns objects that can be compared to each other. For example, a data structure that contains both numbers and strings can’t be sorted, since it makes no sense to compare a number to a string:

ma.sort                                   # => [1, 2, 3, 4]
mixed_type_ma = MultiArray.new([1, 2, 3], ["a", "b", "c"])
mixed_type_ma.sort
# ArgumentError: comparison of Fixnum with String failed

The methods subject to this restriction are max, min, sort, and sort_by. Since you probably don’t have complete control over the types of the data stored in your data structure, the best strategy is probably to just let a method fail if the data is incompatible. This is what Array does:

[1, 2, 3, "a", "b", "c"].sort
# ArgumentError: comparison of Fixnum with String failed

One more example: in this one, we’ll make Module itself include Enumerable. Our each implementation will iterate over the instance methods defined by a class or module. This makes it easy to find methods of a class that meet certain criteria:

class Module
  include Enumerable
  def each
    instance_methods.each { |x| yield x }
  end
end

# Find all instance methods of String that modify the string in place.
    	String.find_all { |method_name| method_name[-1] == ?! }
# => [:succ!, :next!, :upcase!, :downcase!, :capitalize!,
          :swapcase!, :reverse!, :sub!, :gsub!, :chop!,
          :chomp!, :strip!, :lstrip!, :rstrip!, :tr!, :tr_s!,
          :delete!, :squeeze!, :slice!, :encode!, :!]

# Find all instance methods of Fixnum that take 2 arguments.
sample = 0
sample.class.find_all { |method_name| sample.method(method_name).arity == 2 }
# => [:between?, :instance_variable_set]

See Also

Avoiding Naming Collisions with Namespaces

Problem

You want to define a class or module whose name conflicts with an existing class or module, or you want to prevent someone else from coming along later and defining a class whose name conflicts with yours.

Solution

A Ruby module can contain classes and other modules, which means you can use it as a namespace.

Here’s some code from a physics library that defines a class called String within the StringTheory module. The real name of this class is its fully qualified name: StringTheory::String. It’s a totally different class from Ruby’s built-in String class:

module StringTheory
  class String
    def initialize(length=10**-33)
      @length = length
    end
  end
end

String.new      # => ""

StringTheory::String.new
#<StringTheory::String:0x007fbe0186a120
        @length=(1/1000000000000000000000000000000000)>

Discussion

If you’ve read resource not available, you have already seen namespaces in action. The constants defined in a module are qualified with the module’s name. This lets Math::PI have a different value from Greek::PI.

You can qualify the name of any Ruby object this way: a variable, a class, or even another module. Namespaces let you organize your libraries, and make it possible for them to coexist alongside others.

Ruby’s standard library uses namespaces heavily as an organizing principle. An excellent example is REXML, the standard XML library. It defines a REXML namespace that includes lots of XML-related classes like REXML::Comment and REXML::Instruction. Naming those classes Comment and Instruction would be a disaster: they’d get overwritten by other libraries’ Comment and Instruction classes. Since nothing about these generic-sounding names relates them to the REXML library, you might look at someone else’s code for a long time before realizing that the Comment objects have to do with XML.

Namespaces can be nested: see, for instance, rexml‘s REXML::Parsers module, which contains classes like REXML::Parsers::StreamParser. Namespaces group similar classes in one place so you can find what you’re looking for; nested namespaces do the same for namespaces.

In Ruby, you should name your top-level module after your software project (SAX), or after the task it performs (XML::Parser). If you’re writing yet another implementation of something that already exists, you should make sure your namespace includes your project name (XML::Parser::SAX). This is in contrast to Java’s namespaces: they exist in its package structure, which follows a naming convention that includes a domain name, like org.xml.sax.

All code within a module is implicitly qualified with the name of the module. This can cause problems for a module like StringTheory, if it needs to use Ruby’s built-in String class for something. This is fixed in Ruby 2.1, but you can also fix it by setting the built-in String class to a variable before defining your StringTheory::String class. Here’s a version of the StringTheory module that can use Ruby’s built-in String class:

module StringTheory2
 RubyString = String
 class String
   def initialize(length=10**-33)
     @length = length
   end
  end

  RubyString.new("This is a built-in string, not a StringTheory2::String")
end
# => "This is a built-in string, not a StringTheory2::String"

See Also

Automatically Loading Libraries as Needed

Problem

You’ve written a big library with multiple components. You’d like to split it up so that users don’t have to load the entire library into memory just to use part of it. But you don’t want to make your users explicitly require each part of the library they plan to use.

Solution

Split the big library into multiple files, and set up autoloading for the individual files by calling Kernel#autoload. The individual files will be loaded as they’re referenced.

Warning

Deprecation Warning

Matz has indicated that autoload has fundamental flaws under multithreaded environments, which means that although autoload is included in Ruby 2.1, it will not be included in future versions of Ruby like 3.0.

Using autoload in any standard libraries is strongly discouraged.

Suppose you have a library, functions.rb, that provides two very large modules:

# functions.rb
module Decidable
  # … Many, many methods go here.
end

module Semidecidable
  # … Many, many methods go here.
end

You can provide the same interface, but possibly save your users some memory, by splitting functions.rb into three files. The functions.rb file itself becomes a stub full of autoload calls:

# functions.rb
autoload :Decidable, "decidable.rb"
autoload :Semidecidable, "semidecidable.rb"

The modules themselves go into the files mentioned in the new functions.rb:

# decidable.rb
module Decidable
  # … Many, many methods go here.
end
# semidecidable.rb
module Semidecidable
  # … Many, many methods go here.
end

The following code will work if all the modules are in functions.rb, but it will also work if functions.rb contains only calls to autoload:

require 'functions'
Decidable.class                                           # => Module
# More use of the Decidable module follows…

When Decidable and Semidecidable have been split into autoloaded modules, that code loads only the Decidable module. Memory is saved that would otherwise be used to contain the unused Semidecidable module.

Discussion

Refactoring a library to consist of autoloadable components takes a little extra planning, but it’s often worth it to improve performance for the people who use your library.

Each call to Kernel#autoload binds a symbol to the path of the Ruby file that’s supposed to define that symbol. If the symbol is referenced, that file is loaded exactly as though it had been passed as an argument into require. If the symbol is never referenced, the user saves some memory.

Since you can use autoload wherever you might use require, you can autoload built-in libraries when the user triggers some code that needs them. For instance, here’s some code that loads Ruby’s built-in set library as needed:

autoload :Set, "set.rb"

def random_set(size)
  max = size * 10
  set = Set.new
  set << rand(max) until set.size == size
  return set
end

# More code goes here…

If random_set is never called, the set library will never be loaded, and memory will be saved. As soon as random_set gets called, the set library is autoloaded, and the code works even though we never explicitly require
set
:

random_set(10)
# => #<Set: {39, 83, 73, 40, 90, 25, 91, 31, 76, 54}>

require 'set'                                       # => false

Including Namespaces

Problem

You want to use the objects within a module without constantly qualifying the object names with the name of their module.

Solution

Use include to copy a module’s objects into the current namespace. You can then use them from the current namespace, without qualifying their names.

Instead of this:

require 'rexml/document'

xml = "<hello>world</hello>"
REXML::Document.new(xml)

you might write this:

require 'rexml/document'
include REXML

xml = "<hello>world</hello>"
Document.new(xml)

Discussion

This is the exact same include statement you use to incorporate a mixin module into a class you’re writing. It does the same thing here as when it includes a mixin: it copies the contents of a module into the current namespace.

Here, though, the point isn’t to add new functionality to a class or module: it’s to save you from having to do so much typing. This technique is especially useful with large library modules like Curses and the Rails libraries.

This use of include comes with the same caveats as any other: if you already have variables with the same names as the objects being included, the included objects will be copied in over them and clobber them.

You can, of course, import a namespace that’s nested within a namespace of its own. Instead of this:

require 'rexml/parsers/pullparser'

REXML::Parsers::PullParser.new("<hello>world</hello>")

you might write this:

require 'rexml/parsers/pullparser'
include REXML::Parsers

PullParser.new("<hello>world</hello>")

See Also

Initializing Instance Variables Defined by a Module

Credit: Phil Tomson

Problem

You have a mixin module that defines some instance variables. Given a class that mixes in the module, you want to initialize the instance variables whenever an instance of the class is created.

Solution

Define an initialize method in the module, and call super in your class’s constructor. Here’s a Timeable module that tracks when objects are created and how old they are:

module Timeable
 attr_reader :time_created

 def initialize
   @time_created = Time.now
 end

 def age #in seconds
   Time.now - @time_created
 end
end

Timeable has an instance variable time_created, and an initialize method that assigns Time.now (the current time) to the instance variable. Now let’s mix Timeable into another class that also defines an initialize method:

class Character
  include Timeable
  attr_reader :name
  def initialize(name)
    @name = name
    super() #calls Timeable's initialize
  end
end
c = Character.new "Fred"

c.time_created
# => 2013-12-09 13:36:46 -0800

Discussion

You can define and access instance variables within a module’s instance methods, but you can’t actually instantiate a module. A module’s instance variables exist only within objects of a class that includes the module. However, classes don’t usually need to know about the instance variables defined by the modules they include. That sort of information should be initialized and maintained by the module itself.

The Character#initialize method overrides the Timeable#initialize method, but you can use super to call the Timeable constructor from within the Character constructor. When a module is included in a class, that module becomes an ancestor of the class. We can test this in the context of the preceding example by calling the Module#ancestors on the Character class:

Character.ancestors     # => [Character, Timeable, Object, Kernel, BasicObject

When you call super from within a method (such as initialize), Ruby finds every ancestor that defines a method with the same name, and calls it too.

See Also

Automatically Initializing Mixed-in Modules

Credit: Phil Tomson

Problem

You’ve written a module that gets mixed into classes. Your module has some initialization code that needs to run whenever the mixed-into class is initialized. You do not want users of your module to have to call super in their initialize methods.

Solution

First, we need a way for classes to keep track of which modules they’ve included. We also need to redefine Class#new to call a module-level initialize method for each included module. Fortunately, Ruby’s flexibility lets us makes changes to the built-in Class class (though this should never be done lightly):

class Class
  def included_modules
    @included_modules ||= []
  end

  alias_method :old_new, :new
  def new(*args, &block)
    obj = old_new(*args, &block)
    self.included_modules.each do |mod|
      mod.initialize if mod.respond_to?(:initialize)
    end
    obj
  end
end

Now every class has a list of included modules, accessible from the included_modules class method. We’ve also redefined the Class#new method so that it iterates through all the modules in included_modules, and calls the module-level initialize method of each.

All that’s missing is a way to add included modules to included_modules. We’ll put this code into an Initializable module. A module that wants to be initializable can mix this module into itself and define an initialize method:

module Initializable

  def self.included(mod)
    mod.extend ClassMethods
  end

  module ClassMethods
    def included(mod)
      if mod.class != Module #in case Initializeable is mixed-into a class
        puts "Adding #{self} to #{mod}'s included_modules" if $DEBUG
        mod.included_modules << self
      end
    end
  end
end

The included callback method is called whenever this module is included in another module. We’re using the pattern shown in Mixing in Class Methods to add an included callback method into the receiving module. If we didn’t do this, you’d have to use that pattern yourself for every module you wanted to be Initializable.

Discussion

That’s a lot of code, but here’s the payoff. Let’s define a couple of modules that include Initializeable and define initialize module methods:

module A
  include Initializable
  def self.initialize
    puts "A's initialized."
  end
end

module B
  include Initializable
  def self.initialize
    puts "B's initialized."
  end
end

We can now define a class that mixes in both modules. Instantiating the class instantiates the modules, with not a single super call in sight:

class BothAAndB
  include A
  include B
end

both = BothAAndB.new
# A's initialized.
# B's initialized.

The goal of this recipe is very similar to Initializing Instance Variables Defined by a Module. In that recipe, you call super in a class’s initialize method to call a mixed-in module’s initialize method. That recipe is a lot simpler than this one and doesn’t require any changes to built-in classes, so it’s often preferable.

Consider a case like the preceding BothAAndB class. Using the techniques from Initializing Instance Variables Defined by a Module, you’d need to make sure that both A and B had calls to super in their initialize methods, so that each module would get initialized. This solution moves all of that work into the Initializable module and the built-in Class class. The other drawback of the previous technique is that users of your module need to know to call super somewhere in their initialize method. Here, everything happens automatically.

This technique is not without its pitfalls. Anytime you redefine critical built-in methods like Class#new, you need to be careful: someone else may have already redefined it elsewhere in your program. Also, you won’t be able to define your own included method callback in a module that includes Initializeable; doing so will override the callback defined by Initializable itself.

See Also

Prepending Modules

Problem

You need to override class methods when including module methods.

Solution

Instead of using the include method, use the prepend method:

module OverrideModuleMethods
    def override
        "module method"
    end
end

class MyClass
    prepend OverrideModuleMethods

    def override
        "class method"
    end
end

MyClass.new.override # => "module method"

Discussion

When you include a module into a class, the class’s method dispatch search finds the class’s defined methods first and then the module’s methods. For example:

module IncludeModuleMethods
    def which_gets_called?
        "module method"
    end
end

class MyClass
    include IncludeModuleMethods

    def which_gets_called?
        "class method"
    end
end

MyClass.new.which_gets_called? # => "class method"

The class method is called because of the ancestor chain:

MyClass.ancestors
      # => [MyClass, IncludeModuleMethods, Object, Kernel, BasicObject]

When the MyClass#which_gets_called? method is called, the method dispatch searches the anscestor chain, looking for method names that match the called method. When we use the prepend method, it prepends the module namespace in the list of ancestors:

module OverrideModuleMethods
    def override
        "module method"
    end
end

class MyClass
    prepend OverrideModuleMethods
end

MyClass.ancestors
      # => [OverrideModuleMethods, MyClass, Object, Kernel, BasicObject]

This allows you to overwrite methods cleanly.

1An alternative is to define Taggable#initialize to take a variable number of arguments, and then just ignore all the arguments. This only works because Taggable can initialize itself without any outside information.

2You could get both methods by aliasing Potato#potato to another method after mixing in Ayto but before mixing in Ahto. There would still be only one Potato#potato method, and it would still be Ahto#potato, but the implementation of Ayto#potato would survive under a different name.

3The name ClassMethods has no special meaning within Ruby; technically, you can call your submodule whatever you want. But the Ruby community has standardized on ClassMethods as the name of this submodule, and it’s used in many Ruby libraries, so you should use it too.

Post topics: Software Engineering
Share:

Get the O’Reilly Radar Trends to Watch newsletter