From 8f84ad0fc711a82a1040def861cb121e8985fd4c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 8 Jan 2015 14:02:01 -0800 Subject: * ext/psych/lib/psych/visitors/to_ruby.rb: revive hashes with ivars * ext/psych/lib/psych/visitors/yaml_tree.rb: dump hashes with ivars. Fixes github.com/psych/issues/43 * test/psych/test_hash.rb: test for change fixes #43 --- CHANGELOG.rdoc | 9 +++++++++ lib/psych/visitors/to_ruby.rb | 14 +++++++++++++ lib/psych/visitors/yaml_tree.rb | 45 +++++++++++++++++++++++++++++++++-------- test/psych/test_hash.rb | 16 +++++++++++++++ 4 files changed, 76 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.rdoc b/CHANGELOG.rdoc index c6f13c2..5cd3227 100644 --- a/CHANGELOG.rdoc +++ b/CHANGELOG.rdoc @@ -1,3 +1,12 @@ +Fri Jan 9 06:58:43 2015 Aaron Patterson + + * ext/psych/lib/psych/visitors/to_ruby.rb: revive hashes with ivars + + * ext/psych/lib/psych/visitors/yaml_tree.rb: dump hashes with ivars. + Fixes github.com/psych/issues/43 + + * test/psych/test_hash.rb: test for change + Sun Nov 23 13:11:24 2014 Sean Griffin * lib/psych/visitors/to_ruby.rb: Allow loading any BasicObject that diff --git a/lib/psych/visitors/to_ruby.rb b/lib/psych/visitors/to_ruby.rb index e696ebd..adf38a2 100644 --- a/lib/psych/visitors/to_ruby.rb +++ b/lib/psych/visitors/to_ruby.rb @@ -261,6 +261,20 @@ module Psych end set + when /^!ruby\/hash-with-ivars(?::(.*))?$/ + hash = $1 ? resolve_class($1).new : {} + o.children.each_slice(2) do |key, value| + case key.value + when 'elements' + revive_hash hash, value + when 'ivars' + value.children.each_slice(2) do |k,v| + hash.instance_variable_set accept(k), accept(v) + end + end + end + hash + when /^!map:(.*)$/, /^!ruby\/hash:(.*)$/ revive_hash register(o, resolve_class($1).new), o diff --git a/lib/psych/visitors/yaml_tree.rb b/lib/psych/visitors/yaml_tree.rb index 989e1f0..bedf9d3 100644 --- a/lib/psych/visitors/yaml_tree.rb +++ b/lib/psych/visitors/yaml_tree.rb @@ -367,17 +367,46 @@ module Psych end def visit_Hash o - tag = o.class == ::Hash ? nil : "!ruby/hash:#{o.class}" - implicit = !tag + ivars = o.instance_variables - register(o, @emitter.start_mapping(nil, tag, implicit, Psych::Nodes::Mapping::BLOCK)) + if ivars.any? + tag = "!ruby/hash-with-ivars" + tag << ":#{o.class}" unless o.class == ::Hash - o.each do |k,v| - accept k - accept v - end + register(o, @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK)) - @emitter.end_mapping + @emitter.scalar 'elements', nil, nil, true, false, Nodes::Scalar::ANY + + @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK + o.each do |k,v| + accept k + accept v + end + @emitter.end_mapping + + @emitter.scalar 'ivars', nil, nil, true, false, Nodes::Scalar::ANY + + @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK + o.instance_variables.each do |ivar| + accept ivar + accept o.instance_variable_get ivar + end + @emitter.end_mapping + + @emitter.end_mapping + else + tag = o.class == ::Hash ? nil : "!ruby/hash:#{o.class}" + implicit = !tag + + register(o, @emitter.start_mapping(nil, tag, implicit, Psych::Nodes::Mapping::BLOCK)) + + o.each do |k,v| + accept k + accept v + end + + @emitter.end_mapping + end end def visit_Psych_Set o diff --git a/test/psych/test_hash.rb b/test/psych/test_hash.rb index 264a471..8d7ba1b 100644 --- a/test/psych/test_hash.rb +++ b/test/psych/test_hash.rb @@ -10,6 +10,22 @@ module Psych @hash = { :a => 'b' } end + def test_hash_with_ivars + @hash.instance_variable_set :@foo, 'bar' + dup = Psych.load Psych.dump @hash + assert_equal 'bar', dup.instance_variable_get(:@foo) + end + + def test_hash_subclass_with_ivars + x = X.new + x[:a] = 'b' + x.instance_variable_set :@foo, 'bar' + dup = Psych.load Psych.dump x + assert_cycle x + assert_equal 'bar', dup.instance_variable_get(:@foo) + assert_equal X, dup.class + end + def test_load_with_class_syck_compatibility hash = Psych.load "--- !ruby/object:Hash\n:user_id: 7\n:username: Lucas\n" assert_equal({ user_id: 7, username: 'Lucas'}, hash) -- cgit v1.2.3