[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Marshalling cyclic data structures

elbows

10/31/2003 6:00:00 PM

I need to marshal and load cyclic data structures, and I need to write
custom marshalling routines because not all the fields of these
structures can be saved.

The default marshalling routines work fine on cyclic data, but when I
write my own, they go into an infinite loop.

Here is some simplified code that demonstrates the problem:

class Cons
def Cons._load(str)
hash = Marshal.load(str)
c = Cons.new()
c.value = hash["value"]
c.rest = hash["rest"]

return c
end

def _dump(depth)
return Marshal.dump({"value" => @value, "rest" => @rest})
end

attr_accessor :value, :rest
end

first = Cons.new
second = Cons.new

first.rest = second
second.rest = first

Marshal.dump(first)


This will hang on the call to Marshal.dump. Is the a simple way to
make this work?

Nathan
5 Answers

ts

11/1/2003 1:23:00 PM

0

>>>>> "N" == Nathan Weston <elbows@spamcop.net> writes:

N> I need to marshal and load cyclic data structures, and I need to write
N> custom marshalling routines because not all the fields of these
N> structures can be saved.

If you have a recent version of ruby you can use #marshal_load and
#marshal_dump, something like

svg% cat b.rb
#!/usr/bin/ruby -v
class Cons
def marshal_load(hash)
@value = hash["value"]
@rest = hash["rest"]
end

def marshal_dump
{"value" => @value, "rest" => @rest}
end

attr_accessor :value, :rest
end

first = Cons.new
first.value = 12
second = Cons.new
second.value = 24

first.rest = second
second.rest = first

c = Marshal.load(Marshal.dump(first))

p first
p c
svg%

svg% b.rb
ruby 1.8.0 (2003-08-04) [i686-linux]
#<Cons:0x400999e4 @value=12, @rest=#<Cons:0x400998cc @value=24, @rest=#<Cons:0x400999e4 ...>>>
#<Cons:0x400997f0 @value=12, @rest=#<Cons:0x400997a0 @value=24, @rest=#<Cons:0x400997f0 ...>>>
svg%


--

Guy Decoux

daz

11/2/2003 9:35:00 AM

0


"ts" <decoux@moulon.inra.fr> wrote:
> >>>>> "N" == Nathan Weston <elbows@spamcop.net> writes:
>
> N>[...] not all the fields of these structures can be saved.
>

Playing with your code example, Guy, I supplied a proc as an
example of a structure which Marshal doesn't serialize:

second.value = proc {'X'}

which produces ...

C:/TEMP/rb7005.TMP:31:in `dump': class Proc needs to have instance method `marshal_dump' (TypeError)

OK. After extending Proc, this code ...

xxx% cat b.rb
#!/usr/bin/ruby -v
class Cons
def marshal_load(hash)
@value = hash["value"]
@rest = hash["rest"]
end

def marshal_dump
{"value" => @value, "rest" => @rest}
end

attr_accessor :value, :rest
end

class Proc
def marshal_load(dummy)
nil
end
def marshal_dump
""
end
end

first = Cons.new
first.value = 12
second = Cons.new
second.value = proc {'X'}

first.rest = second
second.rest = first

c = Marshal.load(Marshal.dump(first))

p first
p c
xxx%


.... produces ...

C:/TEMP/rb7005.TMP:32:in `load': allocator undefined for Proc (NoMethodError)

Now I don't understand what it's asking for.

<ri>
----------------------------------------------------------------- Class#allocate
aClass.allocate -> anObject
--------------------------------------------------------------------------------
Allocates space for a new object of aClass's class. The returned object
must be an instance of aClass.
</ri>

(Blindly adding Proc#allocate - new to me - didn't change the error message.)

[class Proc]
def allocate
Proc.new {nil}
end
[end]


Thanks for any illumination,


daz
--
ruby 1.8.0 (2003-08-30) [i586-bccwin32]




ts

11/2/2003 11:18:00 AM

0

>>>>> "d" == daz <dooby@d10.karoo.co.uk> writes:

d> C:/TEMP/rb7005.TMP:32:in `load': allocator undefined for Proc
^^^^^^^^^

it want an allocator which can be defined only at C level (if I'm right).

d> (Blindly adding Proc#allocate - new to me - didn't change the error
d> message.)

Normally this is Proc::allocate (singleton method) but this is not really
the same, for example

svg% cat b.rb
#!/usr/bin/ruby

class A
def self.allocate
print "allocate "
super
end

def self.new
print "new "
super
end
end

p A.allocate
p A.new
svg%

svg% b.rb
allocate #<A:0x40099e6c>
new #<A:0x40099e30>
svg%

the first time is call A::allocate which call Object::allocate which
internally call an allocator

the second time the method A::new call internally the allocator and not
the method A::allocate

In your case, Proc has undefined its allocator


--

Guy Decoux

ts

11/2/2003 11:21:00 AM

0

>>>>> "t" == ts <decoux@moulon.inra.fr> writes:

t> the first time is call A::allocate which call Object::allocate which
^^^^^^^^^^^^^^^^
well in reality this is Class#allocate

sorry,

t> internally call an allocator


--

Guy Decoux

elbows

11/3/2003 3:08:00 AM

0

Thanks, that was exactly what I needed.

Nathan

ts <decoux@moulon.inra.fr> wrote in message news:<rfcllr0w7dp.fsf@moulon.inra.fr>...
> >>>>> "N" == Nathan Weston <elbows@spamcop.net> writes:
>
> N> I need to marshal and load cyclic data structures, and I need to write
> N> custom marshalling routines because not all the fields of these
> N> structures can be saved.
>
> If you have a recent version of ruby you can use #marshal_load and
> #marshal_dump, something like
>
> svg% cat b.rb
> #!/usr/bin/ruby -v
> class Cons
> def marshal_load(hash)
> @value = hash["value"]
> @rest = hash["rest"]
> end
>
> def marshal_dump
> {"value" => @value, "rest" => @rest}
> end
>
> attr_accessor :value, :rest
> end
>
> first = Cons.new
> first.value = 12
> second = Cons.new
> second.value = 24
>
> first.rest = second
> second.rest = first
>
> c = Marshal.load(Marshal.dump(first))
>
> p first
> p c
> svg%
>
> svg% b.rb
> ruby 1.8.0 (2003-08-04) [i686-linux]
> #<Cons:0x400999e4 @value=12, @rest=#<Cons:0x400998cc @value=24, @rest=#<Cons:0x400999e4 ...>>>
> #<Cons:0x400997f0 @value=12, @rest=#<Cons:0x400997a0 @value=24, @rest=#<Cons:0x400997f0 ...>>>
> svg%