summaryrefslogtreecommitdiff
path: root/lib/singleton.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/singleton.rb')
-rw-r--r--lib/singleton.rb134
1 files changed, 101 insertions, 33 deletions
diff --git a/lib/singleton.rb b/lib/singleton.rb
index be1f7ff6ca..74aec8903c 100644
--- a/lib/singleton.rb
+++ b/lib/singleton.rb
@@ -1,4 +1,4 @@
-require 'thread'
+# frozen_string_literal: true
# The Singleton module implements the Singleton pattern.
#
@@ -13,7 +13,7 @@ require 'thread'
#
# This ensures that only one instance of Klass can be created.
#
-# a,b = Klass.instance, Klass.instance
+# a,b = Klass.instance, Klass.instance
#
# a == b
# # => true
@@ -58,10 +58,9 @@ require 'thread'
# == 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.
+# default will strip state information, e.g. instance variables 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'
#
@@ -82,7 +81,6 @@ require 'thread'
# a = Example.instance
# a.keep = "keep this"
# a.strip = "get rid of this"
-# a.taint
#
# stored_state = Marshal.dump(a)
#
@@ -94,20 +92,26 @@ require 'thread'
# p a.strip # => nil
#
module Singleton
- # Raises a TypeError to prevent cloning.
- def clone
- raise TypeError, "can't clone instance of singleton #{self.class}"
- end
+ # The version string
+ VERSION = "0.3.0"
- # Raises a TypeError to prevent duping.
- def dup
- raise TypeError, "can't dup instance of singleton #{self.class}"
- end
+ module SingletonInstanceMethods # :nodoc:
+ # Raises a TypeError to prevent cloning.
+ def clone
+ raise TypeError, "can't clone instance of singleton #{self.class}"
+ end
- # By default, do not retain any state when marshalling.
- def _dump(depth = -1)
- ''
+ # Raises a TypeError to prevent duping.
+ def dup
+ raise TypeError, "can't dup instance of singleton #{self.class}"
+ end
+
+ # By default, do not retain any state when marshalling.
+ def _dump(depth = -1)
+ ''
+ end
end
+ include SingletonInstanceMethods
module SingletonClassMethods # :nodoc:
@@ -120,36 +124,52 @@ module Singleton
instance
end
+ def instance # :nodoc:
+ @singleton__instance__ || @singleton__mutex__.synchronize { @singleton__instance__ ||= new }
+ end
+
private
def inherited(sub_klass)
super
Singleton.__init__(sub_klass)
end
+
+ def set_instance(val)
+ @singleton__instance__ = val
+ end
+
+ def set_mutex(val)
+ @singleton__mutex__ = val
+ end
+ end
+
+ def self.module_with_class_methods # :nodoc:
+ SingletonClassMethods
end
- class << Singleton # :nodoc:
+ module SingletonClassProperties # :nodoc:
+
+ def self.included(c)
+ # extending an object with Singleton is a bad idea
+ c.undef_method :extend_object
+ end
+
+ def self.extended(c)
+ # extending an object with Singleton is a bad idea
+ c.singleton_class.send(:undef_method, :extend_object)
+ end
+
def __init__(klass) # :nodoc:
klass.instance_eval {
- @singleton__instance__ = nil
- @singleton__mutex__ = Mutex.new
+ set_instance(nil)
+ set_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
private
- # extending an object with Singleton is a bad idea
- undef_method :extend_object
-
def append_features(mod)
# help out people counting on transitive mixins
unless mod.instance_of?(Class)
@@ -161,12 +181,60 @@ module Singleton
def included(klass)
super
klass.private_class_method :new, :allocate
- klass.extend SingletonClassMethods
+ klass.extend module_with_class_methods
Singleton.__init__(klass)
end
end
+ extend SingletonClassProperties
##
# :singleton-method: _load
# By default calls instance(). Override to retain singleton state.
+
+ ##
+ # :singleton-method: instance
+ # Returns the singleton instance.
+end
+
+if defined?(Ractor)
+ module RactorLocalSingleton # :nodoc:
+ include Singleton::SingletonInstanceMethods
+
+ module RactorLocalSingletonClassMethods # :nodoc:
+ include Singleton::SingletonClassMethods
+ def instance
+ set_mutex(Thread::Mutex.new) if Ractor.current[mutex_key].nil?
+ return Ractor.current[instance_key] if Ractor.current[instance_key]
+ Ractor.current[mutex_key].synchronize {
+ return Ractor.current[instance_key] if Ractor.current[instance_key]
+ set_instance(new())
+ }
+ Ractor.current[instance_key]
+ end
+
+ private
+
+ def instance_key
+ :"__RactorLocalSingleton_instance_with_class_id_#{object_id}__"
+ end
+
+ def mutex_key
+ :"__RactorLocalSingleton_mutex_with_class_id_#{object_id}__"
+ end
+
+ def set_instance(val)
+ Ractor.current[instance_key] = val
+ end
+
+ def set_mutex(val)
+ Ractor.current[mutex_key] = val
+ end
+ end
+
+ def self.module_with_class_methods
+ RactorLocalSingletonClassMethods
+ end
+
+ extend Singleton::SingletonClassProperties
+ end
end