[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Detecting when an object's instance variables are modified

Paul Murton

8/27/2006 8:40:00 PM

Hi,

I have a whole load of objects which I would like to periodically dump
as YAML. However, in order to save on resources, I would prefer to only
dump those whose instance variables have changed since the last dump.

Is it possible to somehow 'mark' an object when the value any of its
instance variables is changed?

Thanks for any help :)

--
Posted via http://www.ruby-....

7 Answers

David Vallner

8/27/2006 9:03:00 PM

0

Paul Murton wrote:
> I have a whole load of objects which I would like to periodically dump
> as YAML. However, in order to save on resources, I would prefer to only
> dump those whose instance variables have changed since the last dump.
>
> Is it possible to somehow 'mark' an object when the value any of its
> instance variables is changed?
>

For the more "magical" way, you could play around with set_trace_func to
monitor setters. Would probably be horribly, terribly slow.

It's probably best to have your objects trace changes by design. Modify
the Object class to have a #dirty? and #clean! method, and alias /
redefine the #attr_writer method to generate methods that will set the
dirty flag when used?

David Vallner



dblack

8/27/2006 9:07:00 PM

0

Paul Murton

8/27/2006 9:38:00 PM

0

unknown wrote:
> Hi --
>
> On Mon, 28 Aug 2006, David Vallner wrote:
>
>> monitor setters. Would probably be horribly, terribly slow.
>>
>> It's probably best to have your objects trace changes by design. Modify the
>> Object class to have a #dirty? and #clean! method, and alias / redefine the
>> #attr_writer method to generate methods that will set the dirty flag when
>> used?
>
> I was thinking of something similar, but using Observable -- but the
> problem is that it would only work for instance variable changes that
> go through attr_writer.
>
>
> David

I appreciate all of the help so far. I had considered the possibility of
redefining attr_writer, but had hoped there might be a way of doing this
so that it would work for changes that DON'T go through attr_writer.

In fact this is actually quite important to me, because I am interested
in changes to ANY instance variable (including if a previously
non-existant instance variable is set), not just those made externally
accessible with a writer method. I should have been more clear about
this in my original post.

I've been thinking about this for ages now and my current thoughts are
that there may not be any way of getting quite what I want here :/

Any further suggestions appreciated

--
Posted via http://www.ruby-....

dblack

8/27/2006 9:41:00 PM

0

Trans

8/27/2006 10:38:00 PM

0


Paul Murton wrote:
> Hi,
>
> I have a whole load of objects which I would like to periodically dump
> as YAML. However, in order to save on resources, I would prefer to only
> dump those whose instance variables have changed since the last dump.
>
> Is it possible to somehow 'mark' an object when the value any of its
> instance variables is changed?

You can take a snapshot of the object and then do a comparsion later to
determine what's changes. Facets has snapshot.rb (which came orignially
from Michael Neumann's Wee) if you'd like to try it:

http://facets.rubyforge.org/api/more/classes/Sna...

Hmm... a #snapshot_compare method might make a good addition.

T.

Alex Fenton

8/27/2006 10:52:00 PM

0

Paul Murton wrote:
> Hi,
>
> I have a whole load of objects which I would like to periodically dump
> as YAML. However, in order to save on resources, I would prefer to only
> dump those whose instance variables have changed since the last dump.

If you're interested in knowing whether instance variables have changed since a known point in the past (eg when you last dumped the object), rather than the moment they change, something like this might work:

module InstanceVariableSnapshooter
def clean!
@__snapshot__ = ivar_hash
end

def clean?
ivar_hash == @__snapshot__
end

def dirty?
not clean?
end

private
def ivar_hash
instance_variables.inject({}) do | iv_hash, i_var |
next iv_hash if i_var == '@__snapshot__'
iv_hash[i_var] = instance_variable_get(i_var)
iv_hash
end
end
end


Call clean! when the object is dumped to file, then call dirty? later to see if anything has changed. It's probably better to work via setter methods if you can, but this works direct with the variables.

Also, test whether this is less expensive than the dumping operation you're trying to avoid

alex

Logan Capaldo

8/28/2006 5:48:00 AM

0


On Aug 27, 2006, at 5:37 PM, Paul Murton wrote:

> unknown wrote:
>> Hi --
>>
>> On Mon, 28 Aug 2006, David Vallner wrote:
>>
>>> monitor setters. Would probably be horribly, terribly slow.
>>>
>>> It's probably best to have your objects trace changes by design.
>>> Modify the
>>> Object class to have a #dirty? and #clean! method, and alias /
>>> redefine the
>>> #attr_writer method to generate methods that will set the dirty
>>> flag when
>>> used?
>>
>> I was thinking of something similar, but using Observable -- but the
>> problem is that it would only work for instance variable changes that
>> go through attr_writer.
>>
>>
>> David
>
> I appreciate all of the help so far. I had considered the
> possibility of
> redefining attr_writer, but had hoped there might be a way of doing
> this
> so that it would work for changes that DON'T go through attr_writer.
>
> In fact this is actually quite important to me, because I am
> interested
> in changes to ANY instance variable (including if a previously
> non-existant instance variable is set), not just those made externally
> accessible with a writer method. I should have been more clear about
> this in my original post.
>
> I've been thinking about this for ages now and my current thoughts are
> that there may not be any way of getting quite what I want here :/
>
> Any further suggestions appreciated
>

class A
# all method definitions here
...

instance_methods(false).each do |m|
m_obj = instance_method(m)
define_method(m) do |*args|
before = instance_variables.inject({}) { |h,k| h[k] =
instance_variable_get(k); h }
res = m_obj.bind(self).call(*args)
after = instance_variables.inject({}) { |h,k| h[k] =
instance_variable_get(k); h }
return res
end
end
end

Salt and season to taste. (Note that the granularity is at the method
level, not per statement, I'm assuming that's acceptable enough).

> --
> Posted via http://www.ruby-....
>