From 09f5560c5721ad779cc2e740c4a77ad6aca1b530 Mon Sep 17 00:00:00 2001 From: knu Date: Sat, 19 Apr 2008 11:45:39 +0000 Subject: Merge everything from ruby_1_8. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8_7@16084 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 44 +++++++++++++++++++ NEWS | 13 ++++++ array.c | 111 +++++++++++++++++++++++++++++++++++------------- eval.c | 103 ++++++++++++++++++++++++++++++++++++++++++++ hash.c | 105 ++++++++++++++++++++++++++++++++++++++++++--- intern.h | 2 + lib/yaml.rb | 4 ++ lib/yaml/baseemitter.rb | 2 +- lib/yaml/encoding.rb | 6 +-- lib/yaml/rubytypes.rb | 18 ++++---- lib/yaml/store.rb | 20 +++++++-- lib/yaml/tag.rb | 7 +-- lib/yaml/types.rb | 6 +-- test/yaml/test_yaml.rb | 8 ++++ version.h | 6 +-- 15 files changed, 393 insertions(+), 62 deletions(-) diff --git a/ChangeLog b/ChangeLog index 22d81a39df..1cce913a59 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,47 @@ +Sat Apr 19 20:35:02 2008 Akinori MUSHA + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 * ext/syck/rubyext.c (syck_genericresolver_node_import): should diff --git a/NEWS b/NEWS index ea98fc2d8e..835f44bf64 100644 --- a/NEWS +++ b/NEWS @@ -27,6 +27,13 @@ with all sufficient information, see the ChangeLog file. 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 @@ with all sufficient information, see the ChangeLog file. New alias to #inject. + * Hash#eql? + * Hash#hash + * Hash#== + + Handle recursive data properly. + * Hash#delete_if * Hash#each * Hash#each_key diff --git a/array.c b/array.c index 1ab1716390..3789e4f6d9 100644 --- a/array.c +++ b/array.c @@ -2595,6 +2595,22 @@ rb_ary_rassoc(ary, value) 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; ilen; 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 @@ static VALUE 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 @@ rb_ary_equal(ary1, ary2) 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; ilen; 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 @@ static VALUE 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; ilen; 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 eql?). - */ - +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; ilen; i++) { h = (h << 1) | (h<0 ? 1 : 0); @@ -2678,6 +2697,21 @@ rb_ary_hash(ary) return LONG2FIX(h); } +/* + * 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 eql?). + */ + +static VALUE +rb_ary_hash(ary) + VALUE ary; +{ + return rb_exec_recursive(recursive_hash, ary, 0); +} + /* * call-seq: * array.include?(obj) -> true or false @@ -2707,6 +2741,29 @@ rb_ary_includes(ary, item) } +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 other_array -> -1, 0, +1 @@ -2731,19 +2788,13 @@ VALUE 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; ilen - RARRAY(ary2)->len; if (len == 0) return INT2FIX(0); if (len > 0) return INT2FIX(1); diff --git a/eval.c b/eval.c index fbca6a0fec..7b2b929bd2 100644 --- a/eval.c +++ b/eval.c @@ -13043,6 +13043,109 @@ thgroup_add(group, thread) } +/* 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. diff --git a/hash.c b/hash.c index 863c98924b..cb8e63a3e7 100644 --- a/hash.c +++ b/hash.c @@ -454,6 +454,18 @@ rb_hash_aref(hash, key) 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 @@ rb_hash_has_value(hash, val) 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,13 +1517,30 @@ equal_i(key, val1, data) 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; @@ -1533,10 +1564,8 @@ hash_equal(hash1, hash2, eql) } 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); } /* @@ -1565,6 +1594,66 @@ rb_hash_equal(hash1, hash2) return hash_equal(hash1, hash2, Qfalse); } +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 eql?). + */ + +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 true if hash and other 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; @@ -2533,6 +2622,8 @@ Init_Hash() 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); diff --git a/intern.h b/intern.h index 37c6231f57..f4f5b56aca 100644 --- a/intern.h +++ b/intern.h @@ -233,6 +233,7 @@ VALUE rb_thread_main _((void)); 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 _((VALUE)); 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)); diff --git a/lib/yaml.rb b/lib/yaml.rb index fe8335c8f0..a8da42a321 100644 --- a/lib/yaml.rb +++ b/lib/yaml.rb @@ -384,6 +384,10 @@ module YAML 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 diff --git a/lib/yaml/baseemitter.rb b/lib/yaml/baseemitter.rb index 1aef152749..a1992f498b 100644 --- a/lib/yaml/baseemitter.rb +++ b/lib/yaml/baseemitter.rb @@ -132,7 +132,7 @@ module YAML # 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 diff --git a/lib/yaml/encoding.rb b/lib/yaml/encoding.rb index 37f5cfda64..57dc553606 100644 --- a/lib/yaml/encoding.rb +++ b/lib/yaml/encoding.rb @@ -10,8 +10,8 @@ module YAML 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 @@ module YAML # 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 diff --git a/lib/yaml/rubytypes.rb b/lib/yaml/rubytypes.rb index c71b704b43..35b719196e 100644 --- a/lib/yaml/rubytypes.rb +++ b/lib/yaml/rubytypes.rb @@ -12,7 +12,7 @@ class Object 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 @@ class Hash 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 @@ class Struct 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 @@ class Array 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 @@ class Exception 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 @@ class String 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 @@ class Range 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 @@ class Time 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 Thanks! unless self.utc? @@ -347,7 +347,7 @@ end 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 diff --git a/lib/yaml/store.rb b/lib/yaml/store.rb index 2ffa9554b9..e3a8e9fcdd 100644 --- a/lib/yaml/store.rb +++ b/lib/yaml/store.rb @@ -20,10 +20,24 @@ class YAML::Store < PStore end def load(content) - YAML::load(content) + table = YAML::load(content) + if table == false + {} + else + table + end + end + + def marshal_dump_supports_canonical_option? + false end - def load_file(file) - YAML::load(file) + 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 diff --git a/lib/yaml/tag.rb b/lib/yaml/tag.rb index 56c3513bc0..0fb6bef9a0 100644 --- a/lib/yaml/tag.rb +++ b/lib/yaml/tag.rb @@ -51,11 +51,12 @@ module YAML 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 @@ class Module 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 diff --git a/lib/yaml/types.rb b/lib/yaml/types.rb index 7897db48e0..3871c628fe 100644 --- a/lib/yaml/types.rb +++ b/lib/yaml/types.rb @@ -45,7 +45,7 @@ module YAML 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 @@ module YAML 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 @@ module YAML 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 ] ) diff --git a/test/yaml/test_yaml.rb b/test/yaml/test_yaml.rb index 676310e6fc..023a8b96f5 100644 --- a/test/yaml/test_yaml.rb +++ b/test/yaml/test_yaml.rb @@ -1272,6 +1272,14 @@ EOY 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__ diff --git a/version.h b/version.h index 79b68d0aff..5fcce79bab 100644 --- a/version.h +++ b/version.h @@ -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[]; -- cgit v1.2.3