summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Patterson <aaron.patterson@gmail.com>2012-01-17 17:45:07 -0800
committerAaron Patterson <aaron.patterson@gmail.com>2012-01-17 17:45:07 -0800
commit59ecddb311265d4dc9e2ddec7122509c8526afc6 (patch)
treefda19857dce7329d9843df7cd870596a43b2c2d2
parent33ce8650bac29190dde937b1b7d3e21fd06926e7 (diff)
downloadpsych-59ecddb311265d4dc9e2ddec7122509c8526afc6.zip
syncing with ruby trunk
-rw-r--r--ext/psych/emitter.c2
-rw-r--r--lib/psych/visitors/to_ruby.rb16
-rw-r--r--lib/psych/visitors/yaml_tree.rb43
-rw-r--r--test/psych/test_array.rb28
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)