From d21bd1c06dbd04b89cdf4d50ce85fede95a7bcc9 Mon Sep 17 00:00:00 2001 From: why Date: Wed, 18 Jun 2003 01:06:00 +0000 Subject: [PATCH] * ext/syck/rubyext.c (rb_syck_load_handler): merge key implemented. * ext/syck/rubyext.c (transfer_find_i): removed use of String#=~ in favor of Regexp#match. * lib/yaml.rb: YAML::try_implicit returns. * lib/yaml/rubytypes.rb: Regexps added for type matching. * lib/yaml/emitter.rb: fix String + nil error. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3955 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 13 ++++++ ext/syck/rubyext.c | 100 ++++++++++++++++++++++++++++++++++++------ lib/yaml.rb | 7 +++ lib/yaml/emitter.rb | 2 +- lib/yaml/rubytypes.rb | 10 ++--- 5 files changed, 112 insertions(+), 20 deletions(-) diff --git a/ChangeLog b/ChangeLog index 42b9bfeff9..c2348baaa3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +Wed Jun 18 01:13:36 2003 why the lucky stiff + + * ext/syck/rubyext.c (rb_syck_load_handler): merge key implemented. + + * ext/syck/rubyext.c (transfer_find_i): removed use of String#=~ in favor + of Regexp#match. + + * lib/yaml.rb: YAML::try_implicit returns. + + * lib/yaml/rubytypes.rb: Regexps added for type matching. + + * lib/yaml/emitter.rb: fix String + nil error. + Tue Jun 17 17:01:08 2003 why the lucky stiff * ext/syck/gram.c: added grammar for certain empty sequence entries. diff --git a/ext/syck/rubyext.c b/ext/syck/rubyext.c index 98f1bfb58f..dfd6f2d28e 100644 --- a/ext/syck/rubyext.c +++ b/ext/syck/rubyext.c @@ -14,21 +14,32 @@ typedef struct RVALUE { union { + //struct { + // unsigned long flags; /* always 0 for freed obj */ + // struct RVALUE *next; + //} free; struct RBasic basic; struct RObject object; struct RClass klass; + //struct RFloat flonum; + //struct RString string; struct RArray array; + //struct RRegexp regexp; struct RHash hash; + //struct RData data; struct RStruct rstruct; + //struct RBignum bignum; + //struct RFile file; } as; } RVALUE; #define RUBY_DOMAIN "ruby.yaml.org,2002" -static ID s_new, s_utc, s_at, s_to_f, s_read, s_binmode, s_call, s_transfer; +static ID s_new, s_utc, s_at, s_to_f, s_read, s_binmode, s_call, s_transfer, s_update, s_dup, s_match; static VALUE sym_model, sym_generic; static VALUE sym_scalar, sym_seq, sym_map; -VALUE cDate, cParser, cLoader, cNode, cPrivateType, cDomainType, cBadAlias, oDefaultLoader; +VALUE cDate, cParser, cLoader, cNode, cPrivateType, cDomainType, cBadAlias, cMergeKey; +VALUE oDefaultLoader; /* * my private collection of numerical oddities. @@ -46,7 +57,7 @@ void rb_syck_err_handler _((SyckParser *, char *)); SyckNode * rb_syck_bad_anchor_handler _((SyckParser *, char *)); struct parser_xtra { - VALUE data; // Borrowed this idea from marshal.c to fix [ruby-dev:8067] problem + VALUE data; // Borrowed this idea from marshal.c to fix [ruby-core:8067] problem VALUE proc; }; @@ -269,6 +280,21 @@ rb_syck_parse_handler(p, n) return obj; } +/* + * handles merging of an array of hashes + * (see http://www.yaml.org/type/merge/) + */ +VALUE +syck_merge_i( entry, hsh ) + VALUE entry, hsh; +{ + if ( rb_obj_is_kind_of( entry, rb_cHash ) ) + { + rb_funcall( hsh, s_update, 1, entry ); + } + return Qnil; +} + /* * {native mode} node handler * - Converts data into native Ruby types @@ -363,15 +389,15 @@ rb_syck_load_handler(p, n) day = INT2FIX(strtol(ptr, NULL, 10)); obj = rb_funcall( cDate, s_new, 3, year, mon, day ); - - // S_REALLOC_N( n->data.str->ptr, char, 22 ); - // strcat( n->data.str->ptr, "t00:00:00Z" ); - // obj = rb_syck_mktime( n->data.str->ptr ); } else if ( strncmp( n->type_id, "timestamp", 9 ) == 0 ) { obj = rb_syck_mktime( n->data.str->ptr ); } + else if ( strncmp( n->type_id, "merge", 5 ) == 0 ) + { + obj = rb_funcall( cMergeKey, s_new, 0 ); + } else { check_transfers = 1; @@ -392,7 +418,41 @@ rb_syck_load_handler(p, n) obj = rb_hash_new(); for ( i = 0; i < n->data.pairs->idx; i++ ) { - rb_hash_aset( obj, syck_map_read( n, map_key, i ), syck_map_read( n, map_value, i ) ); + VALUE k = syck_map_read( n, map_key, i ); + VALUE v = syck_map_read( n, map_value, i ); + int merge_key = 0; + + // + // Handle merge keys + // + if ( rb_obj_is_kind_of( k, cMergeKey ) ) + { + if ( rb_obj_is_kind_of( v, rb_cHash ) ) + { + VALUE dup = rb_funcall( v, s_dup, 0 ); + rb_funcall( dup, s_update, 1, obj ); + obj = dup; + merge_key = 1; + } + else if ( rb_obj_is_kind_of( v, rb_cArray ) ) + { + VALUE end = rb_ary_pop( v ); + if ( rb_obj_is_kind_of( end, rb_cHash ) ) + { + VALUE dup = rb_funcall( end, s_dup, 0 ); + v = rb_ary_reverse( v ); + rb_ary_push( v, obj ); + rb_iterate( rb_each, v, syck_merge_i, dup ); + obj = dup; + merge_key = 1; + } + } + } + + if ( ! merge_key ) + { + rb_hash_aset( obj, k, v ); + } } check_transfers = 1; break; @@ -746,12 +806,15 @@ transfer_find_i(entry, col) { VALUE key = rb_ary_entry( entry, 0 ); VALUE tid = rb_ary_entry( col, 0 ); - VALUE match = rb_funcall(tid, rb_intern("=~"), 1, key); - if ( ! NIL_P( match ) ) - { - rb_ary_push( col, rb_ary_entry( entry, 1 ) ); - rb_iter_break(); - } + if ( rb_respond_to( key, s_match ) ) + { + VALUE match = rb_funcall( key, rb_intern("match"), 1, tid ); + if ( ! NIL_P( match ) ) + { + rb_ary_push( col, rb_ary_entry( entry, 1 ) ); + rb_iter_break(); + } + } return Qnil; } @@ -957,6 +1020,10 @@ Init_syck() s_binmode = rb_intern("binmode"); s_transfer = rb_intern("transfer"); s_call = rb_intern("call"); + s_update = rb_intern("update"); + s_dup = rb_intern("dup"); + s_match = rb_intern("match"); + sym_model = ID2SYM(rb_intern("Model")); sym_generic = ID2SYM(rb_intern("Generic")); sym_map = ID2SYM(rb_intern("map")); @@ -1030,5 +1097,10 @@ Init_syck() cBadAlias = rb_define_class_under( rb_syck, "BadAlias", rb_cObject ); rb_define_attr( cBadAlias, "name", 1, 1 ); rb_define_method( cBadAlias, "initialize", syck_badalias_initialize, 1); + + // + // Define YAML::Syck::MergeKey class + // + cMergeKey = rb_define_class_under( rb_syck, "MergeKey", rb_cObject ); } diff --git a/lib/yaml.rb b/lib/yaml.rb index 4bafa7c5d6..39e176541e 100644 --- a/lib/yaml.rb +++ b/lib/yaml.rb @@ -118,6 +118,13 @@ module YAML @@loader.transfer( type_id, obj ) end + # + # Apply any implicit a node may qualify for + # + def YAML.try_implicit( obj ) + YAML.transfer( YAML.detect_implicit( obj ), obj ) + end + # # Method to extract colon-seperated type and class, returning # the type and the constant of the class diff --git a/lib/yaml/emitter.rb b/lib/yaml/emitter.rb index 66c7a6e813..0255cc7d02 100644 --- a/lib/yaml/emitter.rb +++ b/lib/yaml/emitter.rb @@ -286,7 +286,7 @@ module YAML @buffer.push( "" ) #p [ self.id, @level, :END ] if @level < 0 - header + @buffer.to_s[@headless..-1] + header + @buffer.to_s[@headless..-1].to_s end end end diff --git a/lib/yaml/rubytypes.rb b/lib/yaml/rubytypes.rb index 2597c86a54..09aab98895 100644 --- a/lib/yaml/rubytypes.rb +++ b/lib/yaml/rubytypes.rb @@ -30,7 +30,7 @@ class Object end end -YAML.add_ruby_type( 'object' ) { |type, val| +YAML.add_ruby_type( /^object/ ) { |type, val| type, obj_class = YAML.read_type_class( type, Object ) YAML.object_maker( obj_class, val ) } @@ -86,7 +86,7 @@ hash_proc = Proc.new { |type, val| val } YAML.add_builtin_type( 'map', &hash_proc ) -YAML.add_ruby_type( 'hash', &hash_proc ) +YAML.add_ruby_type( /^hash/, &hash_proc ) module YAML @@ -166,7 +166,7 @@ class Struct end end -YAML.add_ruby_type( 'struct' ) { |type, val| +YAML.add_ruby_type( /^struct/ ) { |type, val| if Hash === val struct_type = nil @@ -238,7 +238,7 @@ array_proc = Proc.new { |type, val| end } YAML.add_builtin_type( 'seq', &array_proc ) -YAML.add_ruby_type( 'array', &array_proc ) +YAML.add_ruby_type( /^array/, &array_proc ) # # Exception#to_yaml @@ -262,7 +262,7 @@ class Exception end end -YAML.add_ruby_type( 'exception' ) { |type, val| +YAML.add_ruby_type( /^exception/ ) { |type, val| type, obj_class = YAML.read_type_class( type, Exception ) o = YAML.object_maker( obj_class, { 'mesg' => val.delete( 'message' ) }, true ) val.each_pair { |k,v|