Question on IO objects, initialize, and yaml

Say I have a class with pseudo code as follows:
class Test
def initialize
@a=1
@b=File.open(“file+Time.now or similar”)
end
end

Now, imagine that I use this class for a while and then I want to dump
it to
a YAML file.

When I restart my code, I want it to read in stuff from the YAML file
(if it
exists) and use that as a starting point to work from (basically, I am
saving state in the yaml file). You’ll note that I cannot just do this
as
is, because reading in from YAML does not initialize the class, so @b
would
not be initialized correctly on restart.

I’d like to just initialize the thing, then read in the YAML file to
overwrite the state with the saved values. Is there some extremely
obvious
ruby way to do this or something equivalent?

Thanks,
mark

On Dec 10, 2006, at 12:19 , Mark N. wrote:

a YAML file.

When I restart my code, I want it to read in stuff from the YAML
file (if it
exists) and use that as a starting point to work from (basically, I am
saving state in the yaml file). You’ll note that I cannot just do
this as
is, because reading in from YAML does not initialize the class, so
@b would
not be initialized correctly on restart.

Ruby and YAML provide hooks to cause things to happen when you load
from Marshal or YAML. I think #initialize_copy gets called for
Marshal, I don’t know the YAML ones, but they should be easy to find.

I’d like to just initialize the thing, then read in the YAML file to
overwrite the state with the saved values. Is there some extremely
obvious
ruby way to do this or something equivalent?

Don’t do this, use the built-in hooks, that’s what they’re for.


Eric H. - [email protected] - http://blog.segment7.net

I LIT YOUR GEM ON FIRE!

I want to use a built-in hook (the ruby way, if you will), if I can
figure
out which one and how to use it.

Based on your suggestion, I’ve googled and found this code:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/104402

Now, I’ve experimented with initialize_copy on this code and your
recommendation, and I cannot get it to do what I want.

Anybody got any other suggestions, or a concrete example for me?
mark

Mark N. wrote:

a YAML file.
ruby way to do this or something equivalent?
A possible alternative is to be lazy about constructing the non-dumpable
stuff:

[~] cat test.rb
require ‘yaml’

class Test
def initialize
@a = 1
end
def b
@b ||= File.open(FILE) # just for testing
end
end

t = Test.new
t2 = YAML.load(YAML.dump(t))

line = t2.b.gets
p line

[~] ruby test.rb
"require ‘yaml’\n

If you do this, other parts of your code shouldn’t access @b directly.
Instead, call the #b method.

Joel VanderWerf wrote:

it to
I’d like to just initialize the thing, then read in the YAML file to
class Test

line = t2.b.gets
p line

[~] ruby test.rb
"require ‘yaml’\n

If you do this, other parts of your code shouldn’t access @b directly.
Instead, call the #b method.

That’s not quite right. If you use #b and then dump/load and try to use
#b on the new object, you get an error:

t = Test.new

t2 = YAML.load(YAML.dump(t))
line = t2.b.gets
p line

t3 = YAML.load(YAML.dump(t2))
line = t3.b.gets
p line

Output:

“require ‘yaml’\n”
test.rb:23:in `gets’: uninitialized stream (IOError)
from test.rb:23

You can “fix” this by adding a #to_yaml method to your class that clears
@b:

class Test
def to_yaml(*)
@b = nil
super
end
end

Then t3.b.gets doesn’t fail. But whether this “fix” is right for your
class is another question…

On Mon, Dec 11, 2006 at 02:43:22PM +0900, Mark N. wrote:

On 12/10/06, Eric H. [email protected] wrote:

Ruby and YAML provide hooks to cause things to happen when you load
from Marshal or YAML. I think #initialize_copy gets called for
Marshal, I don’t know the YAML ones, but they should be easy to find.

I want to use a built-in hook (the ruby way, if you will), if I can figure
out which one and how to use it.
[…]
Now, I’ve experimented with initialize_copy on this code and your
recommendation, and I cannot get it to do what I want.

Anybody got any other suggestions, or a concrete example for me?
mark

require ‘yaml’
class Foo
def initialize
@foo = 1
@bar = 2
end

def yaml_initialize(tag, val)
end
end

foo = Foo.new
foo # => #<Foo:0xa7dfe614 @bar=2, @foo=1>
YAML.load(YAML.dump(foo)) # => #Foo:0xa7dfa6e0

class Foo
def yaml_initialize(tag, val) # !> method redefined; discarding old
yaml_initialize
@foo, @bar = val.values_at(“foo”, “bar”)
end
end

YAML.load(YAML.dump(foo)) # => #<Foo:0xa7ddcfc8 @bar=2, @foo=1>