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.
| Form | What it does |
|---|---|
module Name ... end | Defines a new module named Name, bound to a top-level constant. Reopens if Name already exists |
module Outer::Inner ... end | Defines Inner inside Outer. Requires Outer to already exist |
module Outer; module Inner; end; end | Defines 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.newis the runtime constructor for an anonymous module.module Name; endis 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.newproduces something that inherits fromObjectand is aClass.Module.newproduces something that is aModuleand has nonewmethod, no inheritance chain beyond itself.module M; end; M.is_a?(Class)isfalse;M.is_a?(Module)istrue. Useful inis_a?checks when the API should accept either.Module#newis undefined, soM.newraisesNoMethodError. This is a frequent bug for newcomers porting aclassdefinition to amoduledefinition without changing the call site.- A class can
includea module; a module can alsoincludeanother module. OnlyClass(notModule) 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:
includeadds 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.extendadds a module’s methods as singleton methods on a single object (oftenself).module_functionflips an instance method into a module method, callable asMod.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:
-
moduleis 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::InnerraisesNameErrorifOuteris not already defined. Use the nested form to create both at once. -
Module.nestinginside a::form does not include the outer namespace. Constants defined inOuterare 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; endthenM.newraisesNoMethodError. Modules have nonew. They are not meant to be instantiated; they are meant to be mixed in. -
module M < SomeClass; endis aSyntaxError. Modules cannot have a superclass. Onlyclasstakes<. -
M = 1; module M; endraisesTypeError: M is not a module. The constant already exists and is not a module. -
includeinside 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
- Modules and classes syntax — the canonical Ruby 3.4 reference for
module,class, reopening, and nesting Moduleclass — the runtime Module reference; coversinclude,prepend, andmodule_function- Keywords index — confirms
moduleis a reserved keyword
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
modulebody - is_a? — the inheritance check that returns
truefor any Module