Skip to content

Commit b0a934b

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 b0a934b

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)