diff options
Diffstat (limited to 'lib/singleton.rb')
| -rw-r--r-- | lib/singleton.rb | 134 |
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 |
