diff options
author | Aaron Patterson <aaron.patterson@gmail.com> | 2012-01-17 17:45:07 -0800 |
---|---|---|
committer | Aaron Patterson <aaron.patterson@gmail.com> | 2012-01-17 17:45:07 -0800 |
commit | 59ecddb311265d4dc9e2ddec7122509c8526afc6 (patch) | |
tree | fda19857dce7329d9843df7cd870596a43b2c2d2 | |
parent | 33ce8650bac29190dde937b1b7d3e21fd06926e7 (diff) | |
download | psych-59ecddb311265d4dc9e2ddec7122509c8526afc6.zip |
syncing with ruby trunk
-rw-r--r-- | ext/psych/emitter.c | 2 | ||||
-rw-r--r-- | lib/psych/visitors/to_ruby.rb | 16 | ||||
-rw-r--r-- | lib/psych/visitors/yaml_tree.rb | 43 | ||||
-rw-r--r-- | test/psych/test_array.rb | 28 |
4 files changed, 85 insertions, 4 deletions
diff --git a/ext/psych/emitter.c b/ext/psych/emitter.c index a85fa45..15fdcfe 100644 --- a/ext/psych/emitter.c +++ b/ext/psych/emitter.c @@ -351,7 +351,7 @@ static VALUE start_mapping( (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValuePtr(anchor)), (yaml_char_t *)(NIL_P(tag) ? NULL : StringValuePtr(tag)), implicit ? 1 : 0, - (yaml_sequence_style_t)NUM2INT(style) + (yaml_mapping_style_t)NUM2INT(style) ); emit(emitter, &event); diff --git a/lib/psych/visitors/to_ruby.rb b/lib/psych/visitors/to_ruby.rb index bf48f9d..bb29c8b 100644 --- a/lib/psych/visitors/to_ruby.rb +++ b/lib/psych/visitors/to_ruby.rb @@ -119,6 +119,11 @@ module Psych map[accept(a.children.first)] = accept a.children.last } map + when /^!(?:seq|ruby\/array):(.*)$/ + klass = resolve_class($1) + list = register(o, klass.allocate) + o.children.each { |c| list.push accept c } + list else list = register(o, []) o.children.each { |c| list.push accept c } @@ -135,6 +140,17 @@ module Psych members = Hash[*o.children.map { |c| accept c }] string = members.delete 'str' init_with(string, members.map { |k,v| [k.to_s.sub(/^@/, ''),v] }, o) + when /^!ruby\/array:(.*)$/ + klass = resolve_class($1) + list = register(o, klass.allocate) + + members = Hash[o.children.map { |c| accept c }.each_slice(2).to_a] + list.replace members['internal'] + + members['ivars'].each do |ivar, v| + list.instance_variable_set ivar, v + end + list when /^!ruby\/struct:?(.*)?$/ klass = resolve_class($1) diff --git a/lib/psych/visitors/yaml_tree.rb b/lib/psych/visitors/yaml_tree.rb index f373966..1e22501 100644 --- a/lib/psych/visitors/yaml_tree.rb +++ b/lib/psych/visitors/yaml_tree.rb @@ -301,9 +301,13 @@ module Psych end def visit_Array o - register o, @emitter.start_sequence(nil, nil, true, Nodes::Sequence::BLOCK) - o.each { |c| accept c } - @emitter.end_sequence + if o.class == ::Array + register o, @emitter.start_sequence(nil, nil, true, Nodes::Sequence::BLOCK) + o.each { |c| accept c } + @emitter.end_sequence + else + visit_array_subclass o + end end def visit_NilClass o @@ -315,6 +319,39 @@ module Psych end private + def visit_array_subclass o + tag = "!ruby/array:#{o.class}" + if o.instance_variables.empty? + node = @emitter.start_sequence(nil, tag, false, Nodes::Sequence::BLOCK) + register o, node + o.each { |c| accept c } + @emitter.end_sequence + else + node = @emitter.start_mapping(nil, tag, false, Nodes::Sequence::BLOCK) + register o, node + + # Dump the internal list + accept 'internal' + @emitter.start_sequence(nil, nil, true, Nodes::Sequence::BLOCK) + o.each { |c| accept c } + @emitter.end_sequence + + # Dump the ivars + accept 'ivars' + @emitter.start_mapping(nil, nil, true, Nodes::Sequence::BLOCK) + o.instance_variables.each do |ivar| + accept ivar + accept o.instance_variable_get ivar + end + @emitter.end_mapping + + @emitter.end_mapping + end + end + + def dump_list o + end + # '%:z' was no defined until 1.9.3 if RUBY_VERSION < '1.9.3' def format_time time diff --git a/test/psych/test_array.rb b/test/psych/test_array.rb index ec6a1aa..9eedbb4 100644 --- a/test/psych/test_array.rb +++ b/test/psych/test_array.rb @@ -2,11 +2,39 @@ require 'psych/helper' module Psych class TestArray < TestCase + class X < Array + end + + class Y < Array + attr_accessor :val + end + def setup super @list = [{ :a => 'b' }, 'foo'] end + def test_subclass + yaml = Psych.dump X.new + assert_match X.name, yaml + + list = X.new + list << 1 + assert_equal X, list.class + assert_equal 1, list.first + end + + def test_subclass_with_attributes + y = Psych.load Psych.dump Y.new.tap {|y| y.val = 1} + assert_equal Y, y.class + assert_equal 1, y.val + end + + def test_backwards_with_syck + x = Psych.load "--- !seq:#{X.name} []\n\n" + assert_equal X, x.class + end + def test_self_referential @list << @list assert_cycle(@list) |