What is the correct way to write a singleton pattern in Ruby?
# require singleton librequire 'singleton'class AppConfig # mixin the singleton module include Singleton # do the actual app configuration def load_config(file) # do your work here puts "Application configuration file was loaded from file: #{file}" endendconf1 = AppConfig.instanceconf1.load_config "/home/khelll/conf.yml"#=>Application configuration file was loaded from file: /home/khelll/conf.ymlconf2 = AppConfig.instanceputs conf1 == conf2#=>true# notice the following 2 lines won’t workAppConfig.new rescue(puts $!)#=> new method is private# dup won’t workconf1.dup rescue(puts $!)#=>private method `new’ called for AppConfig:Class#=>can’t dup instance of singleton AppConfig
So what does ruby do when you include the singleton module inside your class?
- It makes the
new
method private and so you can’t use it. - It adds a class method called instance that instantiates only one instance of the class.
So to use ruby singleton module you need two things:
- Require the lib
singleton
then include it inside the desired class. - Use the
instance
method to get the instance you need.
If you want to create a singleton, why bother creating a class? Just create an object, and add the methods and instance variables to it you want.
>> MySingleton = Object.new=> #<Object:0x100390318>>> MySingleton.instance_eval do?> @count = 0>> def next>> @count += 1>> end>> end=> nil>> MySingleton.next=> 1>> MySingleton.next=> 2>> MySingleton.next=> 3
A more standard way that people implement this pattern is to use a Module
as the singleton object (rather than the more generic Object
):
>> module OtherSingleton>> @index = -1>> @colors = %w{ red green blue }>> def self.change>> @colors[(@index += 1) % @colors.size]>> end>> end=> nil>> OtherSingleton.change=> "red">> OtherSingleton.change=> "green">> OtherSingleton.change=> "blue">> OtherSingleton.change=> "red"
If you wanted your singleton object to inherit from some class, just make it an instance of that class. To inherit from a mixin, just use #extend
. If you want a singleton object, ruby makes it really easy, and unlike other languages, it doesn't have to be defined in a class.
Ad-hoc singletons (my first example) are all over the place, and cover the majority of cases I've encountered. The module trick normally covers the rest (when I want something a little more formal).
Ruby code should (imho) use duck typing (via #respond_to?
) rather than explicitly checking an object's class, so I normally don't care about the uniqueness of my singleton objects' class, since it's not its class that makes it unique, but everything I added after.
require 'singleton'class Klass include Singleton # ...end
See the Ruby Standard Library Singleton class documention for an explanation.