Skip to content

Commit ec4f66d

Browse files
rm155hsbt
authored andcommitted
Improve Ractor-compliance; Create PerRactorSingleton
1 parent 17842b0 commit ec4f66d

File tree

1 file changed

+85
-19
lines changed

1 file changed

+85
-19
lines changed

lib/singleton.rb

Lines changed: 85 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -93,21 +93,25 @@
9393
#
9494
module Singleton
9595
VERSION = "0.2.0"
96+
VERSION.freeze
9697

97-
# Raises a TypeError to prevent cloning.
98-
def clone
99-
raise TypeError, "can't clone instance of singleton #{self.class}"
100-
end
98+
module SingletonInstanceMethods
99+
# Raises a TypeError to prevent cloning.
100+
def clone
101+
raise TypeError, "can't clone instance of singleton #{self.class}"
102+
end
101103

102-
# Raises a TypeError to prevent duping.
103-
def dup
104-
raise TypeError, "can't dup instance of singleton #{self.class}"
105-
end
104+
# Raises a TypeError to prevent duping.
105+
def dup
106+
raise TypeError, "can't dup instance of singleton #{self.class}"
107+
end
106108

107-
# By default, do not retain any state when marshalling.
108-
def _dump(depth = -1)
109-
''
109+
# By default, do not retain any state when marshalling.
110+
def _dump(depth = -1)
111+
''
112+
end
110113
end
114+
include SingletonInstanceMethods
111115

112116
module SingletonClassMethods # :nodoc:
113117

@@ -121,7 +125,7 @@ def _load(str)
121125
end
122126

123127
def instance # :nodoc:
124-
@singleton__instance__ || @singleton__mutex__.synchronize { @singleton__instance__ ||= new }
128+
@singleton__instance__ || @singleton__mutex__.synchronize { @singleton__instance__ ||= set_instance(new) }
125129
end
126130

127131
private
@@ -130,22 +134,42 @@ def inherited(sub_klass)
130134
super
131135
Singleton.__init__(sub_klass)
132136
end
137+
138+
def set_instance(val)
139+
@singleton__instance__ = val
140+
end
141+
142+
def set_mutex(val)
143+
@singleton__mutex__ = val
144+
end
133145
end
134146

135-
class << Singleton # :nodoc:
147+
def self.module_with_class_methods
148+
SingletonClassMethods
149+
end
150+
151+
module SingletonClassProperties
152+
153+
def self.included(c)
154+
# extending an object with Singleton is a bad idea
155+
c.undef_method :extend_object
156+
end
157+
158+
def self.extended(c)
159+
# extending an object with Singleton is a bad idea
160+
c.singleton_class.undef_method :extend_object
161+
end
162+
136163
def __init__(klass) # :nodoc:
137164
klass.instance_eval {
138-
@singleton__instance__ = nil
139-
@singleton__mutex__ = Thread::Mutex.new
165+
set_instance(nil)
166+
set_mutex(Thread::Mutex.new)
140167
}
141168
klass
142169
end
143170

144171
private
145172

146-
# extending an object with Singleton is a bad idea
147-
undef_method :extend_object
148-
149173
def append_features(mod)
150174
# help out people counting on transitive mixins
151175
unless mod.instance_of?(Class)
@@ -157,10 +181,11 @@ def append_features(mod)
157181
def included(klass)
158182
super
159183
klass.private_class_method :new, :allocate
160-
klass.extend SingletonClassMethods
184+
klass.extend module_with_class_methods
161185
Singleton.__init__(klass)
162186
end
163187
end
188+
extend SingletonClassProperties
164189

165190
##
166191
# :singleton-method: _load
@@ -170,3 +195,44 @@ def included(klass)
170195
# :singleton-method: instance
171196
# Returns the singleton instance.
172197
end
198+
199+
module PerRactorSingleton
200+
include Singleton::SingletonInstanceMethods
201+
202+
module PerRactorSingletonClassMethods
203+
include Singleton::SingletonClassMethods
204+
def instance
205+
set_mutex(Thread::Mutex.new) if Ractor.current[mutex_key].nil?
206+
return Ractor.current[instance_key] if Ractor.current[instance_key]
207+
Ractor.current[mutex_key].synchronize {
208+
return Ractor.current[instance_key] if Ractor.current[instance_key]
209+
set_instance(new())
210+
}
211+
Ractor.current[instance_key]
212+
end
213+
214+
private
215+
216+
def instance_key
217+
:"__PerRactorSingleton_instance_with_class_id_#{object_id}__"
218+
end
219+
220+
def mutex_key
221+
:"__PerRactorSingleton_mutex_with_class_id_#{object_id}__"
222+
end
223+
224+
def set_instance(val)
225+
Ractor.current[instance_key] = val
226+
end
227+
228+
def set_mutex(val)
229+
Ractor.current[mutex_key] = val
230+
end
231+
end
232+
233+
def self.module_with_class_methods
234+
PerRactorSingletonClassMethods
235+
end
236+
237+
extend Singleton::SingletonClassProperties
238+
end

0 commit comments

Comments
 (0)