singleton pattern in ruby

2 Min. Read
Oct 14, 2019

The singleton pattern in ruby:

A class in object oriented programming is a blueprint of entities that needs to be represented. Sometimes when in a program, a certain scenario presents itself where we have to only create one instance of a class and that instance only. This is known as singleton design pattern.

Singleton design pattern eliminates the option of being able to instantiate more than one object. Although the implementation of singleton pattern being a bad design pattern is up for debate, here’s how ruby implements the design pattern.

  • One way is to make the new method of a class private
  • We can also define a class method named instance that returns the unique instance for the class.

Ruby standard library also comes with a Singleton module that we can include in any class.

  • Ruby singleton pattern without using Singleton module:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Log
  def initialize
    @log = File.new 'log.txt', 'a'
  end

  def log(msg)
    @log.puts msg
  end

  @@instance = Log.new

  def self.instance //method instance should be static
    @@instance
  end

  private_class_method :new
end
  • Including Singleton module in a class:

The Singleton module contains all the logic to implement the singleton pattern within a class. We have to require the ‘singleton’ library.

1
2
3
4
require 'singleton'
class Shop
  include Singleton
end

Now if we try to create a Shop object with Shop.new we’ll see this:

1
2
Shop.new
# NoMethodError: private method `new' called for Shop:Class

And if we want to get the one & only Shop object we can use the instance method:

1
2
3
4
Shop.instance.object_id
# 5659218
Shop.instance.object_id
# 5659218

A new method called instance is added to the Shop class as an instance method. This method always returns the same instance of the Shop class.

In the above example, we can create new Shop objects by using the Shop.send(:new) method.

When the Singleton module is included then the Shop.new method becomes private. This gives the illusion that the Shop class is not instantiable. The problem is that the Object#send method is able to call private methods of a given class.

There is also a method with which we create an instance as soon as the class is loaded, even if it is not used.

1
2
3
4
5
6
7
8
9
class EagerLog
  @@log = File.new 'log.txt', 'a'

  def self.log(msg)
    @@log.puts msg
  end

  private_class_method :new
end

Likewise, a class can be lazily instantiated, ie, an instance is created in an event the programmer wants to use the class for the first time.

1
2
3
4
5
6
7
8
class LazyLog
  def self.log
    @@log ||= File.new 'log.txt', 'a'
    @@log.puts msg
  end

  private_class_method :new
end