[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

How to store/load persistent data?

Josef Wolf

9/4/2006 5:30:00 PM

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?

6 Answers

Logan Capaldo

9/4/2006 10:10:00 PM

0


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

> 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?

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.

> 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?
>


Josef Wolf

9/5/2006 9:41:00 PM

0

On Tue, Sep 05, 2006 at 07:10:28AM +0900, Logan Capaldo 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?

Logan Capaldo

9/5/2006 10:10:00 PM

0


On Sep 5, 2006, at 5:40 PM, Josef Wolf wrote:

>
> 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?

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.)


Tim Hunter

9/5/2006 10:18:00 PM

0

Josef Wolf wrote:
> 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?
>
>

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.

Josef Wolf

9/6/2006 4:50:00 PM

0

On Wed, Sep 06, 2006 at 07:10:18AM +0900, Logan Capaldo wrote:
> On Sep 5, 2006, at 5:40 PM, Josef Wolf wrote:

> > 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?
>
> 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.

Josef Wolf

9/6/2006 5:10:00 PM

0

On Wed, Sep 06, 2006 at 07:17:46AM +0900, Timothy Hunter wrote:
> Josef Wolf wrote:

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

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.