From 2d2271d457c09554881c91313d4ccc610d85e17c Mon Sep 17 00:00:00 2001 From: Maple Ong Date: Wed, 23 Nov 2022 21:48:53 -0500 Subject: [PATCH 1/3] Save info when dumped and loaded by Marshal Previously, ROS did not play well when being dump and loaded with Marshal because the options from ROS did not translate through the serialization. This change saves the information through marshal_dump and then reassigns the information to ROS instance when the object is loaded. --- lib/recursive_open_struct.rb | 8 ++++++++ spec/recursive_open_struct/recursion_spec.rb | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/lib/recursive_open_struct.rb b/lib/recursive_open_struct.rb index 184e5ef..cc27199 100644 --- a/lib/recursive_open_struct.rb +++ b/lib/recursive_open_struct.rb @@ -39,6 +39,14 @@ def initialize(hash=nil, passed_options={}) @sub_elements = {} end + def marshal_load(attributes) + hash, @options, @sub_elements = attributes + super(hash) + end + + def marshal_dump + [super, @options, @sub_elements] + end if OpenStruct.public_instance_methods.include?(:initialize_copy) def initialize_copy(orig) diff --git a/spec/recursive_open_struct/recursion_spec.rb b/spec/recursive_open_struct/recursion_spec.rb index 3fb99c7..4b094d5 100644 --- a/spec/recursive_open_struct/recursion_spec.rb +++ b/spec/recursive_open_struct/recursion_spec.rb @@ -37,6 +37,14 @@ expect(ros.blah.changed).to eql 'backing' end + it "handles being dump then loaded by Marshal" do + foo_struct = [RecursiveOpenStruct.new] + bar_struct = RecursiveOpenStruct.new(foo: foo_struct) + serialized = Marshal.dump(bar_struct) + + expect(Marshal.load(serialized).foo).to eq(foo_struct) + end + describe "handling loops in the original Hashes" do let(:h1) { { :a => 'a'} } let(:h2) { { :a => 'b', :h1 => h1 } } @@ -182,6 +190,17 @@ let(:blah_list) { [ { :foo => '1' }, { :foo => '2' }, 'baz' ] } let(:h) { { :blah => blah_list } } + context "when dump and loaded by Marshal" do + let(:test) { RecursiveOpenStruct.new(h, :recurse_over_arrays => true) } + subject { Marshal.load(Marshal.dump(test))} + + it { expect(subject.blah.length).to eq 3 } + it { expect(subject.blah[0].foo).to eq '1' } + it { expect(subject.blah[1].foo).to eq '2' } + it { expect(subject.blah_as_a_hash).to eq blah_list } + it { expect(subject.blah[2]).to eq 'baz' } + end + context "when recursing over arrays is enabled" do subject { RecursiveOpenStruct.new(h, :recurse_over_arrays => true) } From e33e1ec40ad49299ad9b9b0b4ed144e7cf3fec5c Mon Sep 17 00:00:00 2001 From: Maple Ong Date: Mon, 28 Nov 2022 10:12:25 -0500 Subject: [PATCH 2/3] Remove @sub_elements from serialization as it's a cache We can recreate the hash at load. --- lib/recursive_open_struct.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/recursive_open_struct.rb b/lib/recursive_open_struct.rb index cc27199..683f9db 100644 --- a/lib/recursive_open_struct.rb +++ b/lib/recursive_open_struct.rb @@ -40,12 +40,13 @@ def initialize(hash=nil, passed_options={}) end def marshal_load(attributes) - hash, @options, @sub_elements = attributes + hash, @options = attributes + @sub_elements = {} super(hash) end def marshal_dump - [super, @options, @sub_elements] + [super, @options] end if OpenStruct.public_instance_methods.include?(:initialize_copy) From fbd482de044c0ca6485c0e1eac1ba19efae3181c Mon Sep 17 00:00:00 2001 From: Maple Ong Date: Mon, 28 Nov 2022 10:12:55 -0500 Subject: [PATCH 3/3] Add missing @deep_dup --- lib/recursive_open_struct.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/recursive_open_struct.rb b/lib/recursive_open_struct.rb index 683f9db..debbeab 100644 --- a/lib/recursive_open_struct.rb +++ b/lib/recursive_open_struct.rb @@ -41,6 +41,7 @@ def initialize(hash=nil, passed_options={}) def marshal_load(attributes) hash, @options = attributes + @deep_dup = DeepDup.new(@options) @sub_elements = {} super(hash) end