[前][次][番号順一覧][スレッド一覧]

ruby-changes:37107

From: tenderlove <ko1@a...>
Date: Fri, 9 Jan 2015 07:01:48 +0900 (JST)
Subject: [ruby-changes:37107] tenderlove:r49188 (trunk): * ext/psych/lib/psych/visitors/to_ruby.rb: revive hashes with ivars

tenderlove	2015-01-09 07:00:54 +0900 (Fri, 09 Jan 2015)

  New Revision: 49188

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=49188

  Log:
    * 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

  Modified files:
    trunk/ChangeLog
    trunk/ext/psych/lib/psych/visitors/to_ruby.rb
    trunk/ext/psych/lib/psych/visitors/yaml_tree.rb
    trunk/test/psych/test_hash.rb
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 49187)
+++ ChangeLog	(revision 49188)
@@ -1,3 +1,12 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Fri Jan  9 06:58:43 2015  Aaron Patterson <aaron@t...>
+
+	* 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
+
 Thu Jan  8 17:05:00 2015  Seiei Higa  <hanachin@g...>
 
 	* vm_method.c (rb_method_entry): if no super class, no original
Index: ext/psych/lib/psych/visitors/yaml_tree.rb
===================================================================
--- ext/psych/lib/psych/visitors/yaml_tree.rb	(revision 49187)
+++ ext/psych/lib/psych/visitors/yaml_tree.rb	(revision 49188)
@@ -367,17 +367,46 @@ module Psych https://github.com/ruby/ruby/blob/trunk/ext/psych/lib/psych/visitors/yaml_tree.rb#L367
       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.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
+          @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
Index: ext/psych/lib/psych/visitors/to_ruby.rb
===================================================================
--- ext/psych/lib/psych/visitors/to_ruby.rb	(revision 49187)
+++ ext/psych/lib/psych/visitors/to_ruby.rb	(revision 49188)
@@ -261,6 +261,20 @@ module Psych https://github.com/ruby/ruby/blob/trunk/ext/psych/lib/psych/visitors/to_ruby.rb#L261
           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
 
Index: test/psych/test_hash.rb
===================================================================
--- test/psych/test_hash.rb	(revision 49187)
+++ test/psych/test_hash.rb	(revision 49188)
@@ -10,6 +10,22 @@ module Psych https://github.com/ruby/ruby/blob/trunk/test/psych/test_hash.rb#L10
       @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)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]