[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Marshal.dump fails on extended OpenStruct

synergism

2/17/2009 6:31:00 PM

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')
4 Answers

Justin Collins

2/17/2009 8:33:00 PM

0

synergism wrote:
> 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


Justin Collins

2/17/2009 8:52:00 PM

0

Justin Collins wrote:
> synergism wrote:
>> 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')
>>
>>
>
>
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 Collins

2/17/2009 8:57:00 PM

0

Justin Collins wrote:
> Justin Collins wrote:
>> synergism wrote:
>>> 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')
>>>
>>>
>>
>>
> 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

synergism

2/19/2009 11:21:00 AM

0

On Feb 17, 4:32 pm, Justin Collins <justincoll...@ucla.edu> 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