extend and Module Functions
You already know that include mixes a module’s methods into every instance of a class. But sometimes you don’t want every instance to gain new behavior — you want just one specific object to gain it, or you want a module’s methods to behave like utility functions you call directly on the module itself (think Math.sqrt(9)). That’s exactly what extend and module_function are for. Together they let you attach behavior at a much more precise level than include allows: to a single object, to a class itself, or to a module acting as its own namespace.
Overview: How extend and module_function work
Every object in Ruby — and remember, in Ruby everything is an object, including classes themselves — has a hidden, one-off class that sits directly above it in the method lookup chain. This is called the object’s singleton class (sometimes the eigenclass). It exists specifically to hold methods that belong to that one object and no other. When you write obj.extend(SomeModule), Ruby inserts SomeModule into obj‘s singleton class, exactly as if you had written class << obj; include SomeModule; end. The methods become available on obj immediately, but no other instance of obj‘s class is affected at all.
Because classes are themselves objects (instances of Class), this same trick works on a class. class Foo; extend SomeModule; end inserts SomeModule into Foo‘s singleton class — and a class’s singleton class is precisely the chain Ruby searches when you call a method directly on the class, i.e. a "class method". This is why extend is a clean, idiomatic way to add class-level methods from a module, without resorting to the classic self.included hook and a nested ClassMethods module.
module_function solves a different but related problem: building a module that behaves like a self-contained toolbox, callable directly on the module (like Math.sqrt or Math.hypot) rather than mixed into some other class. Called with no arguments inside a module body, module_function changes the behavior of every method defined below it: each one becomes a singleton method on the module itself (so you can call MyModule.some_method) and its original instance-method version is made private. You can also call it with one or more method names (as symbols or strings) to convert specific, already-defined methods instead of "everything from here down".
There is a close cousin worth knowing: extend self, written inside a module body. It achieves a similar practical result — the module’s own methods become callable on the module — but it does so by extending the module with itself, so the methods stay public if they were already public. Many modern Ruby style guides prefer extend self over module_function for exactly this reason: it doesn’t silently make your instance methods private.
Syntax
object.extend(ModuleName)
class SomeClass
extend ModuleName
end
module SomeModule
module_function
def helper
# becomes SomeModule.helper, and a private instance method
end
end
module AnotherModule
extend self
def helper
# becomes AnotherModule.helper, and stays a public instance method
end
end
| Form | What it does |
|---|---|
object.extend(Mod) |
Mixes Mod‘s instance methods into just this one object’s singleton class. |
extend Mod inside a class body |
Mixes Mod‘s instance methods into the class’s singleton class, i.e. adds them as class methods. |
module_function (bare) |
Every method defined afterward becomes callable on the module itself, and is demoted to a private instance method. |
module_function :name |
Converts one already-defined method by name instead of everything below the call. |
extend self |
Alternative to module_function that keeps the methods public if they were already public. |
Examples
Example 1: extend on a single object
module Greetable
def greet
"Hello, I'm #{name}!"
end
end
class Person
attr_reader :name
def initialize(name)
@name = name
end
end
alice = Person.new("Alice")
bob = Person.new("Bob")
alice.extend(Greetable)
puts alice.greet
puts bob.respond_to?(:greet)
Output:
Hello, I'm Alice!
false
alice.extend(Greetable) drops Greetable into alice‘s singleton class only. Calling alice.greet works because Ruby’s method lookup checks the singleton class before Person. bob was never extended, so bob.respond_to?(:greet) is false — Person the class was never touched.
Example 2: extend on a class itself
module Describable
def describe
"This is the #{name} class."
end
end
class Robot
extend Describable
end
puts Robot.describe
Output:
This is the Robot class.
Since Robot is itself an object (an instance of Class), extend Describable inserts Describable into Robot‘s singleton class, making describe behave as a class method. Inside describe, self is Robot, so the bare call name resolves to Robot.name — the built-in Class#name method that returns a class’s name as a string.
Example 3: module_function for a utility module
module TemperatureConverter
module_function
def celsius_to_fahrenheit(celsius)
(celsius * 9.0 / 5) + 32
end
def fahrenheit_to_celsius(fahrenheit)
(fahrenheit - 32) * 5.0 / 9
end
end
puts TemperatureConverter.celsius_to_fahrenheit(100)
puts TemperatureConverter.fahrenheit_to_celsius(32)
Output:
212.0
0.0
module_function with no arguments means both methods defined after it become directly callable on the module (TemperatureConverter.celsius_to_fahrenheit), exactly like Ruby’s own Math module. Under the hood these are the same methods you’d get from def self.celsius_to_fahrenheit, but module_function also keeps a private instance-method copy around in case the module is ever mixed in with include.
How it works step by step
- Ruby gives every object a singleton class that sits just above its regular class in the method lookup chain, and it is normally empty and invisible.
- Calling
obj.extend(Mod)insertsModinto that singleton class’s own ancestor chain, the same wayincludeinserts a module into a class’s ancestor chain. - When you later call
obj.some_method, Ruby searches the singleton class first, findsMod‘s method there, and uses it — before ever looking atobj‘s real class. - Because a class is an object of class
Class, extending a class inserts the module into the class’s singleton class, which is precisely where Ruby looks up methods called directly on the class (its "class methods"). - Inside a module body,
module_function(bare) flips a switch: everydefthat follows is compiled twice conceptually — once as a private instance method, and once as a singleton method on the module, soModule.method_nameworks immediately.
Common Mistakes
Mistake 1: using include when you meant extend
module Sayable
def say_hi
"Hi from #{self}"
end
end
class Widget
include Sayable
end
puts Widget.say_hi
This raises NoMethodError: undefined method 'say_hi' for class Widget. include mixes say_hi in as an instance method, so only a Widget.new instance could call it — the class object Widget itself never gets it. The fix is to use extend instead, which targets the class’s own singleton class:
module Sayable
def say_hi
"Hi from #{self}"
end
end
class Widget
extend Sayable
end
puts Widget.say_hi
Output:
Hi from Widget
Mistake 2: forgetting module_function makes the instance version private
module TemperatureConverter
module_function
def celsius_to_fahrenheit(celsius)
(celsius * 9.0 / 5) + 32
end
end
class Thermometer
include TemperatureConverter
end
t = Thermometer.new
puts t.celsius_to_fahrenheit(0)
This raises NoMethodError: private method 'celsius_to_fahrenheit' called. module_function deliberately made the instance-method copy private, because the module was designed to be used as a namespaced toolbox, not mixed into other classes. The fix is to call it the way it was meant to be called — directly on the module:
module TemperatureConverter
module_function
def celsius_to_fahrenheit(celsius)
(celsius * 9.0 / 5) + 32
end
end
puts TemperatureConverter.celsius_to_fahrenheit(0)
Output:
32.0
If you genuinely want the methods to stay public and mixable, use extend self in the module body instead of module_function — it exposes the methods on the module without demoting the instance versions to private.
Best Practices
- Use
extendwhen only one object, or a class as a whole, needs a module’s behavior — not every instance of that class. - Use
module_functionorextend selffor stateless helper modules meant to be called directly, the wayMathorComparable-style utility modules are used. - Prefer
extend selfover baremodule_functionif you ever want the methods to remain public and mixable elsewhere — it avoids the private-instance-method surprise. - Don’t reach for
class << selfjust to add a handful of class methods from a module — a simpleextendis usually clearer. - Remember only
nilandfalseare falsy in Ruby; checkingrespond_to?after anextendcall is a truthy/falsy check like any other, so0or""returned from a method would still be treated as true.
Practice Exercises
- Write a module
Loggablewith a methodlog(message)that prints"[LOG] <message>". Extend a single hash or array instance with it and calllogon that instance only, then show that a second instance of the same class does not havelog. - Write a module
StringUtilsusingmodule_functionwith a methodshout(text)that returns the text upcased with an exclamation mark appended. Call it directly on the module and confirm calling it as a mixed-in instance method raises aNoMethodError. - Rewrite your
StringUtilsmodule usingextend selfinstead ofmodule_function, mix it into a class withinclude, and show that instances of that class can now callshoutsuccessfully.
Summary
extendmixes a module’s instance methods into a single object’s (or class’s) singleton class, affecting only that one object.- Extending a class inserts the module into the class’s singleton class, which is exactly where Ruby looks up methods called directly on the class — giving you class-level methods.
module_function(bare) makes subsequent methods callable directly on the module and demotes their instance-method versions to private.module_function :nameconverts specific, already-defined methods instead of everything below the call.extend selfachieves a similar toolbox effect tomodule_functionbut keeps the methods public, making it safer if the module might also be mixed in elsewhere.
