2 min read

module functions in Ruby

Syed Aslam

In Ruby, Modules are a way of grouping together methods, classes, and constants giving you two major benefits:

  • provide namespacing and thus help prevent name collisions
  • implement the mixin facility, providing a controlled way of adding functionality to classes

A module can also be used as a logical entity, containing non-state changing methods ("functions") that may be called, not only from the instance level but also from class level, with the module itself as the receiver and not having to prepend the module every time you want to use the functions.

# class level
MyModule.some_method

# instance level
include MyModule
some_method

There are multiple techniques to achieve this in Ruby, but the simplest and best known are Module#module_function and extend self.

module_function

module_function creates module functions.

You can achieve this by:

module MyModule
  def some_method
    puts "MyModule#some_method"
  end

  module_function :some_method
end

This is very similar to writing:

module MyModule
  def self.some_method
    "MyModule#some_method"
  end

  private

  def some_method
    "MyModule#some_method"
  end
end

This could also be written as the following if you want all the subsequently defined methods to become module functions:

module MyModule
  module_function

  def some_method
    "MyModule#some_method"
  end
end

The instance methods are made private:

MyModule.instance_method(:some_method).owner #=> MyModule
MyModule.public_method_defined?(:some_method) #=> false
MyModule.private_method_defined?(:some_method) #=> true

MyModule.method(:some_method).owner #=> #<Class:MyModule>
MyModule.method(:some_method).owner.singleton_class? #=> true

These functions are copies of the original, and so maybe changed independently:

class MyClass
  include MyModule

  def call_some_method
    some_method
  end
end

MyModule.some_method #=> "MyModule#some_method"

klass = MyClass.new
klass.call_some_method #=> "MyModule#some_method"

module MyModule
  def some_method
    "Overridden MyModule#some_method"
  end
end

MyModule.some_method #=> "MyModule#some_method"
klass.call_some_method #=> "Overridden MyModule#some_method"

The advantage of module_function is that when the module gets included in a class, these functions do not become public methods of the class and do not extend the class's public API, eliminating the need to maintain these methods for backward compatibility.

extend self

Another way to get something very similar is by extend self. By extending self within the module, all instance methods defined within the module will now be available at the module level and can also be called MyModule.some_method.

module MyModule
  extend self

  def some_method
    "MyModule#some_method"
  end
end

Using extend, the module will add its instance methods to its inheritance chain.

MyModule.instance_method(:some_method).owner #=> MyModule
MyModule.public_method_defined?(:some_method) #=> true

MyModule.method(:some_method).owner #=> MyModule
MyModule.method(:some_method).owner.singleton_class? #=> false

conclusion

module_function makes the given instance methods private, then duplicates and puts them into the module's metaclass as public methods.

  • creating copies of the original methods and they may be managed independently
  • making the module instance methods visibility as private

On the other hand, extend self adds all instance methods to the module's singleton, leaving their visibilities unchanged.

  • there is no method copies made, if you want to modify a method's behavior you only need to do this in one place
  • no side effects, like changing the method's visibility