Doing fixups after deserializing YAML

M

Matthew Westcott

Hi,
Suppose (for reasons best known to myself) I had the following code:

require 'yaml'

class Squarer
attr_reader :num, :num_squared

def initialize(num)
@num = num
@num_squared = num * num
end

def to_yaml_properties
# no need to store both num and num_squared...
%w{ @num }
end
end

s = Squarer.new(42)
yaml_s = YAML.dump(s)

new_s = YAML.load(yaml_s)
puts "new_s.num = #{new_s.num}"
puts "new_s.num_squared = #{new_s.num_squared}"


Is there any way I can hook up a bit of fixup code to set @num_squared
appropriately after deserializing from YAML? If I were using Marshal,
I'd just override the marshal_load method - what (if anything) is the
YAML equivalent?

- Matthew
 
L

Logan Capaldo

Hi,
Suppose (for reasons best known to myself) I had the following code:
=20
require 'yaml'
=20
class Squarer
attr_reader :num, :num_squared
=20
def initialize(num)
@num =3D num
@num_squared =3D num * num
end
=20
def to_yaml_properties
# no need to store both num and num_squared...
%w{ @num }
end
end
=20
s =3D Squarer.new(42)
yaml_s =3D YAML.dump(s)
=20
new_s =3D YAML.load(yaml_s)
puts "new_s.num =3D #{new_s.num}"
puts "new_s.num_squared =3D #{new_s.num_squared}"
=20
=20
Is there any way I can hook up a bit of fixup code to set @num_squared
appropriately after deserializing from YAML? If I were using Marshal,
I'd just override the marshal_load method - what (if anything) is the
YAML equivalent?
=20
- Matthew
=20
=20

Well this solution doesn't involve yaml but...

class Squarer
def num_squared
@num_squared ||=3D @num * @num
end
end

So it will calculate it only the first time you ask for it.
 
M

Matthew Westcott

[serialising / deserialising a Squarer object to YAML without writing
the @num_squared variable]
Well this solution doesn't involve yaml but...

class Squarer
def num_squared
@num_squared ||= @num * @num
end
end

So it will calculate it only the first time you ask for it.

Hi,
Thanks very much for the suggestion - as you might expect, though, the
example I gave was drastically simplified from the real-life problem I
was stuck on. In that situation, it just wasn't feasible to eliminate
all redundant internal state from the object itself - but I rather
wanted to eliminate it from the object's YAML representation, at least.

In the end I found the bit of documentation I was after
<http://yaml4r.sourceforge.net/doc/page/type_families.htm> , and arrived
at this solution:

require 'yaml'

class Squarer
attr_reader :num, :num_squared

def initialize(num)
@num = num
@num_squared = num * num
end

def to_yaml_type
# register this as a custom type
"!west.co.tt,2005-05-24/squarer"
end

def to_yaml_properties
%w{ @num }
end
end

# tell the YAML parser how to deal with an object of this type
YAML.add_domain_type( "west.co.tt,2005-05-24", "squarer" ) { |type, val|
# val is a hash of all the fields we serialised (i.e. just @num)
Squarer.new(val['num'])

# here we'd do any more initialisation of the object
# if necessary
}
 

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

No members online now.

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,117
Latest member
Matilda564
Top