[ruby/ostruct] Improved YAML serialization.

Patch adapted from Pietro Monteiro [Fixes bug#8382]
This commit is contained in:
Marc-Andre Lafortune 2020-09-26 01:27:23 -04:00 коммит произвёл Marc-André Lafortune
Родитель 0e93118c44
Коммит b36a45c05c
4 изменённых файлов: 52 добавлений и 1 удалений

Просмотреть файл

@ -275,6 +275,7 @@ Outstanding ones only.
* 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

Просмотреть файл

@ -398,6 +398,33 @@ class OpenStruct
@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}!"

Просмотреть файл

@ -37,7 +37,9 @@ describe "YAML.dump" do
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

Просмотреть файл

@ -1,6 +1,7 @@
# 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
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