All original content is created in Ukrainian. Not all content has been translated yet. Some posts may only be available in Ukrainian.Learn more

module_function in Ruby: when module methods are available as module methods and as functions

Post cover: module_function in Ruby: when module methods are available as module methods and as functions
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:
  1. 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.
  2. 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.

28 Oct 14:42

How &:to_s works in Ruby and what Symbol#to_proc is

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
What are Proc and Lambda in Ruby?
28 Oct 15:57

What are Proc and Lambda in Ruby?

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
What happens if you call [1, 2, 3].map(&Person)
29 Oct 17:54

What happens if you call [1, 2, 3].map(&Person)

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Singleton class (eigenclass) in Ruby: what it is and why it is needed
29 Oct 18:29

Singleton class (eigenclass) in Ruby: what it is and why it is needed

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
==, equal?, eql?, === in Ruby: what they check and when to use them
29 Oct 20:47

==, equal?, eql?, === in Ruby: what they check and when to use them

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Include, Extend, Prepend in Ruby: how they work and what the difference is
29 Oct 21:20

Include, Extend, Prepend in Ruby: how they work and what the difference is

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
What is memoization in Ruby?
30 Oct 10:17

What is memoization in Ruby?

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
is_a?, kind_of?, instance_of? — how does Ruby check the type of an object?
30 Oct 19:55

is_a?, kind_of?, instance_of? — how does Ruby check the type of an object?

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
&& vs and — the difference in Ruby that can break your code
30 Oct 20:23

&& vs and — the difference in Ruby that can break your code

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Variables in Ruby: @, @@ and class instance variable
30 Oct 20:54

Variables in Ruby: @, @@ and class instance variable

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
The difference between blank?, present?, empty? and nil? in Ruby
30 Oct 21:06

The difference between blank?, present?, empty? and nil? in Ruby

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
What is Middleware in Ruby on Rails and when is it used
04 Nov 10:39

What is Middleware in Ruby on Rails and when is it used

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska