diff options
author | Aaron Patterson <aaron.patterson@gmail.com> | 2009-10-07 11:52:54 -0700 |
---|---|---|
committer | Aaron Patterson <aaron.patterson@gmail.com> | 2009-10-07 11:52:54 -0700 |
commit | c330b9e93fdf5eb15aea29ede9dd017c037b3942 (patch) | |
tree | f91933139de909a5addde8a39379189ade17f356 | |
parent | d3bfc7a71256f84d4ce1b7e31b032739f02dfb55 (diff) | |
download | psych-c330b9e93fdf5eb15aea29ede9dd017c037b3942.zip |
structs will round trip
-rw-r--r-- | lib/psych/ruby.rb | 3 | ||||
-rw-r--r-- | lib/psych/visitors/to_ruby.rb | 14 | ||||
-rw-r--r-- | lib/psych/visitors/yast_builder.rb | 11 | ||||
-rw-r--r-- | test/visitors/test_to_ruby.rb | 36 | ||||
-rw-r--r-- | test/visitors/test_yast_builder.rb | 12 |
5 files changed, 74 insertions, 2 deletions
diff --git a/lib/psych/ruby.rb b/lib/psych/ruby.rb index f226c84..f564565 100644 --- a/lib/psych/ruby.rb +++ b/lib/psych/ruby.rb @@ -4,8 +4,7 @@ require 'date' [ Object, String, Class, Hash, Array, NilClass, Float, FalseClass, TrueClass, - Range, Complex, Rational, Date, Time, Regexp, Exception - # Struct + Range, Complex, Rational, Date, Time, Regexp, Exception, Struct ].each do |klass| klass.send(:remove_method, :to_yaml) rescue NameError end diff --git a/lib/psych/visitors/to_ruby.rb b/lib/psych/visitors/to_ruby.rb index d00f72a..1d5bd4b 100644 --- a/lib/psych/visitors/to_ruby.rb +++ b/lib/psych/visitors/to_ruby.rb @@ -77,6 +77,20 @@ module Psych def visit_Psych_Nodes_Mapping o case o.tag + when /!ruby\/struct(:.*)?$/ + klassname = $1 + h = Hash[*o.children.map { |c| accept c }].to_a + + if klassname && klassname.length > 1 + s = klassname.sub(/^:/,'').split('::').inject(Object) { |k,o| + k.const_get(o) + }.allocate + h.each { |k,v| s.send("#{k}=", v) } + s + else + Struct.new(*h.map { |k,v| k.to_sym }).new(*h.map { |k,v| v }) + end + when '!ruby/range' h = Hash[*o.children.map { |c| accept c }] Range.new(h['begin'], h['end'], h['excl']) diff --git a/lib/psych/visitors/yast_builder.rb b/lib/psych/visitors/yast_builder.rb index 914a891..6100264 100644 --- a/lib/psych/visitors/yast_builder.rb +++ b/lib/psych/visitors/yast_builder.rb @@ -21,6 +21,17 @@ module Psych raise TypeError, "Can't dump #{target.class}" end + def visit_Struct o + tag = ['!ruby/struct', o.class.name].compact.join(':') + + @stack.push append Nodes::Mapping.new(nil, tag, false) + o.members.each do |member| + accept member + accept o[member] + end + @stack.pop + end + def visit_Exception o @stack.push append Nodes::Mapping.new(nil, '!ruby/exception', false) ['message', o.message].each do |m| diff --git a/test/visitors/test_to_ruby.rb b/test/visitors/test_to_ruby.rb index e8b7a6e..9c37690 100644 --- a/test/visitors/test_to_ruby.rb +++ b/test/visitors/test_to_ruby.rb @@ -11,6 +11,42 @@ module Psych @visitor = ToRuby.new end + A = Struct.new(:foo) + + def test_struct + s = A.new('bar') + + mapping = Nodes::Mapping.new nil, "!ruby/struct:#{s.class}" + mapping.children << Nodes::Scalar.new('foo') + mapping.children << Nodes::Scalar.new('bar') + + ruby = mapping.to_ruby + + assert_equal s.class, ruby.class + assert_equal s.foo, ruby.foo + assert_equal s, ruby + end + + def test_anon_struct_legacy + s = Struct.new(:foo).new('bar') + + mapping = Nodes::Mapping.new nil, '!ruby/struct:' + mapping.children << Nodes::Scalar.new('foo') + mapping.children << Nodes::Scalar.new('bar') + + assert_equal s.foo, mapping.to_ruby.foo + end + + def test_anon_struct + s = Struct.new(:foo).new('bar') + + mapping = Nodes::Mapping.new nil, '!ruby/struct' + mapping.children << Nodes::Scalar.new('foo') + mapping.children << Nodes::Scalar.new('bar') + + assert_equal s.foo, mapping.to_ruby.foo + end + def test_exception exc = Exception.new 'hello' diff --git a/test/visitors/test_yast_builder.rb b/test/visitors/test_yast_builder.rb index d35ff3d..4730e7d 100644 --- a/test/visitors/test_yast_builder.rb +++ b/test/visitors/test_yast_builder.rb @@ -8,6 +8,18 @@ module Psych @v = Visitors::YASTBuilder.new end + A = Struct.new(:foo) + + def test_struct + assert_round_trip A.new('bar') + end + + def test_struct_anon + s = Struct.new(:foo).new('bar') + obj = Psych.load(Psych.dump(s)) + assert_equal s.foo, obj.foo + end + def test_exception ex = Exception.new 'foo' loaded = Psych.load(Psych.dump(ex)) |