1 # frozen_string_literal: false
3 # The Singleton module implements the Singleton pattern.
7 # To use Singleton, include the module in your class.
14 # This ensures that only one instance of Klass can be created.
16 # a,b = Klass.instance, Klass.instance
22 # # => NoMethodError - new is private ...
24 # The instance is created at upon the first call of Klass.instance().
31 # ObjectSpace.each_object(OtherKlass){}
35 # ObjectSpace.each_object(OtherKlass){}
39 # This behavior is preserved under inheritance and cloning.
43 # This above is achieved by:
45 # * Making Klass.new and Klass.allocate private.
47 # * Overriding Klass.inherited(sub_klass) and Klass.clone() to ensure that the
48 # Singleton properties are kept when inherited and cloned.
50 # * Providing the Klass.instance() method that returns the same object each
53 # * Overriding Klass._load(str) to call Klass.instance().
55 # * Overriding Klass#clone and Klass#dup to raise TypeErrors to prevent
58 # == Singleton and Marshal
60 # By default Singleton's #_dump(depth) returns the empty string. Marshalling by
61 # default will strip state information, e.g. instance variables from the instance.
62 # Classes using Singleton can provide custom _load(str) and _dump(depth) methods
63 # to retain some of the previous state of the instance.
69 # attr_accessor :keep, :strip
71 # # this strips the @strip information from the instance
72 # Marshal.dump(@keep, depth)
76 # instance.keep = Marshal.load(str)
81 # a = Example.instance
82 # a.keep = "keep this"
83 # a.strip = "get rid of this"
85 # stored_state = Marshal.dump(a)
89 # b = Marshal.load(stored_state)
91 # p a.keep # => "keep this"
97 # Raises a TypeError to prevent cloning.
99 raise TypeError, "can't clone instance of singleton #{self.class}"
102 # Raises a TypeError to prevent duping.
104 raise TypeError, "can't dup instance of singleton #{self.class}"
107 # By default, do not retain any state when marshalling.
108 def _dump(depth = -1)
112 module SingletonClassMethods # :nodoc:
115 Singleton.__init__(super)
118 # By default calls instance(). Override to retain singleton state.
123 def instance # :nodoc:
124 @singleton__instance__ || @singleton__mutex__.synchronize { @singleton__instance__ ||= new }
129 def inherited(sub_klass)
131 Singleton.__init__(sub_klass)
135 class << Singleton # :nodoc:
136 def __init__(klass) # :nodoc:
137 klass.instance_eval {
138 @singleton__instance__ = nil
139 @singleton__mutex__ = Thread::Mutex.new
146 # extending an object with Singleton is a bad idea
147 undef_method :extend_object
149 def append_features(mod)
150 # help out people counting on transitive mixins
151 unless mod.instance_of?(Class)
152 raise TypeError, "Inclusion of the OO-Singleton module in module #{mod}"
159 klass.private_class_method :new, :allocate
160 klass.extend SingletonClassMethods
161 Singleton.__init__(klass)
166 # :singleton-method: _load
167 # By default calls instance(). Override to retain singleton state.
170 # :singleton-method: instance
171 # Returns the singleton instance.