summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--file.c40
-rw-r--r--lib/open3.rb1
-rw-r--r--lib/singleton.rb327
-rw-r--r--misc/inf-ruby.el11
5 files changed, 283 insertions, 104 deletions
diff --git a/ChangeLog b/ChangeLog
index c3d7df39128..33a3e0e1778 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,6 +6,14 @@ Mon Jan 28 18:33:18 2002 Nobuyoshi Nakada <nobu.nakada@nifty.ne.jp>
* parse.y (yylex): strict check for numbers.
+Mon Jan 28 18:01:01 2002 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * file.c (rb_stat_rdev_major): added. [new]
+
+ * file.c (rb_stat_rdev_minor): added. [new]
+
+ * file.c (rb_stat_inspect): print mode in octal.
+
Mon Jan 28 13:29:41 2002 K.Kosako <kosako@sofnec.co.jp>
* eval.c (is_defined): defined?(Foo::Baz) should check constants
diff --git a/file.c b/file.c
index e3bc81cdd82..8d6d5e0ca0f 100644
--- a/file.c
+++ b/file.c
@@ -211,6 +211,30 @@ rb_stat_rdev(self)
}
static VALUE
+rb_stat_rdev_major(self)
+ VALUE self;
+{
+#if defined(HAVE_ST_RDEV) && defined(major)
+ long rdev = get_stat(self)->st_rdev;
+ return ULONG2NUM(major(rdev));
+#else
+ return INT2FIX(0);
+#endif
+}
+
+static VALUE
+rb_stat_rdev_minor(self)
+ VALUE self;
+{
+#if defined(HAVE_ST_RDEV) && defined(minor)
+ long rdev = get_stat(self)->st_rdev;
+ return ULONG2NUM(minor(rdev));
+#else
+ return INT2FIX(0);
+#endif
+}
+
+static VALUE
rb_stat_size(self)
VALUE self;
{
@@ -290,15 +314,23 @@ rb_stat_inspect(self)
rb_str_buf_cat2(str, " ");
for (i = 0; i < sizeof(member)/sizeof(member[0]); i++) {
- VALUE str2;
+ VALUE v;
if (i > 0) {
rb_str_buf_cat2(str, ", ");
}
rb_str_buf_cat2(str, member[i].name);
rb_str_buf_cat2(str, "=");
- str2 = rb_inspect((*member[i].func)(self));
- rb_str_append(str, str2);
+ v = (*member[i].func)(self);
+ if (i == 2) { /* mode */
+ char buf[32];
+
+ sprintf(buf, "0%o", NUM2INT(v));
+ rb_str_buf_cat2(str, buf);
+ }
+ else {
+ rb_str_append(str, rb_inspect(v));
+ }
}
rb_str_buf_cat2(str, ">");
OBJ_INFECT(str, self);
@@ -2553,6 +2585,8 @@ Init_File()
rb_define_method(rb_cStat, "uid", rb_stat_uid, 0);
rb_define_method(rb_cStat, "gid", rb_stat_gid, 0);
rb_define_method(rb_cStat, "rdev", rb_stat_rdev, 0);
+ rb_define_method(rb_cStat, "rdev_major", rb_stat_rdev_major, 0);
+ rb_define_method(rb_cStat, "rdev_minor", rb_stat_rdev_minor, 0);
rb_define_method(rb_cStat, "size", rb_stat_size, 0);
rb_define_method(rb_cStat, "blksize", rb_stat_blksize, 0);
rb_define_method(rb_cStat, "blocks", rb_stat_blocks, 0);
diff --git a/lib/open3.rb b/lib/open3.rb
index 33701bbfc0c..a6e6c5d62b3 100644
--- a/lib/open3.rb
+++ b/lib/open3.rb
@@ -40,6 +40,7 @@ module Open3
pe[1].close
Process.waitpid(pid)
pi = [pw[1], pr[0], pe[0]]
+ pw[1].sync = true
if defined? yield
begin
return yield(*pi)
diff --git a/lib/singleton.rb b/lib/singleton.rb
index 5a9b271fbd6..2b5a3a3cb5e 100644
--- a/lib/singleton.rb
+++ b/lib/singleton.rb
@@ -1,130 +1,203 @@
-# The Singleton module implements the Singleton pattern - i.e.
+# The Singleton module implements the Singleton pattern.
#
-# class Klass
-# include Singleton
-# # ...
-# end
+# Usage:
+# class Klass
+# include Singleton
+# # ...
+# end
#
-# * ensures that only one instance of Klass called ``the instance''
-# can be created.
+# * this ensures that only one instance of Klass lets call it
+# ``the instance'' can be created.
#
# a,b = Klass.instance, Klass.instance
# a == b # => true
# a.new # NoMethodError - new is private ...
#
-# * ``The instance'' is created at instanciation time - i.e. the first call
-# of Klass.instance().
+# * ``The instance'' is created at instanciation time, in other words
+# the first call of Klass.instance(), thus
#
# class OtherKlass
# include Singleton
# # ...
# end
-# p "#{ObjectSpace.each_object(OtherKlass) {}}" # => 0
+# ObjectSpace.each_object(OtherKlass){} # => 0.
#
-# * This behavior is preserved under inheritance.
+# * This behavior is preserved under inheritance and cloning.
#
#
-# This achieved by marking
-# * Klass.new and Klass.allocate - as private and modifying
-# * Klass.inherited(sub_klass) - to ensure
-# that the Singleton pattern is properly inherited.
+# This is achieved by marking
+# * Klass.new and Klass.allocate - as private
+# * removing #clone and #dup and modifying
+# * Klass.inherited(sub_klass) and Klass.clone() -
+# to ensure that the Singleton pattern is properly
+# inherited and cloned.
#
-# In addition Klass is provided with the class methods
-# * Klass.instance() - returning ``the instance''
-# * Klass._load(str) - returning ``the instance''
-# * Klass._wait() - a hook method putting a second (or n-th)
-# thread calling Klass.instance on a waiting loop if the first call
-# to Klass.instance is still in progress.
+# 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.
#
# The sole instance method of Singleton is
-# * _dump(depth) - returning the empty string
-# The default Marshalling strategy is to strip all state information - i.e.
-# instance variables from ``the instance''. Providing custom
-# _dump(depth) and _load(str) method allows the (partial) resurrection
-# of a previous state of ``the instance'' - see third example.
-#
+# * _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''.
module Singleton
- def Singleton.included (klass)
- # should this be checked?
- # raise TypeError.new "..." if klass.type == Module
- klass.module_eval {
- undef_method :clone
- undef_method :dup
- }
- class << klass
- def inherited(sub_klass)
- # @__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
- sub_klass.instance_eval { @__instance__ = nil }
- def sub_klass.instance
- unless @__instance__.nil?
- # is the extra flexiblity having the hook method
- # _wait() around ever useful?
- _wait()
- # check for instance creation
- return @__instance__ if @__instance__
- end
- Thread.critical = true
- unless @__instance__
- @__instance__ = false
- Thread.critical = false
- begin
- @__instance__ = new
- ensure
- if @__instance__
- define_method(:instance) {@__instance__ }
- else
- # failed instance creation
- @__instance__ = nil
- end
- end
- else
- Thread.critical = false
- end
- return @__instance__
- end
- end
- def _load(str)
- instance
- end
- def _wait
- sleep(0.05) while false.equal?(@__instance__)
- end
- private :new, :allocate
- # hook methods are also marked private
- private :_load,:_wait
+ 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.new "Inclusion of the OO-Singleton module in module #{mod}"
+ end
+ unless (class << mod; self end) <= (class << Object; self end)
+ raise TypeError.new "Inclusion of the OO-Singleton module in singleton type"
+ end
+ super
+ end
+ def included (klass)
+ # remove build in copying methods
+ klass.class_eval do
+ undef_method(:clone) rescue nil
+ undef_method(:dup) rescue nil
+ 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__
+ def self.instance() @__instance__ end
+ else
+ @__instance__ = nil # failed instance creation
+ end
+ end
+ elsif _instanciate?()
+ Thread.critical = false
+ else
+ @__instance__ = false
+ Thread.critical = false
+ begin
+ @__instance__ = new
+ ensure
+ if @__instance__
+ def self.instance() @__instance__ end
+ else
+ @__instance__ = nil
+ end
+ end
+ end
+ @__instance__
end
- klass.inherited klass
- end
- private
- def _dump(depth)
- return ""
- end
end
+
+
+
if __FILE__ == $0
-#basic example
+def num_of_instances(klass)
+ "#{ObjectSpace.each_object(klass){}} #{klass} instance(s)"
+end
+
+# The basic and most important example. The latter examples demonstrate
+# advanced features that have no relevance for the general usage
+
class SomeSingletonClass
include Singleton
end
+puts "There are #{num_of_instances(SomeSingletonClass)}"
+
a = SomeSingletonClass.instance
b = SomeSingletonClass.instance # a and b are same object
-p a == b # => true
+puts "basic test is #{a == b}"
+
begin
SomeSingletonClass.new
rescue NoMethodError => mes
puts mes
end
-# threaded example with exception and customized hook #_wait method
+
+
+puts "\nThreaded example with exception and customized #_instanciate?() hook"; p
Thread.abort_on_exception = false
-def num_of_instances(mod)
- "#{ObjectSpace.each_object(mod){}} #{mod} instance"
-end
class Ups < SomeSingletonClass
def initialize
@@ -132,18 +205,23 @@ class Ups < SomeSingletonClass
puts "initialize called by thread ##{Thread.current[:i]}"
end
class << self
- def _wait
+ def _instanciate?
@enter.push Thread.current[:i]
- sleep 0.02 while false.equal?(@__instance__)
+ 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.1))
+ sleep (rand(0.08))
end
def allocate
__sleep
def self.allocate; __sleep; super() end
- raise "allocation in thread ##{Thread.current[:i]} aborted"
+ raise "boom - allocation in thread ##{Thread.current[:i]} aborted"
end
def instanciate_all
@enter = []
@@ -159,9 +237,9 @@ class Ups < SomeSingletonClass
end
end
end
- puts "Before there were #{num_of_instances(Ups)}s"
- sleep 3
- puts "Now there is #{num_of_instances(Ups)}"
+ 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
@@ -177,8 +255,17 @@ Ups.instanciate_all
# 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
+puts "\nLets see if class level cloning really works"
+Yup = Ups.clone
+def Yup.allocate
+ __sleep
+ def self.allocate; __sleep; super() end
+ raise "boom - allocation in thread ##{Thread.current[:i]} aborted"
+end
+Yup.instanciate_all
+
-# Customized marshalling
+puts "\n","Customized marshalling"
class A
include Singleton
attr_accessor :persist, :die
@@ -195,6 +282,7 @@ end
a = A.instance
a.persist = ["persist"]
a.die = "die"
+a.taint
stored_state = Marshal.dump(a)
# change state
@@ -203,6 +291,47 @@ a.die = nil
b = Marshal.load(stored_state)
p a == b # => true
p a.persist # => ["persist"]
-p a.die # => nil
+p a.die # => nil
+
+puts "\n\nSingleton with overridden default #inherited() hook"
+class Up
+ def Up.inherited(sub_klass)
+ puts "#{sub_klass} subclasses #{self}"
+ end
+end
+
+
+class Middle < Up
+ undef_method :dup
+ include Singleton
+end
+class Down < Middle; end
+
+puts "basic test is #{Down.instance == Down.instance}"
+
+
+puts "\n","Various exceptions"
+
+begin
+ module AModule
+ include Singleton
+ end
+rescue TypeError => mes
+ puts mes #=> Inclusion of the OO-Singleton module in module AModule
+end
+
+begin
+ class << 'aString'
+ include Singleton
+ end
+rescue TypeError => mes
+ puts mes # => Inclusion of the OO-Singleton module in singleton type
+end
+
+begin
+ 'aString'.extend Singleton
+rescue NoMethodError => mes
+ puts mes #=> undefined method `extend_object' for Singleton:Module
+end
end
diff --git a/misc/inf-ruby.el b/misc/inf-ruby.el
index dab2d51743a..7679ff91d76 100644
--- a/misc/inf-ruby.el
+++ b/misc/inf-ruby.el
@@ -15,7 +15,7 @@
;;; for example :
;;;
;;; (autoload 'ruby-mode "ruby-mode"
-;;; "Mode for editing ruby source files")
+;;; "Mode for editing ruby source files" t)
;;; (setq auto-mode-alist
;;; (append '(("\\.rb$" . ruby-mode)) auto-mode-alist))
;;; (setq interpreter-mode-alist (append '(("ruby" . ruby-mode))
@@ -35,9 +35,16 @@
;;; HISTORY
;;; senda - 8 Apr 1998: Created.
;;; $Log$
+;;; Revision 1.4 2002/01/29 07:16:09 matz
+;;; * file.c (rb_stat_rdev_major): added. [new]
+;;;
+;;; * file.c (rb_stat_rdev_minor): added. [new]
+;;;
+;;; * file.c (rb_stat_inspect): print mode in octal.
+;;;
;;; Revision 1.3 1999/12/01 09:24:18 matz
;;; 19991201
-;;;
+;;;
;;; Revision 1.2 1999/08/13 05:45:18 matz
;;; 1.4.0
;;;