Table of contentsClick link to navigate to the desired location
This content has been automatically translated from Ukrainian.
```html
```
In Ruby, modules allow you to organize code, but sometimes you need a method to be accessible both for instances of the module and directly from the module (like a function). This is achieved using module_function.
How module_function works
- Makes the method private for instances of the module (read about private here).
- Adds a "module copy" of the method that can be called without creating an object.
module MathHelper
def square(x)
x * x
end
module_function :square
end
Now you can call the method directly through the module:
MathHelper.square(5) # => 25
Or use it inside other methods of the module (as private):
module MathHelper
def cube(x)
square(x) * x
end
module_function :cube
end
MathHelper.cube(3) # => 27
Features
Private for instances of the module:
include MathHelper square(5) # => NoMethodError (because square became private)
Suitable for utilities
module_function is often used in "static utilities" to avoid creating a module object to call functions.
In short:
- module_function makes the method simultaneously:
- Private for instances (through include)
- Accessible as a function through the module
MathHelper.square(5) # works include MathHelper square(5) # error
This is convenient for modules that have a set of utilities, like in Ruby's standard libraries (Math, Enumerable for example).
But if you pay attention to the point - private for instances (through include), you might ask, what about extend and prepend (wrote about these methods here)?
- The module method becomes private for instances and accessible through the module itself.
- Calling through include does not work directly (the method is private).
- Calling through extend works as a class method.
- Calling through prepend does not work on the object (the method is private).
Still hard to understand? Let's take a closer look:
module_function does two things at once:
-
Private for instances
- If you include the module (include) or do prepend, the method becomes private for all objects, meaning you cannot call it like this: obj.method - there will be an error.
- Ruby does this so you cannot accidentally call this method on an instance.
-
Accessible through the module itself
- Ruby creates a copy of the method at the module level.
- Therefore, you can call: ModuleName.method - this works like a "static function".
A simple example:
module Utils
def greet
"Hello"
end
module_function :greet
end
# Through the module you can
Utils.greet # => "Hello"
# Through include — you cannot, because it's private
include Utils
greet # => NoMethodError
- Why does extend work? extend adds the module methods to the singleton class of the class or object. There, the method is called through the class/object, not through an instance, so it works.
- Why doesn't prepend work? prepend inserts the method into the ancestor chain, but the original method remains private -> the object cannot call it directly.
This post doesn't have any additions from the author yet.