Module: Singleton
Relationships & Source Files | |
Namespace Children | |
Modules:
| |
Defined in: | lib/singleton.rb |
Overview
The Singleton module implements the Singleton
pattern.
Usage
To use Singleton
, include the module in your class.
class Klass
include Singleton
# ...
end
This ensures that only one instance of Klass can be created.
a,b = Klass.instance, Klass.instance
a == b
# => true
Klass.new
# => NoMethodError - new is private ...
The instance is created at upon the first call of Klass.instance
().
class OtherKlass
include Singleton
# ...
end
ObjectSpace.each_object(OtherKlass){}
# => 0
OtherKlass.instance
ObjectSpace.each_object(OtherKlass){}
# => 1
This behavior is preserved under inheritance and cloning.
Implementation
This above is achieved by:
-
Making
Klass.new
andKlass.allocate
private. -
Overriding
Klass.inherited
(sub_klass) andKlass.clone
() to ensure that the Singleton properties are kept when inherited and cloned. -
Providing the
Klass.instance
() method that returns the same object each time it is called. -
Overriding
Klass._load
(str) to callKlass.instance
(). -
Overriding
Klass#clone
andKlass#dup
to raise TypeErrors to prevent cloning or duping.
Singleton and Marshal
By default Singleton's #_dump(depth) returns the empty string. Marshalling by default will strip state information, e.g. instance variables and taint state, from the instance. Classes using Singleton
can provide custom _load(str) and _dump(depth) methods to retain some of the previous state of the instance.
require 'singleton'
class Example
include Singleton
attr_accessor :keep, :strip
def _dump(depth)
# this strips the @strip information from the instance
Marshal.dump(@keep, depth)
end
def self._load(str)
instance.keep = Marshal.load(str)
instance
end
end
a = Example.instance
a.keep = "keep this"
a.strip = "get rid of this"
a.taint
stored_state = Marshal.dump(a)
a.keep = nil
a.strip = nil
b = Marshal.load(stored_state)
p a == b # => true
p a.keep # => "keep this"
p a.strip # => nil
Class Method Summary
-
._load
By default calls instance().
- .append_features(mod) private
- .included(klass) private
- .__init__(klass) Internal use only
Instance Method Summary
-
#_dump(depth = -1))
By default, do not retain any state when marshalling.
-
#clone
Raises a TypeError to prevent cloning.
-
#dup
Raises a TypeError to prevent duping.
Class Method Details
.__init__(klass)
# File 'lib/singleton.rb', line 132
def __init__(klass) # :nodoc: klass.instance_eval { @singleton__instance__ = nil @singleton__mutex__ = Thread::Mutex.new } def klass.instance # :nodoc: return @singleton__instance__ if @singleton__instance__ @singleton__mutex__.synchronize { return @singleton__instance__ if @singleton__instance__ @singleton__instance__ = new() } @singleton__instance__ end klass end
._load
By default calls instance(). Override to retain singleton state.
# File 'lib/singleton.rb', line 169
RDoc directive :singleton-method: _load
.append_features(mod) (private)
[ GitHub ]# File 'lib/singleton.rb', line 153
def append_features(mod) # help out people counting on transitive mixins unless mod.instance_of?(Class) raise TypeError, "Inclusion of the OO-Singleton module in module #{mod}" end super end
.included(klass) (private)
[ GitHub ]# File 'lib/singleton.rb', line 161
def included(klass) super klass.private_class_method :new, :allocate klass.extend SingletonClassMethods Singleton.__init__(klass) end
Instance Method Details
#_dump(depth = -1))
By default, do not retain any state when marshalling.
# File 'lib/singleton.rb', line 108
def _dump(depth = -1) '' end
#clone
Raises a TypeError to prevent cloning.
# File 'lib/singleton.rb', line 98
def clone raise TypeError, "can't clone instance of singleton #{self.class}" end
#dup
Raises a TypeError to prevent duping.
# File 'lib/singleton.rb', line 103
def dup raise TypeError, "can't dup instance of singleton #{self.class}" end