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

ruby-changes:63228

From: Marc-Andre <ko1@a...>
Date: Thu, 1 Oct 2020 07:11:47 +0900 (JST)
Subject: [ruby-changes:63228] b36a45c05c (master): [ruby/ostruct] Improved YAML serialization.

https://git.ruby-lang.org/ruby.git/commit/?id=b36a45c05c

From b36a45c05cafc227ade3b59349482953321d6a89 Mon Sep 17 00:00:00 2001
From: Marc-Andre Lafortune <github@m...>
Date: Sat, 26 Sep 2020 01:27:23 -0400
Subject: [ruby/ostruct] Improved YAML serialization.

Patch adapted from Pietro Monteiro [Fixes bug#8382]

diff --git a/NEWS.md b/NEWS.md
index 4078f19..24abb1d 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -275,6 +275,7 @@ Outstanding ones only. https://github.com/ruby/ruby/blob/trunk/NEWS.md#L275
     * Builtin methods can now be overridden safely. [[Bug #15409]]
     * Implementation uses only methods ending with `!`.
     * Ractor compatible.
+    * Improved support for YAML [[Bug #8382]]
     * Use officially discouraged. Read "Caveats" section.
 
 * Reline
diff --git a/lib/ostruct.rb b/lib/ostruct.rb
index d2e93b1..4ecffb0 100644
--- a/lib/ostruct.rb
+++ b/lib/ostruct.rb
@@ -398,6 +398,33 @@ class OpenStruct https://github.com/ruby/ruby/blob/trunk/lib/ostruct.rb#L398
     @table.hash
   end
 
+  #
+  # Provides marshalling support for use by the YAML library.
+  #
+  def encode_with(coder) # :nodoc:
+    @table.each_pair do |key, value|
+      coder[key.to_s] = value
+    end
+    if @table.size == 1 && @table.key?(:table) # support for legacy format
+      # in the very unlikely case of a single entry called 'table'
+      coder['legacy_support!'] = true # add a bogus second entry
+    end
+  end
+
+  #
+  # Provides marshalling support for use by the YAML library.
+  #
+  def init_with(coder) # :nodoc:
+    h = coder.map
+    if h.size == 1 # support for legacy format
+      key, val = h.first
+      if key == 'table'
+        h = val
+      end
+    end
+    update_to_values!(h)
+  end
+
   # Make all public methods (builtin or our own) accessible with `!`:
   instance_methods.each do |method|
     new_name = "#{method}!"
diff --git a/spec/ruby/library/yaml/dump_spec.rb b/spec/ruby/library/yaml/dump_spec.rb
index 5af794b..9e884b0 100644
--- a/spec/ruby/library/yaml/dump_spec.rb
+++ b/spec/ruby/library/yaml/dump_spec.rb
@@ -37,7 +37,9 @@ describe "YAML.dump" do https://github.com/ruby/ruby/blob/trunk/spec/ruby/library/yaml/dump_spec.rb#L37
   it "dumps an OpenStruct" do
     require "ostruct"
     os = OpenStruct.new("age" => 20, "name" => "John")
-    YAML.dump(os).should match_yaml("--- !ruby/object:OpenStruct\ntable:\n  :age: 20\n  :name: John\n")
+    os2 = YAML.load(YAML.dump(os))
+    os2.age.should == 20
+    os2.name.should == "John"
   end
 
   it "dumps a File without any state" do
diff --git a/test/ostruct/test_ostruct.rb b/test/ostruct/test_ostruct.rb
index 5de6f27..7dd1ac6 100644
--- a/test/ostruct/test_ostruct.rb
+++ b/test/ostruct/test_ostruct.rb
@@ -1,6 +1,7 @@ https://github.com/ruby/ruby/blob/trunk/test/ostruct/test_ostruct.rb#L1
 # frozen_string_literal: true
 require 'test/unit'
 require 'ostruct'
+require 'yaml'
 
 class TC_OpenStruct < Test::Unit::TestCase
   def test_initialize
@@ -309,4 +310,24 @@ class TC_OpenStruct < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ostruct/test_ostruct.rb#L310
     end.take
     assert obj1.object_id == obj2.object_id
   end if defined?(Ractor)
+
+  def test_legacy_yaml
+    s = "--- !ruby/object:OpenStruct\ntable:\n  :foo: 42\n"
+    o = YAML.load(s)
+    assert_equal(42, o.foo)
+
+    o = OpenStruct.new(table: {foo: 42})
+    assert_equal({foo: 42}, YAML.load(YAML.dump(o)).table)
+  end
+
+  def test_yaml
+    h = {name: "John Smith", age: 70, pension: 300.42}
+    yaml = "--- !ruby/object:OpenStruct\nname: John Smith\nage: 70\npension: 300.42\n"
+    os1 = OpenStruct.new(h)
+    os2 = YAML.load(os1.to_yaml)
+    assert_equal yaml, os1.to_yaml
+    assert_equal os1, os2
+    assert_equal true, os1.eql?(os2)
+    assert_equal 300.42, os2.pension
+  end
 end
-- 
cgit v0.10.2


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

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