Skip to content

Instantly share code, notes, and snippets.

@estum
Created September 7, 2016 05:53
Show Gist options
  • Save estum/c83a1eeb08a788f20108db1f3fe10d18 to your computer and use it in GitHub Desktop.
Save estum/c83a1eeb08a788f20108db1f3fe10d18 to your computer and use it in GitHub Desktop.
Abstract Singleton Module Class
class AbstractSingleton < Module
def self.base_class
self < AbstractSingleton ? superclass : self
end
module SingletonInstanceMethods
::Singleton.instance_methods.each do |name|
define_method(name, ::Singleton.instance_method(name))
end
end
module SingletonClassMethods # :nodoc:
def instance
raise NotImplemented
end
def clone # :nodoc:
@singleton__module__.__init__(super)
end
# By default calls instance(). Override to retain singleton state.
def _load(str)
instance
end
private
def inherited(sub_klass)
super
@singleton__module__.__init__(sub_klass)
end
end
def __init__(klass) # :nodoc:
klass.instance_variable_set(:@singleton__module__, self)
__reset__(klass)
klass
end
private
def extend_object(klass)
klass.extend(singleton_class_methods)
end
def append_features(klass)
klass.prepend(singleton_instance_methods)
end
def prepend_features(klass)
unless klass.instance_of?(Class)
raise TypeError, "Prepending of the OO-AbstractSingleton module in module #{mod}"
end
super
end
def prepended(klass)
super
klass.private_class_method(:new, :allocate)
klass.extend(self)
klass.include(self)
__init__(klass)
end
def singleton_instance_methods(inherit: true, &block)
_def_or_get_relative_module(:SingletonInstanceMethods, inherit, &block)
end
def singleton_class_methods(inherit: true, &block)
_def_or_get_relative_module(:SingletonClassMethods, inherit, &block)
end
def _def_or_get_relative_module(name, inherit = true, &block)
mod = const_defined?(name, false) ? const_get(name, false) : self.class.base_class.const_get(name, false)
return mod unless block_given?
if self.class < mod.parent
mod = const_set(name, Module.new).tap do |submod|
mod.send(:prepend_features, submod) if inherit
end
end
mod.module_eval(&block) if block_given?
end
end
Kernel.module_eval do
def abstract_singleton(name, supermod = ::AbstractSingleton, &block)
parent = respond_to?(:const_set) ? self : Object
parent.const_set name, supermod.new(&block)
end
end
# Implement the default +Singleton+ behavior
abstract_singleton :PlainSingleton do
singleton_class_methods do
def instance(klass)
return @singleton__instance__ if @singleton__instance__
@singleton__mutex__.synchronize do
return @singleton__instance__ if @singleton__instance__
@singleton__instance__ = new()
end
@singleton__instance__
end
end
def self.__reset__(klass)
klass.instance_eval do
@singleton__instance__ = nil
@singleton__mutex__ = Mutex.new
end
nil
end
end
abstract_singleton :PerThreadSingleton do
singleton_class_methods do
attr_reader :singleton__key__
def instance
Thread.current[singleton__key__] ||= new()
end
end
def self.__init__(klass)
klass.instance_variable_set(:@singleton__key__, :"singleton_#{klass.object_id}")
super(klass)
end
def self.__reset__(klass)
Thread.current[klass.singleton__key__] = nil
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment