[前][次][番号順一覧][スレッド一覧]

ruby-changes:4590

From: ko1@a...
Date: Sat, 19 Apr 2008 20:46:16 +0900 (JST)
Subject: [ruby-changes:4590] knu - Ruby:r16084 (ruby_1_8_7): Merge everything from ruby_1_8.

knu	2008-04-19 20:45:39 +0900 (Sat, 19 Apr 2008)

  New Revision: 16084

  Modified files:
    branches/ruby_1_8_7/ChangeLog
    branches/ruby_1_8_7/NEWS
    branches/ruby_1_8_7/array.c
    branches/ruby_1_8_7/eval.c
    branches/ruby_1_8_7/hash.c
    branches/ruby_1_8_7/intern.h
    branches/ruby_1_8_7/lib/yaml/baseemitter.rb
    branches/ruby_1_8_7/lib/yaml/encoding.rb
    branches/ruby_1_8_7/lib/yaml/rubytypes.rb
    branches/ruby_1_8_7/lib/yaml/store.rb
    branches/ruby_1_8_7/lib/yaml/tag.rb
    branches/ruby_1_8_7/lib/yaml/types.rb
    branches/ruby_1_8_7/lib/yaml.rb
    branches/ruby_1_8_7/test/yaml/test_yaml.rb
    branches/ruby_1_8_7/version.h

  Log:
    Merge everything from ruby_1_8.


  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8_7/hash.c?r1=16084&r2=16083&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8_7/lib/yaml/baseemitter.rb?r1=16084&r2=16083&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8_7/lib/yaml/rubytypes.rb?r1=16084&r2=16083&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8_7/lib/yaml/tag.rb?r1=16084&r2=16083&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8_7/lib/yaml/encoding.rb?r1=16084&r2=16083&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8_7/eval.c?r1=16084&r2=16083&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8_7/lib/yaml/types.rb?r1=16084&r2=16083&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8_7/ChangeLog?r1=16084&r2=16083&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8_7/NEWS?r1=16084&r2=16083&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8_7/test/yaml/test_yaml.rb?r1=16084&r2=16083&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8_7/lib/yaml.rb?r1=16084&r2=16083&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8_7/lib/yaml/store.rb?r1=16084&r2=16083&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8_7/version.h?r1=16084&r2=16083&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8_7/intern.h?r1=16084&r2=16083&diff_format=u
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8_7/array.c?r1=16084&r2=16083&diff_format=u

Index: ruby_1_8_7/intern.h
===================================================================
--- ruby_1_8_7/intern.h	(revision 16083)
+++ ruby_1_8_7/intern.h	(revision 16084)
@@ -233,6 +233,7 @@
 VALUE rb_thread_local_aref _((VALUE, ID));
 VALUE rb_thread_local_aset _((VALUE, ID, VALUE));
 void rb_thread_atfork _((void));
+VALUE rb_exec_recursive _((VALUE(*)(VALUE, VALUE, int),VALUE,VALUE));
 VALUE rb_funcall_rescue __((VALUE, ID, int, ...));
 /* file.c */
 VALUE rb_file_s_expand_path _((int, VALUE *));
@@ -270,6 +271,7 @@
 VALUE rb_hash_new _((void));
 VALUE rb_hash_freeze _((VALUE));
 VALUE rb_hash_aref _((VALUE, VALUE));
+VALUE rb_hash_lookup _((VALUE, VALUE));
 VALUE rb_hash_aset _((VALUE, VALUE, VALUE));
 VALUE rb_hash_delete_if _((VALUE));
 VALUE rb_hash_delete _((VALUE,VALUE));
Index: ruby_1_8_7/array.c
===================================================================
--- ruby_1_8_7/array.c	(revision 16083)
+++ ruby_1_8_7/array.c	(revision 16084)
@@ -2595,6 +2595,22 @@
     return Qnil;
 }
 
+static VALUE recursive_equal _((VALUE, VALUE, int));
+static VALUE
+recursive_equal(ary1, ary2, recur)
+    VALUE ary1, ary2;
+    int recur;
+{
+    long i;
+
+    if (recur) return Qfalse;
+    for (i=0; i<RARRAY(ary1)->len; i++) {
+	if (!rb_equal(rb_ary_elt(ary1, i), rb_ary_elt(ary2, i)))
+	    return Qfalse;
+    }
+    return Qtrue;
+}
+
 /* 
  *  call-seq:
  *     array == other_array   ->   bool
@@ -2613,8 +2629,6 @@
 rb_ary_equal(ary1, ary2)
     VALUE ary1, ary2;
 {
-    long i;
-
     if (ary1 == ary2) return Qtrue;
     if (TYPE(ary2) != T_ARRAY) {
 	if (!rb_respond_to(ary2, rb_intern("to_ary"))) {
@@ -2623,8 +2637,20 @@
 	return rb_equal(ary2, ary1);
     }
     if (RARRAY(ary1)->len != RARRAY(ary2)->len) return Qfalse;
+    return rb_exec_recursive(recursive_equal, ary1, ary2);
+}
+
+static VALUE recursive_eql _((VALUE, VALUE, int));
+static VALUE
+recursive_eql(ary1, ary2, recur)
+    VALUE ary1, ary2;
+    int recur;
+{
+    long i;
+
+    if (recur) return Qfalse;
     for (i=0; i<RARRAY(ary1)->len; i++) {
-	if (!rb_equal(rb_ary_elt(ary1, i), rb_ary_elt(ary2, i)))
+	if (!rb_eql(rb_ary_elt(ary1, i), rb_ary_elt(ary2, i)))
 	    return Qfalse;
     }
     return Qtrue;
@@ -2642,33 +2668,26 @@
 rb_ary_eql(ary1, ary2)
     VALUE ary1, ary2;
 {
-    long i;
-
     if (ary1 == ary2) return Qtrue;
     if (TYPE(ary2) != T_ARRAY) return Qfalse;
     if (RARRAY(ary1)->len != RARRAY(ary2)->len) return Qfalse;
-    for (i=0; i<RARRAY(ary1)->len; i++) {
-	if (!rb_eql(rb_ary_elt(ary1, i), rb_ary_elt(ary2, i)))
-	    return Qfalse;
-    }
-    return Qtrue;
+    return rb_exec_recursive(recursive_eql, ary1, ary2);
 }
 
-/*
- *  call-seq:
- *     array.hash   -> fixnum
- *
- *  Compute a hash-code for this array. Two arrays with the same content
- *  will have the same hash code (and will compare using <code>eql?</code>).
- */
-
+static VALUE recursive_hash _((VALUE, VALUE, int));
 static VALUE
-rb_ary_hash(ary)
+recursive_hash(ary, dummy, recur)
     VALUE ary;
