How to store/load persistent data?

Hello!

In my previous life (in perl-world) I was used to store persistent data
with Data::Dumper and load it back with “require ‘/path/to/file’”.

Now I’m learing ruby and started my first toy-project. I must admit
that
I am not very familiar with OO techniques.

AFAICS, the ruby way to store persistent data is YAML. Saving an object
with YAML.dump() works like a charm. But I have trouble to read them
back with YAML.load(). For some reason, the initialize() method of the
loaded object doesn’t get called. I don’t understand how an object can
properly spring in existance without the initialize method? For
example,
I allocate a TkCanvas in the initialize() method. Such an object can
not
be loaded back properly, IMHO.

I have one more problem with such an object: There’s no destructor.
Should
such an object get out of scope, how do I make sure the allocated canvas
is destroyed properly?

I’m sorry if this is a stupid question, but I am new to both, ruby and
OO.
Please can somebody give an explanation how such an object is handled in
the ruby-world?

On Sep 4, 2006, at 1:30 PM, Josef W. wrote:

AFAICS, the ruby way to store persistent data is YAML. Saving an
object
with YAML.dump() works like a charm. But I have trouble to read them
back with YAML.load(). For some reason, the initialize() method of
the
loaded object doesn’t get called. I don’t understand how an object
can
properly spring in existance without the initialize method?

Well the general purpose of initialize is to set up some state /
instance variables. That’s exactly what the serialized form of the
object keeps track of anyway.

For example,
I allocate a TkCanvas in the initialize() method. Such an object
can not
be loaded back properly, IMHO.

Some things aren’t serializable in a sane way, that’s just a fact of
life.

I have one more problem with such an object: There’s no
destructor. Should
such an object get out of scope, how do I make sure the allocated
canvas
is destroyed properly?

The garbage collector makes sure that the memory used by objects that
go out of scope is reclaimed.

On Tue, Sep 05, 2006 at 07:10:28AM +0900, Logan C. wrote:
[ … ]

AFAICS, the ruby way to store persistent data is YAML. Saving an
object with YAML.dump() works like a charm. But I have trouble to
read them back with YAML.load(). For some reason, the initialize()
method of the loaded object doesn’t get called. I don’t understand
how an object can properly spring in existance without the initialize
method?

Well the general purpose of initialize is to set up some state /
instance variables. That’s exactly what the serialized form of the
object keeps track of anyway.

But what to do when an object needs some resources (this might be a
file/database opened, or, as in my case, a TkCanvas)?

For example, I allocate a TkCanvas in the initialize() method. Such
an object can not be loaded back properly, IMHO.

Some things aren’t serializable in a sane way, that’s just a fact of
life.

I understand that this is not serializable. But wouldn’t it be good
to have a chance to reconstruct a new (identical) object from the
reloaded
state/instance variables? It need not be the original initialize()
method.
It would probably be even better would YAML invoke yaml_initialize() or
something.

I have one more problem with such an object: There’s no destructor.
Should such an object get out of scope, how do I make sure the
allocated canvas is destroyed properly?

The garbage collector makes sure that the memory used by objects that
go out of scope is reclaimed.

It is clear to me that the ruby object is removed by the garbage
collector. But it is not clear what happens to other recources (a
TkCanvas in this case) allocated by this object. Check this out:

#! /usr/bin/ruby

require ‘tk’

root=TkRoot.new

class Foo
def initialize
canvas = TkCanvas.new.pack
rect = TkcRectangle.new(canvas, 0, 0, 50, 50, “fill”=>“white”)
end
end

begin
x=Foo.new()
end

GC.start

Object destroyed but canvas and rectangle are still alive

Tk.mainloop

I can’t see a solution for this problem since I am a novice for
ruby/OO/Tk.
How do you gurus handle such situations?

On Sep 5, 2006, at 5:40 PM, Josef W. wrote:

end

GC.start

Object destroyed but canvas and rectangle are still alive

Tk.mainloop

I can’t see a solution for this problem since I am a novice for
ruby/OO/Tk.
How do you gurus handle such situations?

That just means that there is still a reference to those objects.
When all the references go away, then and only then ruby will collect
them (if it needs to.)

Josef W. wrote:

class Foo
GC.start

Object destroyed but canvas and rectangle are still alive

Tk.mainloop

I can’t see a solution for this problem since I am a novice for ruby/OO/Tk.
How do you gurus handle such situations?

There is a well-known Ruby idiom for coding block-scoped resources.
There used to be a good page describing this in RubyGarden but alas that
page seems to have disappeared. Anyway, here’s the general example from
that page:

def Resource.open( identifier ) # :yield: resource
resource = Resource.new( identifier )
if block_given?
begin
yield resource
ensure
resource.close
end
else
return resource
end
end

That is, create/open/whatever the resource is and yield to a block.
Within the block use the resource. When the block returns, close/destroy
the resource. The open method in the IO class is prototypical.

On Wed, Sep 06, 2006 at 07:17:46AM +0900, Timothy H. wrote:

Josef W. wrote:

    ensure
        resource.close
    end
else
    return resource
end

end

That is, create/open/whatever the resource is and yield to a block.
Within the block use the resource. When the block returns, close/destroy
the resource. The open method in the IO class is prototypical.

I am aware of this idiom. This idiom works very well if you have a
strictly
hierachical call structure.

But I just can’t see how this can help when dealing with Tk (especially
with canvas items). In this case, objects are created and destroyed
asynchronously. The block that creates a new widget has to return
before the widget is destroyed.

Of course, with widgets like TkDialog, this idiom would work very well
since dialog->Show() blocks until the widget is destroyed. OTOH,
TkDialog
don’t need this idiom since it is already destroyed when its Show method
returns.

On Wed, Sep 06, 2006 at 07:10:18AM +0900, Logan C. wrote:

On Sep 5, 2006, at 5:40 PM, Josef W. wrote:

That just means that there is still a reference to those objects.
When all the references go away, then and only then ruby will collect
them (if it needs to.)

Exactly. The Tk library holds the references. To get rid of them, I
need to call canvas.delete(rect) for the rectangle and canvas.destroy
for the canvas. When I add those two calls, they disappear without
messing with the GC.