[rubygems/rubygems] Use a constant empty tar header to avoid extra allocations
[ruby.git] / lib / singleton.rb
blob6da939124ee064a18478e2b8fd00b6910c696f0c
1 # frozen_string_literal: false
3 # The Singleton module implements the Singleton pattern.
5 # == Usage
7 # To use Singleton, include the module in your class.
9 #    class Klass
10 #       include Singleton
11 #       # ...
12 #    end
14 # This ensures that only one instance of Klass can be created.
16 #      a,b = Klass.instance, Klass.instance
18 #      a == b
19 #      # => true
21 #      Klass.new
22 #      # => NoMethodError - new is private ...
24 # The instance is created at upon the first call of Klass.instance().
26 #      class OtherKlass
27 #        include Singleton
28 #        # ...
29 #      end
31 #      ObjectSpace.each_object(OtherKlass){}
32 #      # => 0
34 #      OtherKlass.instance
35 #      ObjectSpace.each_object(OtherKlass){}
36 #      # => 1
39 # This behavior is preserved under inheritance and cloning.
41 # == Implementation
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
51 #    time it is called.
53 # *  Overriding Klass._load(str) to call Klass.instance().
55 # *  Overriding Klass#clone and Klass#dup to raise TypeErrors to prevent
56 #    cloning or duping.
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.
65 #    require 'singleton'
67 #    class Example
68 #      include Singleton
69 #      attr_accessor :keep, :strip
70 #      def _dump(depth)
71 #        # this strips the @strip information from the instance
72 #        Marshal.dump(@keep, depth)
73 #      end
75 #      def self._load(str)
76 #        instance.keep = Marshal.load(str)
77 #        instance
78 #      end
79 #    end
81 #    a = Example.instance
82 #    a.keep = "keep this"
83 #    a.strip = "get rid of this"
85 #    stored_state = Marshal.dump(a)
87 #    a.keep = nil
88 #    a.strip = nil
89 #    b = Marshal.load(stored_state)
90 #    p a == b  #  => true
91 #    p a.keep  #  => "keep this"
92 #    p a.strip #  => nil
94 module Singleton
95   VERSION = "0.2.0"
97   # Raises a TypeError to prevent cloning.
98   def clone
99     raise TypeError, "can't clone instance of singleton #{self.class}"
100   end
102   # Raises a TypeError to prevent duping.
103   def dup
104     raise TypeError, "can't dup instance of singleton #{self.class}"
105   end
107   # By default, do not retain any state when marshalling.
108   def _dump(depth = -1)
109     ''
110   end
112   module SingletonClassMethods # :nodoc:
114     def clone # :nodoc:
115       Singleton.__init__(super)
116     end
118     # By default calls instance(). Override to retain singleton state.
119     def _load(str)
120       instance
121     end
123     def instance # :nodoc:
124       @singleton__instance__ || @singleton__mutex__.synchronize { @singleton__instance__ ||= new }
125     end
127     private
129     def inherited(sub_klass)
130       super
131       Singleton.__init__(sub_klass)
132     end
133   end
135   class << Singleton # :nodoc:
136     def __init__(klass) # :nodoc:
137       klass.instance_eval {
138         @singleton__instance__ = nil
139         @singleton__mutex__ = Thread::Mutex.new
140       }
141       klass
142     end
144     private
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}"
153       end
154       super
155     end
157     def included(klass)
158       super
159       klass.private_class_method :new, :allocate
160       klass.extend SingletonClassMethods
161       Singleton.__init__(klass)
162     end
163   end
165   ##
166   # :singleton-method: _load
167   #  By default calls instance(). Override to retain singleton state.
169   ##
170   # :singleton-method: instance
171   #  Returns the singleton instance.