+    VALUE dummy;
+    int recur;
 {
     long i, h;
     VALUE n;
 
+    if (recur) {
+	return LONG2FIX(0);
+    }
+
     h = RARRAY(ary)->len;
     for (i=0; i<RARRAY(ary)->len; i++) {
 	h = (h << 1) | (h<0 ? 1 : 0);
@@ -2680,6 +2699,21 @@
 
 /*
  *  call-seq:
+ *     array.hash   -> fixnum
+ *
+ *  Compute a hash-code for this array. Two arrays with the same content
+ *  will have the same hash code (and will compare using <code>eql?</code>).
+ */
+
+static VALUE
+rb_ary_hash(ary)
+    VALUE ary;
+{
+    return rb_exec_recursive(recursive_hash, ary, 0);
+}
+
+/*
+ *  call-seq:
  *     array.include?(obj)   -> true or false
  *  
  *  Returns <code>true</code> if the given object is present in
@@ -2707,6 +2741,29 @@
 }
 
 
+static VALUE recursive_cmp _((VALUE, VALUE, int));
+static VALUE
+recursive_cmp(ary1, ary2, recur)
+    VALUE ary1;
+    VALUE ary2;
+    int recur;
+{
+    long i, len;
+
+    if (recur) return Qnil;
+    len = RARRAY(ary1)->len;
+    if (len > RARRAY(ary2)->len) {
+	len = RARRAY(ary2)->len;
+    }
+    for (i=0; i<len; i++) {
+	VALUE v = rb_funcall(rb_ary_elt(ary1, i), id_cmp, 1, rb_ary_elt(ary2, i));
+	if (v != INT2FIX(0)) {
+	    return v;
+	}
+    }
+    return Qundef;
+}
+
 /* 
  *  call-seq:
  *     array <=> other_array   ->  -1, 0, +1
@@ -2731,19 +2788,13 @@
 rb_ary_cmp(ary1, ary2)
     VALUE ary1, ary2;
 {
-    long i, len;
+    long len;
+    VALUE v;
 
     ary2 = to_ary(ary2);
-    len = RARRAY(ary1)->len;
-    if (len > RARRAY(ary2)->len) {
-	len = RARRAY(ary2)->len;
-    }
-    for (i=0; i<len; i++) {
-	VALUE v = rb_funcall(rb_ary_elt(ary1, i), id_cmp, 1, rb_ary_elt(ary2, i));
-	if (v != INT2FIX(0)) {
-	    return v;
-	}
-    }
+    if (ary1 == ary2) return INT2FIX(0);
+    v = rb_exec_recursive(recursive_cmp, ary1, ary2);
+    if (v != Qundef) return v;
     len = RARRAY(ary1)->len - RARRAY(ary2)->len;
     if (len == 0) return INT2FIX(0);
     if (len > 0) return INT2FIX(1);
Index: ruby_1_8_7/hash.c
===================================================================
--- ruby_1_8_7/hash.c	(revision 16083)
+++ ruby_1_8_7/hash.c	(revision 16084)
@@ -454,6 +454,18 @@
     return val;
 }
 
+VALUE
+rb_hash_lookup(hash, key)
+    VALUE hash, key;
+{
+    VALUE val;
+
+    if (!st_lookup(RHASH(hash)->tbl, key, &val)) {
+	return Qnil; /* without Hash#default */
+    }
+    return val;
+}
+
 /*
  *  call-seq:
  *     hsh.fetch(key [, default] )       => obj
@@ -1489,11 +1501,13 @@
 struct equal_data {
     int result;
     st_table *tbl;
+    int eql;
 };
 
 static int
-equal_i(key, val1, data)
-    VALUE key, val1;
+eql_i(key, val1, data)
+    VALUE key;
+    VALUE val1;
     struct equal_data *data;
 {
     VALUE val2;
@@ -1503,14 +1517,31 @@
 	data->result = Qfalse;
 	return ST_STOP;
     }
-    if (!rb_equal(val1, val2)) {
+    if (!(data->eql ? rb_eql(val1, val2) : rb_equal(val1, val2))) {
 	data->result = Qfalse;
 	return ST_STOP;
     }
     return ST_CONTINUE;
 }
 
+static VALUE recursive_eql _((VALUE, VALUE, int));
 static VALUE
+recursive_eql(hash, dt, recur)
+    VALUE hash;
+    VALUE dt;
+    int recur;
+{
+    struct equal_data *data;
+
+    if (recur) return Qfalse;
+    data = (struct equal_data*)dt;
+    data->result = Qtrue;
+    rb_hash_foreach(hash, eql_i, (st_data_t)data);
+
+    return data->result;
+}
+
+static VALUE
 hash_equal(hash1, hash2, eql)
     VALUE hash1, hash2;
     int eql;			/* compare default value if true */
@@ -1533,10 +1564,8 @@
     }
 
     data.tbl = RHASH(hash2)->tbl;
