Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to deserialize recursively #71

Closed
wildmaples opened this issue Nov 23, 2022 · 2 comments · Fixed by #72
Closed

Unable to deserialize recursively #71

wildmaples opened this issue Nov 23, 2022 · 2 comments · Fixed by #72

Comments

@wildmaples
Copy link
Contributor

Hi there! I believe this could be similar to this open issue: #69 but I figure I'd make one for our use case.

It seems like we are unable to

irb(main):001:0> require 'recursive-open-struct'
=> true
irb(main):002:0> Marshal.load(Marshal.dump(RecursiveOpenStruct.new(red: [RecursiveOpenStruct.new]))).red
/Users/maple.ong/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/recursive-open-struct-1.1.3/lib/recursive_open_struct.rb:80:in `[]': undefined method `[]' for nil:NilClass (NoMethodError)

    elsif v.is_a?(Array) and @options[:recurse_over_arrays]
                                     ^^^^^^^^^^^^^^^^^^^^^^
	from /Users/maple.ong/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/recursive-open-struct-1.1.3/lib/recursive_open_struct.rb:142:in `block (2 levels) in new_ostruct_member'
	from (irb):2:in `<main>'
	from /Users/maple.ong/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/irb-1.4.3/exe/irb:11:in `<top (required)>'
	from /Users/maple.ong/.rbenv/versions/3.1.2/bin/irb:25:in `load'
	from /Users/maple.ong/.rbenv/versions/3.1.2/bin/irb:25:in `<main>'

We are trying to upgrade our application to Ruby 3 but we are relying on this behaviour to work. Since it is broken on the latest version we cannot upgrade.

@christhomson
Copy link

We are seeing the same problem while attempting to upgrade one of our services to Ruby 3 as well. (Thanks for posting this - great timing!)

@christhomson
Copy link

christhomson commented Nov 23, 2022

It looks like marshal_load is passed the options like recurse_over_arrays but they are just passed in at the top level and it will fallback to using OpenStruct's marshal_load implementation which will assign them in as keys in the struct rather than interpreting them as options.

Something like this may help:

class RecursiveOpenStruct
  # …

  def marshal_load(attributes)
    @options ||= {}
    @sub_elements ||= {}

    self.class.default_options.keys.each do |option|
      @options[option] = attributes.delete(option) if attributes.key?(option)
    end

    @deep_dup = DeepDup.new(@options)

    super
  end
end

Note: I have never written one of these marshal_load methods before so I'm not confident that this follows all the best practices (it almost certainly doesn't 😅). I'm not sure if it's common practice to re-do a lot of the same work that initialize typically does. This would also mean it wouldn't be possible to create a RecursiveOpenStruct that has any of the three option names as a key in the struct. Perhaps if we defined our own marshal_dump method then we could support all key names properly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants