Modules as namespaces

Constants in a module

A module is a container for names. A constant written inside it belongs to it, and the rest of the program reaches it with :::

module Shop VERSION = "1" end puts Shop::VERSION

ruby -e 'module Shop; VERSION = "1"; end; puts Shop::VERSION'

1

Without the module, VERSION would sit at the top level and collide with every gem that has the same idea. The module prefix is the file system of a Ruby project: a namespace is a folder, and :: is the slash.

Nested modules

Modules nest, and the inner one is named with the whole path:

module Shop module Payments def self.name "payments" end end end p Shop::Payments.name

ruby -e 'module Shop; module Payments; def self.name = "payments"; end; end; p Shop::Payments.name'

"payments"

The compact form module Shop::Payments works too, but only when Shop already exists: it reopens the constant instead of defining it. The nested form defines both, which is why a file usually writes the nested one.

How :: lookup works

Inside Shop::Payments, a plain constant is looked up in the inner module first, then in the enclosing ones, then at the top level. That is how an inner module reads a constant its parent defines:

ruby -e 'module Shop; X = 1; module Payments; def self.x = X; end; end; p Shop::Payments.x'

1

A leading :: skips the nesting and starts at the top: ::VERSION is the top-level constant even inside a module that has its own. Reaching for the leading form is usually a sign that two constants share a name and one of them should be renamed.

The lookup does not follow the class hierarchy for modules that are included. A constant defined in a mixin is found through the ancestors because the mixin is in them; a constant in a module that is merely required is not.

Namespace or mixin

The same keyword does two jobs. A namespace module holds constants and module methods and is never included; a mixin module holds instance methods and is included into a class. The difference is what the methods are: def self.x belongs to the module, def x belongs to whoever includes it.

module Formatting def money(cents) format("%.2f", cents / 100.0) end end class Invoice include Formatting def total money(1234) end end puts Invoice.new.total

ruby -e 'module Formatting; def money(cents) = format("%.2f", cents / 100.0); end; class Invoice; include Formatting; def total = money(1234); end; puts Invoice.new.total'

12.34

module_function bridges the two: it makes a method callable as Formatting.money and, when the module is included, as a private instance method. It is the right choice for a helper that is useful both ways.

What to watch for

A module name is a constant, so a second definition reopens it rather than replacing it. Two files that both say module Shop add to the same module, which is convenient and also how a typo in the name silently creates a second namespace.

Naming a class with :: in a message is normal: Shop::Payments::Error says exactly where the error lives. Naming it that way inside its own module is not; a file in the folder uses the short name.

Next: Singleton methods and class << self

Article author: Arthur Isaev