-    data.result = Qtrue;
-    rb_hash_foreach(hash1, equal_i, (st_data_t)&data);
-
-    return data.result;
+    data.eql = eql;
+    return rb_exec_recursive(recursive_eql, hash1, (VALUE)&data);
 }
 
 /*
@@ -1566,6 +1595,66 @@
 }
 
 static int
+hash_i(key, val, hval)
+    VALUE key;
+    VALUE val;
+    int *hval;
+{
+    if (key == Qundef) return ST_CONTINUE;
+    *hval ^= rb_hash(key);
+    *hval *= 137;
+    *hval ^= rb_hash(val);
+    return ST_CONTINUE;
+}
+
+static VALUE
+recursive_hash(hash, dummy, recur)
+    VALUE hash;
+    VALUE dummy;
+    int recur;
+{
+    int hval;
+
+    if (recur) {
+	return LONG2FIX(0);
+    }
+    hval = RHASH(hash)->tbl->num_entries;
+    rb_hash_foreach(hash, hash_i, (st_data_t)&hval);
+    return INT2FIX(hval);
+}
+
+/*
+ *  call-seq:
+ *     array.hash   -> fixnum
+ *
+ *  Compute a hash-code for this array. Two arrays with the same content
+ *  will have the same hash code (and will compare using <code>eql?</code>).
+ */
+
+static VALUE
+rb_hash_hash(hash)
+    VALUE hash;
+{
+    return rb_exec_recursive(recursive_hash, hash, 0);
+}
+
+
+/*
+ *  call-seq:
+ *     hash.eql?(other)  -> true or false
+ *
+ *  Returns <code>true</code> if <i>hash</i> and <i>other</i> are
+ *  both hashes with the same content.
+ */
+
+static VALUE
+rb_hash_eql(hash1, hash2)
+    VALUE hash1, hash2;
+{
+    return hash_equal(hash1, hash2, Qtrue);
+}
+
+static int
 rb_hash_invert_i(key, value, hash)
     VALUE key, value;
     VALUE hash;
@@ -2533,6 +2622,8 @@
 
     rb_define_method(rb_cHash,"==", rb_hash_equal, 1);
     rb_define_method(rb_cHash,"[]", rb_hash_aref, 1);
+    rb_define_method(rb_cHash,"hash", rb_hash_hash, 0);
+    rb_define_method(rb_cHash,"eql?", rb_hash_eql, 1);
     rb_define_method(rb_cHash,"fetch", rb_hash_fetch, -1);
     rb_define_method(rb_cHash,"[]=", rb_hash_aset, 2);
     rb_define_method(rb_cHash,"store", rb_hash_aset, 2);
Index: ruby_1_8_7/NEWS
===================================================================
--- ruby_1_8_7/NEWS	(revision 16083)
+++ ruby_1_8_7/NEWS	(revision 16084)
@@ -27,6 +27,13 @@
     Takes an optional argument that determines the level of recursion
     to flatten.
 
+  * Array#eql?
+  * Array#hash
+  * Array#==
+  * Array#<=>
+
+    Handle recursive data properly.
+
   * Array#index
   * Array#rindex
 
@@ -122,6 +129,12 @@
 
     New alias to #inject.
 
+  * Hash#eql?
+  * Hash#hash
+  * Hash#==
+
+    Handle recursive data properly.
+
   * Hash#delete_if
   * Hash#each
   * Hash#each_key
Index: ruby_1_8_7/ChangeLog
===================================================================
--- ruby_1_8_7/ChangeLog	(revision 16083)
+++ ruby_1_8_7/ChangeLog	(revision 16084)
@@ -1,3 +1,47 @@
+Sat Apr 19 20:35:02 2008  Akinori MUSHA  <knu@i...>
+
+	* lib/yaml/baseemitter.rb, lib/yaml/encoding.rb: performance
+	  tuning around String#gsub.
+
+	* lib/yaml/tag.rb: Replace nodoc with stopdoc so Module methods get
+	  documented.
+
+	* lib/yaml/store.rb (YAML::load): modified to support empty
+	  database.
+
+	* lib/yaml/store.rb (YAML::Store::marshal_dump_supports_canonical_option?):
+	  add a method to support faster PStore.
+
+Sat Apr 19 20:16:52 2008  Akinori MUSHA  <knu@i...>
+
+	* lib/yaml/types.rb: Likewise, pass self to YAML::quick_emit;
+	  merged from 1.9.
+
+	* lib/yaml.rb (quick_emit): use combination of object_id and hash to
+	  identify repeated object references, since GC will reuse memory of
+	  objects during output of YAML. [ruby-Bugs-8548] [ruby-Bugs-3698];
+	  merged from 1.9.
+
+Sat Apr 19 20:05:39 2008  Akinori MUSHA  <knu@i...>
+
+	* array.c (rb_ary_equal, rb_ary_eql, rb_ary_hash, rb_ary_cmp):
+	  Make Array#eql?, #hash, #== and #<=> use rb_exec_recursive() and
+	  handle recursive data properly.
+
+	* hash.c (hash_equal, rb_hash_hash): Make Hash#eql?, #hash and #==
+	  use rb_exec_recursive() and handle recursive data properly.
+
+Sat Apr 19 19:26:09 2008  Akinori MUSHA  <knu@i...>
+
+	* intern.h, eval.c (rb_exec_recursive): New internal function to
+	  help perform recursive operation; backported from 1.9.
+
+Sat Apr 19 18:42:04 2008  Akinori MUSHA  <knu@i...>
+
+	* intern.h, hash.c (rb_hash_lookup): New internal function to
+	  check if a key exists in a hash, ignoring #default; backported
+	  from 1.9.
+
 Fri Apr 18 18:56:57 2008  Akinori MUSHA  <knu@i...>
 
 	* ext/syck/rubyext.c (syck_genericresolver_node_import): should
