rubyguides

Ruby keyword: module

module Name [:: Nested]

module is the keyword that creates a Module object and binds a constant name to it. Like class, the module ... end form is an expression that returns the resulting Module once the body runs. The official Ruby docs list two uses for it: bundling related constants and methods under a shared name (namespacing), and sharing behavior across multiple classes through include (mix-ins).

The keyword is purely syntactic. The runtime constructor is Module.new; module itself is not a method and cannot be invoked dynamically.

Syntax

Three syntactic shapes, and the difference between them is the part most readers get wrong.

FormWhat it does
module Name ... endDefines a new module named Name, bound to a top-level constant. Reopens if Name already exists
module Outer::Inner ... endDefines Inner inside Outer. Requires Outer to already exist
module Outer; module Inner; end; endDefines both Outer and Inner if either is missing, and puts both into Module.nesting

The two “create inner” forms look interchangeable but are not. module Outer::Inner does not create Outer for you, and it does not put Outer into Module.nesting, which changes constant lookup inside the body. The nested form is verbose but is the only one that puts Outer into the nesting for the inner body.

module Greeter
  def self.hello = "hi"
end

Greeter.hello         # => "hi"
Greeter.is_a?(Module) # => true

Reopening

A second module Name ... end block with the same constant reopens the existing module and merges in any new definitions. This is the same mechanism that powers monkey-patching of String, Array, and Hash:

module Box
  def open?; false; end
end

module Box
  def open?; true; end   # overrides the previous method silently
end

include Box
open?  # => true

The official docs put it plainly: “Reopening modules (or classes) is a very powerful feature of Ruby, but it is best to only reopen modules you own.”

Return value

module ... end returns the Module object created or reopened, identical in shape to how class ... end returns a Class:

m = module Greeter
       def hello = "hi"
     end

m                        # => Greeter
m.instance_methods(false) # => [:hello]
m.new                     # raises NoMethodError: undefined method `new' for Greeter:Module

Two consequences:

  • The keyword form is an expression, not a statement. It can appear on the right-hand side of an assignment.
  • Module.new is the runtime constructor for an anonymous module. module Name; end is a different path: it requires a constant name and runs the body in that constant’s context.

Module vs class

From the official docs: “Every class is also a module, but unlike modules a class may not be mixed-in to another module (or class). Like a module, a class can be used as a namespace. A class also inherits methods and constants from its superclass.”

The practical consequences:

  • Class.new produces something that inherits from Object and is a Class. Module.new produces something that is a Module and has no new method, no inheritance chain beyond itself.
  • module M; end; M.is_a?(Class) is false; M.is_a?(Module) is true. Useful in is_a? checks when the API should accept either.
  • Module#new is undefined, so M.new raises NoMethodError. This is a frequent bug for newcomers porting a class definition to a module definition without changing the call site.
  • A class can include a module; a module can also include another module. Only Class (not Module) can be inherited via <.

Nesting and constant lookup

Module.nesting returns the chain of enclosing modules and classes at the point of call, not the absolute path of the current constant. The :: form does not add the outer module to nesting:

module A
  Z = 1
  module B
    p Module.nesting   # => [A::B, A]
    p Z                # => 1
  end
end

module A::B
  p Module.nesting     # => [A::B]
  p Z                  # NameError: uninitialized constant A::B::Z
end

Top-level constants are reachable from inside any nesting by prefixing :: to skip the local lookup. The leading :: forces the lookup to start at the top-level namespace rather than the enclosing module, so even a local constant that shadows the top-level one becomes invisible to that expression. This is the only reliable way to reach a built-in name from inside a deep namespace without renaming the inner constant.

Z = 0
module A
  Z = 1
  module B
    p ::Z   # => 0  (the top-level one, not A::Z)
  end
end

This is one of the more common sources of “why is my constant nil?” bugs.

Mixin mechanics

module is the keyword that produces the things include, prepend, and extend operate on. The short version:

  • include adds the module’s instance methods to the class’s ancestors, after the class itself.
  • prepend (Ruby 2.0+) inserts the module before the class in the chain, so the module’s methods win over the class’s own methods in method lookup.
  • extend adds a module’s methods as singleton methods on a single object (often self).
  • module_function flips an instance method into a module method, callable as Mod.method_name, and keeps a private copy for instances.
module Fly
  def fly
    "I'm flying!"
  end
end

class Bird
  include Fly
end

class Plane
  include Fly
end

Bird.new.fly   # => "I'm flying!"
Plane.new.fly  # => "I'm flying!"

Common gotchas

A handful of behaviors that show up in bug reports:

  • module is a reserved keyword. You cannot use it as a variable name (module = 1), as a method name (def module; end), or invoke it dynamically (send(:module, ...) is meaningless because there is no method to call).

  • module Outer::Inner raises NameError if Outer is not already defined. Use the nested form to create both at once.

  • Module.nesting inside a :: form does not include the outer namespace. Constants defined in Outer are not visible unqualified inside the body.

  • Reopening a class as a module, or a module as a class, raises TypeError. The kind is fixed at first definition.

    module M; end
    class M; end
    # TypeError: M is not a class
  • module M; end then M.new raises NoMethodError. Modules have no new. They are not meant to be instantiated; they are meant to be mixed in.

  • module M < SomeClass; end is a SyntaxError. Modules cannot have a superclass. Only class takes <.

  • M = 1; module M; end raises TypeError: M is not a module. The constant already exists and is not a module.

  • include inside a module body adds the included module to that module’s own ancestors, not to any class that later includes the outer module.

External documentation

See also

  • class keyword — closest sibling; explains how every class is a module and what modules cannot do that classes can
  • def keyword — defines the methods that go inside a module body
  • is_a? — the inheritance check that returns true for any Module