This is a multi-part message in MIME format.

------extPart_000_003D_01C35919.1F2811C0
Content-Type: text/plain;
	charsetso-8859-1"
Content-Transfer-Encoding: 7bit

Hi,

some examples of the current singleton.rb depend on the previous
allocate-framework.  The patch also contains a simplification of
the current implementation (the logic didn't change at all). 


/Christoph


------extPart_000_003D_01C35919.1F2811C0
Content-Type: application/octet-stream;
	nameingleton.diff"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filenameingleton.diff"

--- singleton.rb.old	2003-08-02 16:40:46.804458300 +0200
+++ singleton.rb	2003-08-02 16:34:55.889867900 +0200
@@ -11,10 +11,10 @@

a,b  = Klass.instance, Klass.instance
a == b   # => true
-#    a.new     #  NoMethodError - new is private ...
+#    a.new    #  NoMethodError - new is private ...

-# *  ``The instance'' is created at instanciation time, in other words
-#    the first call of Klass.instance(), thus
+# *  ``The instance'' is created at instanciation time, in other
+#    words the first call of Klass.instance(), thus

class OtherKlass
include Singleton
@@ -25,148 +25,157 @@
This behavior is preserved under inheritance and cloning.


+#
his is achieved by marking
Klass.new and Klass.allocate - as private
-# *  removing #clone and #dup and modifying 
+#
+# Providing (or modifying) the class methods
Klass.inherited(sub_klass) and Klass.clone()  - 
to ensure that the Singleton pattern is properly
inherited and cloned.

-# In addition Klass is providing the additional class methods
-# *  Klass.instance()  -  returning ``the instance''. After a successful
-#    self modifying instanciating first call the method body is a simple
-#           def Klass.instance()
-#               return @__instance__
-#           end
-# *  Klass._load(str)  -  calls instance()
-# *  Klass._instanciate?()  -  returning ``the instance'' or nil
-#    This hook method puts a second (or nth) thread calling
-#    Klass.instance() on a waiting loop. The return value signifies
-#    the successful completion or premature termination of the
-#    first, or more generally, current instanciating thread.
+# *  Klass.instance()  -  returning ``the instance''. After a
+#    successful self modifying (normally the first) call the
+#    method body is a simple:
+#
+#       def Klass.instance()
+#         return @__instance__
+#       end
+#
+# *  Klass._load(str)  -  calling Klass.instance()
+#
+# *  Klass._instanciate?()  -  returning ``the instance'' or
+#    nil. This hook method puts a second (or nth) thread calling
+#    Klass.instance() on a waiting loop. The return value
+#    signifies the successful completion or premature termination
+#    of the first, or more generally, current "instanciation thread".
+#
+#
+# The instance method of Singleton are
+# * clone and dup - raising TypeErrors to prevent cloning or duping

-# The sole instance method of Singleton is
_dump(depth) - returning the empty string.  Marshalling strips
-#    by default all state information, e.g. instance variables and taint
-#    state, from ``the instance''.  Providing custom _load(str) and
-#    _dump(depth) hooks allows the (partially) resurrections of a
-#    previous state of ``the instance''.
+#    by default all state information, e.g. instance variables and
+#    taint state, from ``the instance''.  Providing custom _load(str)
+#    and _dump(depth) hooks allows the (partially) resurrections of
+#    a previous state of ``the instance''.
+
+
0Aodule Singleton
-    private 
-    #  default marshalling strategy
-    def _dump(depth=-1) '' end
-    
-    class << self
-        #  extending an object with Singleton is a bad idea
-        undef_method :extend_object
-        private
-        def append_features(mod)
-            #  This catches ill advisted inclusions of Singleton in
-            #  singletons types (sounds like an oxymoron) and 
-            #  helps out people counting on transitive mixins
-            unless mod.instance_of?(Class)
-                raise TypeError, "Inclusion of the OO-Singleton module in module #{mod}"
-            end 
-            unless (class << mod; self end) <= (class << Object; self end)
-                raise TypeError, "Inclusion of the OO-Singleton module in singleton type"
-            end
-            super
+  #  disable build-in copying methods
+  def clone
+    raise TypeError, "can't clone instance of singleton #{self.class}"
+  end
+  def dup
+    raise TypeError, "can't dup instance of singleton #{self.class}"
+  end
+  
+  private 
+  #  default marshalling strategy
+  def _dump(depth=-1) 
+    ''
+  end
+end
+
+
+class << Singleton
+  #  Method body of first instance call.
+  FirstInstanceCall = proc do
+    #  @__instance__ takes on one of the following values
+    #  * nil     -  before and after a failed creation
+    #  * false  -  during creation
+    #  * sub_class instance  -  after a successful creation
+    #  the form makes up for the lack of returns in progs
+    Thread.critical = true
+    if  @__instance__.nil?
+      @__instance__  = false
+      Thread.critical = false
+      begin
+        @__instance__ = new
+      ensure
+        if @__instance__
+          def self.instance; @__instance__ end
+        else
+          @__instance__ = nil #  failed instance creation
nd
-        def included(klass)
-            #  remove build in copying methods
-            klass.class_eval do 
-	      define_method(:clone) {raise TypeError, "can't clone singleton #{self.class}"}
-            end
-            
-            #  initialize the ``klass instance variable'' @__instance__ to nil
-            klass.instance_eval do @__instance__ = nil end
-            class << klass
-                #  a main point of the whole exercise - make
-                #  new and allocate private
-                private  :new, :allocate
-                
-                #  declare the self modifying klass#instance method
-                define_method(:instance, Singleton::FirstInstanceCall) 
-                 
-                #  simple waiting loop hook - should do in most cases
-                #  note the pre/post-conditions of a thread-critical state
-                private   
-                def _instanciate?()
-                    while false.equal?(@__instance__)
-                        Thread.critical = false
-                        sleep(0.08)  
-                        Thread.critical = true
-                    end
-                    @__instance__
-                end
-                
-                #  default Marshalling strategy
-                def _load(str) instance end    
-                 
-               #  ensure that the Singleton pattern is properly inherited   
-                def inherited(sub_klass)
-                    super
-                    sub_klass.instance_eval do @__instance__ = nil end
-                    class << sub_klass
-                        define_method(:instance, Singleton::FirstInstanceCall) 
-                    end
-                end 
-                
-                public
-                #  properly clone the Singleton pattern. Question - Did
-                #  you know that duping doesn't copy class methods?
-                def clone
-                    res = super
-                    res.instance_eval do @__instance__ = nil end
-                    class << res
-                        define_method(:instance, Singleton::FirstInstanceCall)
-                    end
-                    res
-                end
-            end   #  of << klass
-        end       #  of included
-    end           #  of << Singleton
-    
-    FirstInstanceCall = proc do
-        #  @__instance__ takes on one of the following values
-        #  * nil     -  before and after a failed creation
-        #  * false  -  during creation
-        #  * sub_class instance  -  after a successful creation
-        #  the form makes up for the lack of returns in progs
-        Thread.critical = true
-        if  @__instance__.nil?
-            @__instance__  = false
-            Thread.critical = false
-            begin
-                @__instance__ = new
-            ensure
-                if @__instance__
-		    define_method(:instance) {@__instance__}
-                else
-                    @__instance__ = nil #  failed instance creation
-                end
-            end
-        elsif  _instanciate?()
-            Thread.critical = false    
+      end
+    elsif  _instanciate?()
+      Thread.critical = false    
+    else
+      @__instance__  = false
+      Thread.critical = false
+      begin
+        @__instance__ = new
+      ensure
+        if @__instance__
+          def self.instance; @__instance__ end
lse
-            @__instance__  = false
-            Thread.critical = false
-            begin
-                @__instance__ = new
-            ensure
-                if @__instance__
-		    define_method(:instance) {@__instance__}
-                else
-                    @__instance__ = nil
-                end
-            end
+          @__instance__ = nil
nd
-        @__instance__ 
+      end
+    end
+    @__instance__
+  end
+  
+  module SingletonClassMethods  
+    # properly clone the Singleton pattern - did you know
+    # that duping doesn't copy class methods?  
+    def clone
+      Singleton.__init__(super)
+    end
+    
+    private
+    
+    #  ensure that the Singleton pattern is properly inherited   
+    def inherited(sub_klass)
+      super
+      Singleton.__init__(sub_klass)
+    end
+    
+    def _load(str) 
+      instance 
+    end
+    
+    # waiting-loop hook
+    def _instanciate?()
+      while false.equal?(@__instance__)
+        Thread.critical = false
+        sleep(0.08)   # timeout
+        Thread.critical = true
+      end
+      @__instance__
nd
+  end
+  
+  def __init__(klass)
+    klass.instance_eval { @__instance__ = nil }
+    class << klass
+      define_method(:instance,FirstInstanceCall)
+    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)
+      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)
+  end
nd
-
-
+ 
0A0Af __FILE__ == $0
@@ -175,11 +184,10 @@
#{ObjectSpace.each_object(klass){}} #{klass} instance(s)"
nd 
0A-# The basic and most important example.  The latter examples demonstrate
-# advanced features that have no relevance for the general usage
+# The basic and most important example.
0Alass SomeSingletonClass
-    include Singleton
+  include Singleton
nd
uts "There are #{num_of_instances(SomeSingletonClass)}" 
0A@@ -188,9 +196,9 @@
uts "basic test is #{a == b}"
0Aegin
-    SomeSingletonClass.new
+  SomeSingletonClass.new
escue  NoMethodError => mes
-    puts mes
+  puts mes
nd
0A0A@@ -199,83 +207,102 @@
hread.abort_on_exception = false
0Alass Ups < SomeSingletonClass
-    def initialize
-        self.class.__sleep
-        puts "initialize called by thread ##{Thread.current[:i]}"
+  def initialize
+    self.class.__sleep
+    puts "initialize called by thread ##{Thread.current[:i]}"
+  end
+end
+  
+class << Ups
+  def _instanciate?
+    @enter.push Thread.current[:i]
+    while false.equal?(@__instance__)
+      Thread.critical = false
+      sleep 0.08 
+      Thread.critical = true
nd
-    class << self
-        def _instanciate?
-            @enter.push Thread.current[:i]
-            while false.equal?(@__instance__)
-                Thread.critical = false
-                sleep 0.04 
-                Thread.critical = true
-            end
-            @leave.push Thread.current[:i]
-            @__instance__
-        end
-        def __sleep
-            sleep(rand(0.08))
-        end 
-        def allocate
-            __sleep
-            def self.allocate; __sleep; super() end
-            raise  "boom - allocation in thread ##{Thread.current[:i]} aborted"
-        end
-        def instanciate_all
-            @enter = []
-            @leave = []
-            1.upto(9) do |i|  
-                Thread.new do 
-                    begin
-                        Thread.current[:i] = i
-                        __sleep
-                        instance
-                    rescue RuntimeError => mes
-                        puts mes
-                    end
-                end
-            end
-            puts "Before there were #{num_of_instances(self)}"
-            sleep 5
-            puts "Now there is #{num_of_instances(self)}"
-            puts "#{@enter.join '; '} was the order of threads entering the waiting loop"
-            puts "#{@leave.join '; '} was the order of threads leaving the waiting loop"
-        end
+    @leave.push Thread.current[:i]
+    @__instance__
+  end
+  
+  def __sleep
+    sleep(rand(0.08))
+  end
+  
+  def new
+    begin
+      __sleep
+      raise  "boom - thread ##{Thread.current[:i]} failed to create instance"
+    ensure
+      # simple flip-flop
+      class << self
+        remove_method :new
+      end
nd
+  end
+  
+  def instanciate_all
+    @enter = []
+    @leave = []
+    1.upto(9) {|i|  
+      Thread.new { 
+        begin
+          Thread.current[:i] = i
+          __sleep
+          instance
+        rescue RuntimeError => mes
+          puts mes
+        end
+      }
+    }
+    puts "Before there were #{num_of_instances(self)}"
+    sleep 3
+    puts "Now there is #{num_of_instances(self)}"
+    puts "#{@enter.join '; '} was the order of threads entering the waiting loop"
+    puts "#{@leave.join '; '} was the order of threads leaving the waiting loop"
+  end
nd
0A+
ps.instanciate_all
-#  results in message like
-#  Before there were 0 Ups instances
-#  boom - allocation in thread #8 aborted
-#  initialize called by thread #3
-#  Now there is 1 Ups instance
-#  2; 3; 6; 1; 7; 5; 9; 4 was the order of threads entering the waiting loop
-#  3; 2; 1; 7; 6; 5; 4; 9 was the order of threads leaving the waiting loop
+# results in message like
+# Before there were 0 Ups instance(s)
+# boom - thread #6 failed to create instance
+# initialize called by thread #3
+# Now there is 1 Ups instance(s)
+# 3; 2; 1; 8; 4; 7; 5 was the order of threads entering the waiting loop
+# 3; 2; 1; 7; 4; 8; 5 was the order of threads leaving the waiting loop
+
0Auts "\nLets see if class level cloning really works"
up = Ups.clone
-def Yup.allocate
+def Yup.new
+  begin
_sleep
-    def self.allocate; __sleep; super() end
-    raise  "boom - allocation in thread ##{Thread.current[:i]} aborted"
+    raise  "boom - thread ##{Thread.current[:i]} failed to create instance"
+  ensure
+    # simple flip-flop
+    class << self
+      remove_method :new
+    end
+  end
nd
up.instanciate_all
0A0A-puts "\n","Customized marshalling"
+puts "\n\n","Customized marshalling"
lass A
-    include Singleton
-    attr_accessor :persist, :die
-    def _dump(depth)
-        # this strips the @die information from the instance
-        Marshal.dump(@persist,depth)
-    end
+  include Singleton
+  attr_accessor :persist, :die
+  def _dump(depth)
+    # this strips the @die information from the instance
+    Marshal.dump(@persist,depth)
+  end
nd
+
ef A._load(str)
-    instance.persist = Marshal.load(str)
-    instance
+  instance.persist = Marshal.load(str)
+  instance
nd
0A3D A.instance
@@ -292,45 +319,36 @@
.persist  #  => ["persist"]
.die      #  => nil
0A+
uts "\n\nSingleton with overridden default #inherited() hook"
lass Up
-    def Up.inherited(sub_klass)
-        puts "#{sub_klass} subclasses #{self}"
-    end
+end
+def Up.inherited(sub_klass)
+  puts "#{sub_klass} subclasses #{self}"
nd
0A0Alass Middle < Up
-    undef_method :dup
-    include Singleton
+  include Singleton
nd
-class Down < Middle; end
-
-puts  "basic test is #{Down.instance == Down.instance}"  
-
0A-puts "\n","Various exceptions"
+class Down < Middle; end
0A-begin
-    module AModule
-        include Singleton
-    end
-rescue TypeError => mes
-    puts mes  #=> Inclusion of the OO-Singleton module in module AModule
-end
+puts  "and basic \"Down test\" is #{Down.instance == Down.instance}\n
+Various exceptions"  
0Aegin
-    class << 'aString'
-        include Singleton
-    end
+  module AModule
+    include Singleton
+  end
escue TypeError => mes
-    puts mes  # => Inclusion of the OO-Singleton module in singleton type
+  puts mes  #=> Inclusion of the OO-Singleton module in module AModule
nd
0Aegin
-    'aString'.extend Singleton
+  'aString'.extend Singleton
escue NoMethodError => mes
-    puts mes  #=> undefined method `extend_object' for Singleton:Module
+  puts mes  #=> undefined method `extend_object' for Singleton:Module
nd
0And
-----extPart_000_003D_01C35919.1F2811C0--