Index: ruby_1_8_7/version.h
===================================================================
--- ruby_1_8_7/version.h	(revision 16083)
+++ ruby_1_8_7/version.h	(revision 16084)
@@ -1,7 +1,7 @@
 #define RUBY_VERSION "1.8.7"
-#define RUBY_RELEASE_DATE "2008-04-18"
+#define RUBY_RELEASE_DATE "2008-04-19"
 #define RUBY_VERSION_CODE 187
-#define RUBY_RELEASE_CODE 20080418
+#define RUBY_RELEASE_CODE 20080419
 #define RUBY_PATCHLEVEL 0
 
 #define RUBY_VERSION_MAJOR 1
@@ -9,7 +9,7 @@
 #define RUBY_VERSION_TEENY 7
 #define RUBY_RELEASE_YEAR 2008
 #define RUBY_RELEASE_MONTH 4
-#define RUBY_RELEASE_DAY 18
+#define RUBY_RELEASE_DAY 19
 
 #ifdef RUBY_EXTERN
 RUBY_EXTERN const char ruby_version[];
Index: ruby_1_8_7/lib/yaml.rb
===================================================================
--- ruby_1_8_7/lib/yaml.rb	(revision 16083)
+++ ruby_1_8_7/lib/yaml.rb	(revision 16084)
@@ -384,6 +384,10 @@
             else
                 emitter.reset( opts )
             end
+        oid =
+            case oid when Fixnum, NilClass; oid
+            else oid = "#{oid.object_id}-#{oid.hash}"
+            end
         out.emit( oid, &e )
 	end
 	
Index: ruby_1_8_7/lib/yaml/encoding.rb
===================================================================
--- ruby_1_8_7/lib/yaml/encoding.rb	(revision 16083)
+++ ruby_1_8_7/lib/yaml/encoding.rb	(revision 16084)
@@ -10,8 +10,8 @@
 	def YAML.escape( value, skip = "" )
 		value.gsub( /\\/, "\\\\\\" ).
               gsub( /"/, "\\\"" ).
-              gsub( /([\x00-\x1f])/ ) do |x|
-                 skip[x] || ESCAPES[ x.unpack("C")[0] ]
+              gsub( /([\x00-\x1f])/ ) do
+                 skip[$&] || ESCAPES[ $&.unpack("C")[0] ]
              end
 	end
 
@@ -19,7 +19,7 @@
 	# Unescape the condenses escapes
 	#
 	def YAML.unescape( value )
