singleton.new 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/singleton.new.rb +181 -0
  3. metadata +44 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 65b54a973d037d87002124ad29b0228d032352cd
4
+ data.tar.gz: 114e5eda16c7d078d2d38f51544bf1b37716c6c2
5
+ SHA512:
6
+ metadata.gz: 3616647580ae0b913f0bd9feb6f4eb85fc45a4339ddbcf5164b985268001132c16b755fa78185d460e495a57145593cbc6735ad64f359d87ab1d4fd53693e9e4
7
+ data.tar.gz: a2e800558504172f88899bc19fa7491db5bb375f604a0f9fe6be47f5cd2e5c4acbc6a330b4c7b42a589a5198da99f3fe7c65c03a390a27e439cddd00a3aae0af
@@ -0,0 +1,181 @@
1
+ require 'thread'
2
+
3
+ # The Singleton module implements the Singleton pattern.
4
+ #
5
+ # == Usage
6
+ #
7
+ # To use Singleton, include the module in your class.
8
+ #
9
+ # class Klass
10
+ # include Singleton
11
+ # # ...
12
+ # end
13
+ #
14
+ # This ensures that only one instance of Klass can be created.
15
+ #
16
+ # a,b = Klass.new, Klass.new
17
+ #
18
+ # a == b
19
+ # # => true
20
+ #
21
+ # Klass.new
22
+ # # => NoMethodError - new is private ...
23
+ #
24
+ # The instance is created at upon the first call of Klass.instance().
25
+ #
26
+ # class OtherKlass
27
+ # include Singleton
28
+ # # ...
29
+ # end
30
+ #
31
+ # ObjectSpace.each_object(OtherKlass){}
32
+ # # => 0
33
+ #
34
+ # OtherKlass.new
35
+ # ObjectSpace.each_object(OtherKlass){}
36
+ # # => 1
37
+ #
38
+ #
39
+ # This behavior is preserved under inheritance and cloning.
40
+ #
41
+ # == Implementation
42
+ #
43
+ # This above is achieved by:
44
+ #
45
+ # * Making Klass.allocate private.
46
+ #
47
+ # * Overriding Klass.inherited(sub_klass) and Klass.clone() to ensure that the
48
+ # Singleton properties are kept when inherited and cloned.
49
+ #
50
+ # * Providing the Klass.new() method that returns the same object each
51
+ # time it is called.
52
+ #
53
+ # * Overriding Klass._load(str) to call Klass.new().
54
+ #
55
+ # * Overriding Klass#clone and Klass#dup to raise TypeErrors to prevent
56
+ # cloning or duping.
57
+ #
58
+ # == Singleton and Marshal
59
+ #
60
+ # By default Singleton's #_dump(depth) returns the empty string. Marshalling by
61
+ # default will strip state information, e.g. instance variables and taint
62
+ # state, from the instance. Classes using Singleton can provide custom
63
+ # _load(str) and _dump(depth) methods to retain some of the previous state of
64
+ # the instance.
65
+ #
66
+ # require 'singleton'
67
+ #
68
+ # class Example
69
+ # include Singleton
70
+ # attr_accessor :keep, :strip
71
+ # def _dump(depth)
72
+ # # this strips the @strip information from the instance
73
+ # Marshal.dump(@keep, depth)
74
+ # end
75
+ #
76
+ # def self._load(str)
77
+ # instance.keep = Marshal.load(str)
78
+ # instance
79
+ # end
80
+ # end
81
+ #
82
+ # a = Example.new
83
+ # a.keep = "keep this"
84
+ # a.strip = "get rid of this"
85
+ # a.taint
86
+ #
87
+ # stored_state = Marshal.dump(a)
88
+ #
89
+ # a.keep = nil
90
+ # a.strip = nil
91
+ # b = Marshal.load(stored_state)
92
+ # p a == b # => true
93
+ # p a.keep # => "keep this"
94
+ # p a.strip # => nil
95
+ #
96
+ module Singleton
97
+ # Raises a TypeError to prevent cloning.
98
+ def clone
99
+ raise TypeError, "can't clone instance of singleton #{self.class}"
100
+ end
101
+
102
+ # Raises a TypeError to prevent duping.
103
+ def dup
104
+ raise TypeError, "can't dup instance of singleton #{self.class}"
105
+ end
106
+
107
+ # By default, do not retain any state when marshalling.
108
+ def _dump(depth = -1)
109
+ ''
110
+ end
111
+
112
+ module SingletonClassMethods # :nodoc:
113
+
114
+ def clone # :nodoc:
115
+ Singleton.__init__(super)
116
+ end
117
+
118
+ # By default calls new(). Override to retain singleton state.
119
+ def _load(str)
120
+ new
121
+ end
122
+
123
+ private
124
+
125
+ def inherited(sub_klass)
126
+ super
127
+ Singleton.__init__(sub_klass)
128
+ end
129
+ end
130
+
131
+ class << Singleton # :nodoc:
132
+ def __init__ klass # :nodoc:
133
+ klass.instance_eval {
134
+ @singleton__instance__ = nil
135
+ @singleton__mutex__ = Mutex.new
136
+ }
137
+
138
+ if klass.methods.grep(:singleton_orig_new).empty?
139
+ class << klass
140
+ # https://web.archive.org/web/20120304144227/http://www.mindbucket.com/2009/02/11/ruby-overriding-classnew-to-make-custom-wrapper-pattern/
141
+ alias_method :singleton_orig_new, :new
142
+ end
143
+ end
144
+
145
+ klass.define_singleton_method :new do
146
+ return @singleton__instance__ if @singleton__instance__
147
+ @singleton__mutex__.synchronize {
148
+ return @singleton__instance__ if @singleton__instance__
149
+ @singleton__instance__ = singleton_orig_new
150
+ }
151
+ @singleton__instance__
152
+ end
153
+
154
+ klass
155
+ end
156
+
157
+ private
158
+
159
+ # extending an object with Singleton is a bad idea
160
+ undef_method :extend_object
161
+
162
+ def append_features(mod)
163
+ # help out people counting on transitive mixins
164
+ unless mod.instance_of?(Class)
165
+ raise TypeError, "Inclusion of the OO-Singleton module in module #{mod}"
166
+ end
167
+ super
168
+ end
169
+
170
+ def included(klass)
171
+ super
172
+ klass.private_class_method :allocate
173
+ klass.extend SingletonClassMethods
174
+ Singleton.__init__ klass
175
+ end
176
+ end
177
+
178
+ ##
179
+ # :singleton-method: _load
180
+ # By default calls new(). Override to retain singleton state.
181
+ end
metadata ADDED
@@ -0,0 +1,44 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: singleton.new
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - c4605
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-09-06 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Use .new instead of .instance
14
+ email: bolasblack@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/singleton.new.rb
20
+ homepage: http://rubygems.org/gems/singleton.new
21
+ licenses:
22
+ - MIT
23
+ metadata: {}
24
+ post_install_message:
25
+ rdoc_options: []
26
+ require_paths:
27
+ - lib
28
+ required_ruby_version: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ required_rubygems_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ requirements: []
39
+ rubyforge_project:
40
+ rubygems_version: 2.4.5
41
+ signing_key:
42
+ specification_version: 4
43
+ summary: Use .new instead of .instance
44
+ test_files: []