The Class
and Module
constructs are cornerstones of the Ruby language,
yet the basic principles of each are often overlooked resulting in incorrect
usage.
In object-oriented programming, a class is an extensible program-code-template
for creating objects, providing initial values for state (member variables)
and implementations of behaviour (member functions or methods).
In short, classes are designed to create objects. The Class
provides a
template or cookie cutter for creating instances of itself.
As a rule of thumb, if you create a
Class
and it has no instance methods,
you shouldn't be using aClass
To illustrate, here is a common example of where people go astray:
Class TaxCalculator
def self.calculate(amount)
amount * 1.2
end
end
The above Class
does not manage state and it does not have instance methods
for the objects it creates. The calculate
function would be better suited in a
Module
.
In computer science, functional programming is a programming paradigm — a style
of building the structure and elements of computer programs — that treats
computation as the evaluation of mathematical functions and avoids
changing-state and mutable data.In functional code, the output value of a function depends only on the
arguments that are input to the function
If you find yourself looking to create a function, which is not specific to an
object, you are best to use a Module
.
Module TaxCalculator
def calculate(amount)
amount * 1.2
end
end
Without a bit of extra magic or mixing this module into a Class
you can't
access calculate
directly e.g. TaxCalculator.calculate
. Here are two common
ways to make that a reality:
Yes, that's right, Ruby has a method module_function, which will allow you to call methods direct on a module, neat.
Module TaxCalculator
def calculate(amount)
amount * 1.2
end
module_function :calculate
end
Another way to achieve a similar result is to use extend self
:
Module TaxCalculator
extend self
def calculate(amount)
amount * 1.2
end
end
Although both these approaches will allow you to call your method direct on the Module
, there are a couple of subtle differences. That's slightly out of scope for this article, but you can have a further read on the topic here.