-		value.gsub( /\\(?:([nevfbart\\])|0?x([0-9a-fA-F]{2})|u([0-9a-fA-F]{4}))/ ) { |x| 
+		value.gsub( /\\(?:([nevfbart\\])|0?x([0-9a-fA-F]{2})|u([0-9a-fA-F]{4}))/ ) {
 			if $3
 				["#$3".hex ].pack('U*')
 			elsif $2
Index: ruby_1_8_7/lib/yaml/store.rb
===================================================================
--- ruby_1_8_7/lib/yaml/store.rb	(revision 16083)
+++ ruby_1_8_7/lib/yaml/store.rb	(revision 16084)
@@ -20,10 +20,24 @@
   end
 
   def load(content)
-    YAML::load(content)
+    table = YAML::load(content)
+    if table == false
+      {}
+    else
+      table
+    end
   end
 
-  def load_file(file)
-    YAML::load(file)
+  def marshal_dump_supports_canonical_option?
+    false
   end
+
+  EMPTY_MARSHAL_DATA = {}.to_yaml
+  EMPTY_MARSHAL_CHECKSUM = Digest::MD5.digest(EMPTY_MARSHAL_DATA)
+  def empty_marshal_data
+    EMPTY_MARSHAL_DATA
+  end
+  def empty_marshal_checksum
+    EMPTY_MARSHAL_CHECKSUM
+  end
 end
Index: ruby_1_8_7/lib/yaml/types.rb
===================================================================
--- ruby_1_8_7/lib/yaml/types.rb	(revision 16083)
+++ ruby_1_8_7/lib/yaml/types.rb	(revision 16084)
@@ -45,7 +45,7 @@
     class Object
         def self.tag_subclasses?; false; end
         def to_yaml( opts = {} )
-            YAML::quick_emit( object_id, opts ) do |out|
+            YAML::quick_emit( self, opts ) do |out|
                 out.map( "tag:ruby.yaml.org,2002:object:#{ @class }", to_yaml_style ) do |map|
                     @ivars.each do |k,v|
                         map.add( k, v )
@@ -123,7 +123,7 @@
             true
         end
         def to_yaml( opts = {} )
-            YAML::quick_emit( self.object_id, opts ) do |out|
+            YAML::quick_emit( self, opts ) do |out|
                 out.seq( taguri, to_yaml_style ) do |seq|
                     self.each do |v|
                         seq.add( Hash[ *v ] )
@@ -173,7 +173,7 @@
             true
         end
         def to_yaml( opts = {} )
-            YAML::quick_emit( self.object_id, opts ) do |out|
+            YAML::quick_emit( self, opts ) do |out|
                 out.seq( taguri, to_yaml_style ) do |seq|
                     self.each do |v|
                         seq.add( Hash[ *v ] )
Index: ruby_1_8_7/lib/yaml/baseemitter.rb
===================================================================
--- ruby_1_8_7/lib/yaml/baseemitter.rb	(revision 16083)
+++ ruby_1_8_7/lib/yaml/baseemitter.rb	(revision 16084)
@@ -132,7 +132,7 @@
 		# Folding paragraphs within a column
 		#
 		def fold( value )
-            value.gsub( /(^[ \t]+.*$)|(\S.{0,#{options(:BestWidth) - 1}})(?:[ \t]+|(\n+(?=[ \t]|\Z))|$)/ ) do |s| 
+            value.gsub( /(^[ \t]+.*$)|(\S.{0,#{options(:BestWidth) - 1}})(?:[ \t]+|(\n+(?=[ \t]|\Z))|$)/ ) do
                 $1 || $2 + ( $3 || "\n" )
             end
 		end
Index: ruby_1_8_7/lib/yaml/rubytypes.rb
===================================================================
--- ruby_1_8_7/lib/yaml/rubytypes.rb	(revision 16083)
+++ ruby_1_8_7/lib/yaml/rubytypes.rb	(revision 16084)
@@ -12,7 +12,7 @@
     def to_yaml_style; end
     def to_yaml_properties; instance_variables.sort; end
 	def to_yaml( opts = {} )
-		YAML::quick_emit( object_id, opts ) do |out|
+		YAML::quick_emit( self, opts ) do |out|
             out.map( taguri, to_yaml_style ) do |map|
 				to_yaml_properties.each do |m|
                     map.add( m[1..-1], instance_variable_get( m ) )
@@ -35,7 +35,7 @@
         end
     end
 	def to_yaml( opts = {} )
-		YAML::quick_emit( object_id, opts ) do |out|
+		YAML::quick_emit( self, opts ) do |out|
             out.map( taguri, to_yaml_style ) do |map|
                 each do |k, v|
                     map.add( k, v )
@@ -83,7 +83,7 @@
         end
     end
 	def to_yaml( opts = {} )
-		YAML::quick_emit( object_id, opts ) do |out|
+		YAML::quick_emit( self, opts ) do |out|
 			#
 			# Basic struct is passed as a YAML map
 			#
@@ -104,7 +104,7 @@
     yaml_as "tag:yaml.org,2002:seq"
     def yaml_initialize( tag, val ); concat( val.to_a ); end
 	def to_yaml( opts = {} )
-		YAML::quick_emit( object_id, opts ) do |out|
+		YAML::quick_emit( self, opts ) do |out|
             out.seq( taguri, to_yaml_style ) do |seq|
                 each do |x|
                     seq.add( x )
@@ -124,7 +124,7 @@
         o
     end
 	def to_yaml( opts = {} )
-		YAML::quick_emit( object_id, opts ) do |out|
+		YAML::quick_emit( self, opts ) do |out|
             out.map( taguri, to_yaml_style ) do |map|
                 map.add( 'message', message )
 				to_yaml_properties.each do |m|
@@ -161,7 +161,7 @@
         end
     end
 	def to_yaml( opts = {} )
-		YAML::quick_emit( is_complex_yaml? ? object_id : nil, opts ) do |out|
+		YAML::quick_emit( is_complex_yaml? ? self : nil, opts ) do |out|
             if is_binary_data?
                 out.scalar( "tag:yaml.org,2002:binary", [self].pack("m"), :literal )
             elsif to_yaml_properties.empty?
@@ -227,7 +227,7 @@
         end
     end
 	def to_yaml( opts = {} )
-		YAML::quick_emit( object_id, opts ) do |out|
+		YAML::quick_emit( self, opts ) do |out|
             # if self.begin.is_complex_yaml? or self.begin.respond_to? :to_str or
             #   self.end.is_complex_yaml? or self.end.respond_to? :to_str or
             #   not to_yaml_properties.empty?
@@ -310,7 +310,7 @@
         end
     end
 	def to_yaml( opts = {} )
-		YAML::quick_emit( object_id, opts ) do |out|
+		YAML::quick_emit( self, opts ) do |out|
             tz = "Z"
             # from the tidy Tobias Peters <t-peters@g...> Thanks!
             unless self.utc?
@@ -347,7 +347,7 @@
 class Date
     yaml_as "tag:yaml.org,2002:timestamp#ymd"
 	def to_yaml( opts = {} )
-		YAML::quick_emit( object_id, opts ) do |out|
+		YAML::quick_emit( self, opts ) do |out|
             out.scalar( "tag:yaml.org,2002:timestamp", self.to_s, :plain )
         end
 	end
Index: ruby_1_8_7/lib/yaml/tag.rb
===================================================================
--- ruby_1_8_7/lib/yaml/tag.rb	(revision 16083)
+++ ruby_1_8_7/lib/yaml/tag.rb	(revision 16084)
@@ -51,11 +51,12 @@
 end
 
 class Module
+    # :stopdoc:
 
     # Adds a taguri _tag_ to a class, used when dumping or loading the class
     # in YAML.  See YAML::tag_class for detailed information on typing and
     # taguris.
-    def yaml_as( tag, sc = true ) # :nodoc:
+    def yaml_as( tag, sc = true )
         verbose, $VERBOSE = $VERBOSE, nil
         class_eval <<-"end;", __FILE__, __LINE__+1
             attr_writer :taguri
@@ -79,12 +80,12 @@
     end
     # Transforms the subclass name into a name suitable for display
     # in a subclassed tag.
-    def yaml_tag_class_name  # :nodoc:
+    def yaml_tag_class_name
         self.name
     end
     # Transforms the subclass name found in the tag into a Ruby
     # constant name.
-    def yaml_tag_read_class( name ) # :nodoc:
+    def yaml_tag_read_class( name )
         name
     end
 end
Index: ruby_1_8_7/test/yaml/test_yaml.rb
===================================================================
--- ruby_1_8_7/test/yaml/test_yaml.rb	(revision 16083)
+++ ruby_1_8_7/test/yaml/test_yaml.rb	(revision 16084)
@@ -1272,6 +1272,14 @@
       assert_equal([{}], o.keys)
     end
 
+    #
+    # contributed by riley lynch [ruby-Bugs-8548]
+    #
+    def test_object_id_collision
+      omap = YAML::Omap.new
+      1000.times { |i| omap["key_#{i}"] = { "value" => i } }
+      raise "id collision in ordered map" if omap.to_yaml =~ /id\d+/
+    end
 end
 
 if $0 == __FILE__
Index: ruby_1_8_7/eval.c
===================================================================
--- ruby_1_8_7/eval.c	(revision 16083)
+++ ruby_1_8_7/eval.c	(revision 16084)
@@ -13043,6 +13043,109 @@
 }
 
 
+/* variables for recursive traversals */
+static ID recursive_key;
+
+static VALUE
+recursive_check(hash, obj)
+    VALUE hash;
+    VALUE obj;
+{
+    if (NIL_P(hash) || TYPE(hash) != T_HASH) {
+	return Qfalse;
+    }
+    else {
+	VALUE list = rb_hash_aref(hash, ID2SYM(rb_frame_last_func()));
+
+	if (NIL_P(list) || TYPE(list) != T_HASH)
+	    return Qfalse;
+	if (NIL_P(rb_hash_lookup(list, obj)))
+	    return Qfalse;
+	return Qtrue;
+    }
+}
+
+static VALUE
+recursive_push(hash, obj)
+    VALUE hash;
+    VALUE obj;
+{
+    VALUE list, sym;
+
+    sym = ID2SYM(rb_frame_last_func());
+    if (NIL_P(hash) || TYPE(hash) != T_HASH) {
+	hash = rb_hash_new();
+	rb_thread_local_aset(rb_thread_current(), recursive_key, hash);
+	list = Qnil;
+    }
+    else {
+	list = rb_hash_aref(hash, sym);
+    }
+    if (NIL_P(list) || TYPE(list) != T_HASH) {
+	list = rb_hash_new();
+	rb_hash_aset(hash, sym, list);
+    }
+    rb_hash_aset(list, obj, Qtrue);
+    return hash;
+}
+
+static void
+recursive_pop(hash, obj)
+    VALUE hash;
+    VALUE obj;
+{
+    VALUE list, sym;
+
+    sym = ID2SYM(rb_frame_last_func());
+    if (NIL_P(hash) || TYPE(hash) != T_HASH) {
+	VALUE symname;
+	VALUE thrname;
+	symname = rb_inspect(sym);
+	thrname = rb_inspect(rb_thread_current());
+
+	rb_raise(rb_eTypeError, "invalid inspect_tbl hash for %s in %s",
+		 StringValuePtr(symname), StringValuePtr(thrname));
+    }
+    list = rb_hash_aref(hash, sym);
+    if (NIL_P(list) || TYPE(list) != T_HASH) {
+	VALUE symname = rb_inspect(sym);
+	VALUE thrname = rb_inspect(rb_thread_current());
+	rb_raise(rb_eTypeError, "invalid inspect_tbl list for %s in %s",
+		 StringValuePtr(symname), StringValuePtr(thrname));
+    }
+    rb_hash_delete(list, obj);
+}
+
+VALUE
+rb_exec_recursive(func, obj, arg)
+    VALUE (*func) _((VALUE, VALUE, int));
+    VALUE obj;
+    VALUE arg;
+{
+    VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
+    VALUE objid = rb_obj_id(obj);
+
+    if (recursive_check(hash, objid)) {
+	return (*func) (obj, arg, Qtrue);
+    }
+    else {
+	VALUE result = Qundef;
+	int state;
+
+	hash = recursive_push(hash, objid);
+	PUSH_TAG(PROT_NONE);
+	if ((state = EXEC_TAG()) == 0) {
+	    result = (*func) (obj, arg, Qfalse);
+	}
+	POP_TAG();
+	recursive_pop(hash, objid);
+	if (state)
+	    JUMP_TAG(state);
+	return result;
+    }
+}
+
+
 /*
  *  +Thread+ encapsulates the behavior of a thread of
  *  execution, including the main thread of the Ruby script.

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]