Forum: Ruby Marshal.dump fails on extended OpenStruct

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
synergism (Guest)
on 2009-02-17 20:40
(Received via mailing list)
If I subclass OpenStruct and extend the subclass, I cannot
Marshal.dump it.  This is apparently because ostruct.rb has its own
custom marshal_dump / marshal_load that only cares about what's in
@table:

  def marshal_dump
    @table
  end
  def marshal_load(x)
    @table = x
    @table.each_key{|key| new_ostruct_member(key)}
  end

Is there no way to fix this in ostruct.rb to allow my 'bad' example
below to work?

require 'pp'
require 'ostruct'

case ARGV.first
    when /bad/i,nil
        class C < OpenStruct
            def initialize
                super()
                @var=123
            end
        end
    when /good/i
        class C
            def initialize
                @struct=OpenStruct.new
                @var=123
            end

            def method_missing method,*args,&block
                @struct.send method,*args,&block
            end
        end
end

c=C.new
c.a=:a
pp c
puts 'c.a=%s ' %  c.a
puts 'c var=%s' % c.instance_variable_get('@var')
x=Marshal.load(Marshal.dump(c))

pp x
puts 'x.a=%s ' %  x.a
puts 'x var=%s' % x.instance_variable_get('@var')
Justin C. (Guest)
on 2009-02-17 22:33
(Received via mailing list)
synergism wrote:
>     @table.each_key{|key| new_ostruct_member(key)}
>         class C < OpenStruct
>             end
> puts 'c.a=%s ' %  c.a
> puts 'c var=%s' % c.instance_variable_get('@var')
> x=Marshal.load(Marshal.dump(c))
>
> pp x
> puts 'x.a=%s ' %  x.a
> puts 'x var=%s' % x.instance_variable_get('@var')
>
>


You could just write new marshal_dump and marshal_load methods:

require 'ostruct'
require 'pp'
class C < OpenStruct

  def initialize *args
    super
    @var = 123
  end

  def marshal_dump
    [@table, Hash[self.instance_variables.map { |v| [v,
self.instance_variable_get("#{v}")] }]]
  end

  def marshal_load x
    @table = x[0]
    @table.each_key{|key| new_ostruct_member(key)}
    x[1].each do |k,v|
      self.instance_variable_set("#{k}", v) unless k.to_sym == :table
    end
  end
end

c=C.new
c.a=:a
pp c
puts 'c.a=%s ' %  c.a
puts 'c var=%s' % c.instance_variable_get('@var')
x=Marshal.load(Marshal.dump(c))

pp x
puts 'x.a=%s ' %  x.a
puts 'x var=%s' % x.instance_variable_get('@var')



-Justin
Justin C. (Guest)
on 2009-02-17 22:53
(Received via mailing list)
Justin C. wrote:
>>     @table = x
>>     when /bad/i,nil
>>                 @var=123
>> pp c
>
Let me try that again:

require 'ostruct'
require 'pp'

class C < OpenStruct

  def initialize *args
    super
   @var = 123
  end
  def marshal_dump
    [@table, Hash[self.instance_variables.map { |v| [v,
self.instance_variable_get("#{v}")] }]]
  end
  def marshal_load x
    @table = x[0]
    @table.each_key{|key| new_ostruct_member(key)}
    x[1].each do |k,v|
      self.instance_variable_set("#{k}", v) unless k.to_sym == :table
    end
  end
end

c=C.new
c.a=:a
pp c
puts 'c.a=%s ' %  c.a
puts 'c var=%s' % c.instance_variable_get('@var')
x=Marshal.load(Marshal.dump(c))

pp x
puts 'x.a=%s ' %  x.a
puts 'x var=%s' % x.instance_variable_get('@var')
Justin C. (Guest)
on 2009-02-17 22:58
(Received via mailing list)
Justin C. wrote:
>>>   def marshal_load(x)
>>> case ARGV.first
>>>                 @struct=OpenStruct.new
>>> c.a=:a
>>
>   @var = 123
> end
> puts 'x var=%s' % x.instance_variable_get('@var')
>

I give up. I don't know why the formatting is all weird.

-Justin
synergism (Guest)
on 2009-02-19 13:27
(Received via mailing list)
On Feb 17, 4:32 pm, Justin C. <removed_email_address@domain.invalid> wrote:
> You could just write new marshal_dump and marshal_load methods:

Thanks.  I considered that, but the bigger issue is that this makes
using DRb in any application of non-trivial complexity quite painful,
as we now need to mess with the implementation details of every
serialized object.  I was just hoping something more transparent could
be done with ostruct to make things better.

Incidentally, I continued with the delegation model I used in my
example and found that this wasn't where the trouble ended.  I had to
also eliminate an un-dumpable proc I had used to auto-initialize a
Hash of Hashes (to make an empty hash be the default value so that []
[] references would not raise an exception on uninitialized keys) i.e.

class AutoHash < Hash
    def [] key
        _=fetch(key) rescue _=store(key,{})
        _
    end
end

class C
    def initialize
        # ...
        @attributes=AutoHash.new
    end
end

instead of:

        # ...
        @attributes=Hash.new{|hash,key| hash[key]={}}

It seems programming with DRb is fraught with difficulties like
these.  I wish we had something easier to use, as otherwise DRb is
exactly what we need for this application.

Ben
This topic is locked and can not be replied to.