Skip to content

Commit

Permalink
[ruby/singleton] Simplify the implementation
Browse files Browse the repository at this point in the history
(ruby/singleton#7)

Remove `__init__` and move logic to `included`.
  • Loading branch information
dpep authored and matzbot committed Jun 3, 2023
1 parent 4e26ae3 commit bebd05f
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 17 deletions.
26 changes: 9 additions & 17 deletions lib/singleton.rb
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def _dump(depth = -1)
module SingletonClassMethods # :nodoc:

def clone # :nodoc:
Singleton.__init__(super)
super.include(Singleton)
end

# By default calls instance(). Override to retain singleton state.
Expand All @@ -121,31 +121,18 @@ def _load(str)
end

def instance # :nodoc:
return @singleton__instance__ if @singleton__instance__
@singleton__mutex__.synchronize {
return @singleton__instance__ if @singleton__instance__
@singleton__instance__ = new()
}
@singleton__instance__
@singleton__instance__ || @singleton__mutex__.synchronize { @singleton__instance__ ||= new }
end

private

def inherited(sub_klass)
super
Singleton.__init__(sub_klass)
sub_klass.include(Singleton)
end
end

class << Singleton # :nodoc:
def __init__(klass) # :nodoc:
klass.instance_eval {
@singleton__instance__ = nil
@singleton__mutex__ = Thread::Mutex.new
}
klass
end

private

# extending an object with Singleton is a bad idea
Expand All @@ -156,14 +143,19 @@ def append_features(mod)
unless mod.instance_of?(Class)
raise TypeError, "Inclusion of the OO-Singleton module in module #{mod}"
end

super
end

def included(klass)
super

klass.private_class_method :new, :allocate
klass.extend SingletonClassMethods
Singleton.__init__(klass)
klass.instance_eval {
@singleton__instance__ = nil
@singleton__mutex__ = Thread::Mutex.new
}
end
end

Expand Down
11 changes: 11 additions & 0 deletions test/test_singleton.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,22 @@ def test_inheritance_works_with_overridden_inherited_method
assert_same a, b
end

def test_inheritance_creates_separate_singleton
a = SingletonTest.instance
b = Class.new(SingletonTest).instance

assert_not_same a, b
end

def test_class_level_cloning_preserves_singleton_behavior
klass = SingletonTest.clone

a = klass.instance
b = klass.instance
assert_same a, b
end

def test_class_level_cloning_creates_separate_singleton
assert_not_same SingletonTest.instance, SingletonTest.clone.instance
end
end

0 comments on commit bebd05f

Please sign in to comment.