Marshal.dump fails on extended OpenStruct

S

synergism

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')
 
J

Justin Collins

synergism said:
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')


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
 
J

Justin Collins

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')
 
J

Justin Collins

Justin said:
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')

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

-Justin
 
S

synergism

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,262
Messages
2,571,056
Members
48,769
Latest member
Clifft

Latest Threads

Top