From: Joel VanderWerf Date: 2006-12-12T05:29:32+09:00 Subject: Re: Question on IO objects, initialize, and yaml Joel VanderWerf wrote: > Mark Noworolski wrote: >> 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? > > 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. > 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... -- vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407