Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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