Skip to content

Commit

Permalink
fix incorrect deserialization of some legacy formats
Browse files Browse the repository at this point in the history
```
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"
```
  • Loading branch information
atogata committed Dec 20, 2022
1 parent 26ea134 commit b0a934b
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 8 deletions.
17 changes: 9 additions & 8 deletions lib/ostruct.rb
Original file line number Diff line number Diff line change
Expand Up @@ -435,9 +435,10 @@ 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

# ensure data isn't corrupted on reload if it looks like the legacy format
if @table.size == 1 && @table.key?(:table) || @table.size == 2 && [:modifiable, :table].all? { |x| @table.key?(x) }
coder['legacy_support!'] = true # add a bogus entry to change the size
end
end

Expand All @@ -446,12 +447,12 @@ def encode_with(coder) # :nodoc:
#
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

# support for legacy format
if h.size == 1 && h.key?('table') || h.size == 2 && %w[modifiable table].all? { |x| h.key?(x) }
h = h['table']
end

update_to_values!(h)
end

Expand Down
9 changes: 9 additions & 0 deletions test/ostruct/test_ostruct.rb
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,15 @@ def test_legacy_yaml
assert_equal({foo: 42}, YAML.safe_load(YAML.dump(o), permitted_classes: [Symbol, OpenStruct]).table)
end if RUBY_VERSION >= '2.6'

def test_legacy_yaml_2
s = "--- !ruby/object:OpenStruct\ntable:\n :foo: 42\nmodifiable: true\n"
o = YAML.safe_load(s, permitted_classes: [Symbol, OpenStruct])
assert_equal(42, o.foo)

o = OpenStruct.new(table: {foo: 42})
assert_equal({foo: 42}, YAML.safe_load(YAML.dump(o), permitted_classes: [Symbol, OpenStruct]).table)
end if RUBY_VERSION >= '2.6'

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"
Expand Down

0 comments on commit b0a934b

Please sign in to comment.