diff --git a/ChangeLog b/ChangeLog index fc224f9a4a..a35bed3372 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Wed Jan 18 12:49:15 2012 Aaron Patterson + + * ext/psych/lib/psych/visitors/to_ruby.rb: Added support for loading + subclasses of String with ivars + * ext/psych/lib/psych/visitors/yaml_tree.rb: Added support for dumping + subclasses of String with ivars + * test/psych/test_string.rb: corresponding tests + Wed Jan 18 10:39:47 2012 Aaron Patterson * ext/psych/lib/psych/visitors/to_ruby.rb: Added ability to load array diff --git a/ext/psych/lib/psych/visitors/to_ruby.rb b/ext/psych/lib/psych/visitors/to_ruby.rb index bb29c8b52d..3db67a3698 100644 --- a/ext/psych/lib/psych/visitors/to_ruby.rb +++ b/ext/psych/lib/psych/visitors/to_ruby.rb @@ -50,8 +50,13 @@ module Psych case o.tag when '!binary', 'tag:yaml.org,2002:binary' o.value.unpack('m').first - when '!str', 'tag:yaml.org,2002:str' - o.value + when /^!(?:str|ruby\/string)(?::(.*))?/, 'tag:yaml.org,2002:str' + klass = resolve_class($1) + if klass + klass.allocate.replace o.value + else + o.value + end when '!ruby/object:BigDecimal' require 'bigdecimal' BigDecimal._load o.value @@ -136,9 +141,16 @@ module Psych return revive_hash({}, o) unless o.tag case o.tag - when '!str', 'tag:yaml.org,2002:str' + when /^!(?:str|ruby\/string)(?::(.*))?/, 'tag:yaml.org,2002:str' + klass = resolve_class($1) members = Hash[*o.children.map { |c| accept c }] string = members.delete 'str' + + if klass + string = klass.allocate + string.replace string + end + init_with(string, members.map { |k,v| [k.to_s.sub(/^@/, ''),v] }, o) when /^!ruby\/array:(.*)$/ klass = resolve_class($1) diff --git a/ext/psych/lib/psych/visitors/yaml_tree.rb b/ext/psych/lib/psych/visitors/yaml_tree.rb index 1e22501ad4..80af0466eb 100644 --- a/ext/psych/lib/psych/visitors/yaml_tree.rb +++ b/ext/psych/lib/psych/visitors/yaml_tree.rb @@ -245,9 +245,15 @@ module Psych ivars = find_ivars o if ivars.empty? + unless o.class == ::String + tag = "!ruby/string:#{o.class}" + end @emitter.scalar str, nil, tag, plain, quote, style else - @emitter.start_mapping nil, '!str', false, Nodes::Mapping::BLOCK + maptag = '!ruby/string' + maptag << ":#{o.class}" unless o.class == ::String + + @emitter.start_mapping nil, maptag, false, Nodes::Mapping::BLOCK @emitter.scalar 'str', nil, nil, true, false, Nodes::Scalar::ANY @emitter.scalar str, nil, tag, plain, quote, style diff --git a/test/psych/test_string.rb b/test/psych/test_string.rb index cffc12163b..c7d5c60623 100644 --- a/test/psych/test_string.rb +++ b/test/psych/test_string.rb @@ -2,6 +2,31 @@ require 'psych/helper' module Psych class TestString < TestCase + class X < String + end + + class Y < String + attr_accessor :val + end + + def test_backwards_with_syck + x = Psych.load "--- !str:#{X.name} foo\n\n" + assert_equal X, x.class + assert_equal 'foo', x + end + + def test_empty_subclass + assert_match "!ruby/string:#{X}", Psych.dump(X.new) + x = Psych.load Psych.dump X.new + assert_equal X, x.class + 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_string_with_base_60 yaml = Psych.dump '01:03:05' assert_match "'01:03:05'", yaml