Skip to content

Commit 431bfe2

Browse files
committed
fix incorrect deserialization of some legacy formats
In at least some cases, the legacy format includes an additional field that needs to be considered. # ruby 2.6.10p210 (2022-04-12 revision 67958) [universal.x86_64-darwin22] require "ostruct" require "yaml" os = OpenStruct.new os.a = 'b' YAML.dump(os) # => "--- !ruby/object:OpenStruct\ntable:\n 🅰️ b\nmodifiable: true\n"
1 parent 26ea134 commit 431bfe2

File tree

2 files changed

+18
-8
lines changed

2 files changed

+18
-8
lines changed

lib/ostruct.rb

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -435,9 +435,10 @@ def encode_with(coder) # :nodoc:
435435
@table.each_pair do |key, value|
436436
coder[key.to_s] = value
437437
end
438-
if @table.size == 1 && @table.key?(:table) # support for legacy format
439-
# in the very unlikely case of a single entry called 'table'
440-
coder['legacy_support!'] = true # add a bogus second entry
438+
439+
# ensure data isn't corrupted on reload if it looks like the legacy format
440+
if @table.size == 1 && @table.key?(:table) || @table.size == 2 && [:modifiable, :table].all? { |x| @table.key?(x) }
441+
coder['legacy_support!'] = true # add a bogus entry to change the size
441442
end
442443
end
443444

@@ -446,12 +447,12 @@ def encode_with(coder) # :nodoc:
446447
#
447448
def init_with(coder) # :nodoc:
448449
h = coder.map
449-
if h.size == 1 # support for legacy format
450-
key, val = h.first
451-
if key == 'table'
452-
h = val
453-
end
450+
451+
# support for legacy format
452+
if h.size == 1 && h.key?('table') || h.size == 2 && %w[modifiable table].all? { |x| h.key?(x) }
453+
h = h['table']
454454
end
455+
455456
update_to_values!(h)
456457
end
457458

test/ostruct/test_ostruct.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,15 @@ def test_legacy_yaml
390390
assert_equal({foo: 42}, YAML.safe_load(YAML.dump(o), permitted_classes: [Symbol, OpenStruct]).table)
391391
end if RUBY_VERSION >= '2.6'
392392

393+
def test_legacy_yaml_2
394+
s = "--- !ruby/object:OpenStruct\ntable:\n :foo: 42\nmodifiable: true\n"
395+
o = YAML.safe_load(s, permitted_classes: [Symbol, OpenStruct])
396+
assert_equal(42, o.foo)
397+
398+
o = OpenStruct.new(table: {foo: 42})
399+
assert_equal({foo: 42}, YAML.safe_load(YAML.dump(o), permitted_classes: [Symbol, OpenStruct]).table)
400+
end if RUBY_VERSION >= '2.6'
401+
393402
def test_yaml
394403
h = {name: "John Smith", age: 70, pension: 300.42}
395404
yaml = "--- !ruby/object:OpenStruct\nname: John Smith\nage: 70\npension: 300.42\n"

0 commit comments

Comments
 (0)