What are Ruby modules
Modules are a way to share code either by re-using your own code, or using third party libraries (i.e., gems).
They help you group together methods, classes, and constants inside a namespace so that they are isolated from other modules.
module Generic
def self.greeting
puts "Hello World"
end
end
module Specific
def self.greeting
puts "Hello John"
end
end
Generic.greeting
Specific.greeting
# output
Hello World
Hello John
In the example above, even though the two methods have the same names, you can still use both because they belong to different namespaces.
How are Ruby modules used
You can use modules on their own (just as you saw in the previous example), to group methods that don’t really fit anywhere else. To call a module method, you specify the name of the module, and the name of the method, separated by a dot. Like this: MyModule.my_method.
But you can also include modules into classes so that those classes inherit all the module’s instance methods.
module Greet
def greeting
puts "Hello World"
end
end
class Person
include Greet
end
Person.new.greeting
# output
Hello World
How to test a Ruby module with RSpec
For module methods (i.e., those declared on self), the tests are similar to class method tests.
require 'spec_helper'
module MyMath
def self.number
5
end
end
RSpec.describe MyMath do
it 'returns five' do
expect(MyMath.number).to eq(5)
end
end
But when you have a module that you include in other classes (i.e., it contains instance methods) the way you test it might not be obvious. An example should help with this challenge.
require 'spec_helper'
module MyMath
def number
5
end
end
class DummyClass
include MyMath
end
RSpec.describe MyMath do
it 'returns five' do
dc = DummyClass.new
expect(dc.number).to eq(5)
end
end
Because DummyClass includes the MyMath module, it behaves like any other class that would include it. So by having a test that covers DummyClass, you’ve covered all those other classes that include the module.
Another way you can do it, without including the module is to extend an object.
require 'spec_helper'
module MyMath
def number
5
end
end
class DummyClass
end
RSpec.describe MyMath do
it 'returns five' do
dc = DummyClass.new
dc.extend(MyMath)
expect(dc.number).to eq(5)
end
end
And lastly, instead of polluting the global namespace with a dummy class like that, you can use let.
require 'spec_helper'
module MyMath
def number
5
end
end
RSpec.describe MyMath do
let(:dummy_class) { Class.new { extend MyMath } }
it 'returns five' do
expect(dummy_class.number).to eq(5)
end
end
Testing modules in Ruby should be easier now that you’ve see a few examples.