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
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.
[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
}