Jim Cain wrote:
All,
I’m working on the same problem as has been encountered in the projects
named above: It would be very handy to have a way to trap changes to an
instance variable… perhaps a callback in the same spirit as
Kernel#trace_var. To be really useful it would have to be attached to
the instance variable itself, not just to the accessor methods.
There is a problem even with this low level of control, however. Suppose
you have a reference R outside of a particular object S that you’re
interested in serializing, and that the reference R points to an object
that one of S’s instance variables points to. In other words, this is true:
R.equal?(S.iv)
How can you detect, from S, that a change to S.iv has been made through
R, without doing something like comparing the before and after
serializations of S? Would it be possible to create a callback that was
attached to the referred-to object (*R or *S.iv in C-speak), rather than
to the instance variable?
I think you should not allow anyone to modify your instance variables
without going through your accessor methods. It ruins everything that
encapsulation gives you.
With that out of the way I have heard of method:before and method:after
callbacks comming (are they in ruby 1.8?) - they would help you to
transparently test if serialization is needed. Again, this depends on
using accessor methods.
Another way to do it would be to wrap the object like I have done in the
supplied example. The idea, in this example, is to load an object as
late as possible which might save us from fetching some of your
objects from a database. Imagine fetching a large array of objects where
you in reality only need a few of those objects. This wrapper object
would postpone the loading of the object until it was needed.
– 8< –
code to test the idea of a wrapper object
class SomeObject
attr_accessor :myvar
end
class Wrapper
def method_missing(meth, *args)
if (@obj.nil?)
@obj = SomeObject.new # load the object from the database here
end
@obj.send(meth, *args)
end
end
w=Wrapper.new # SomeObject isn’t loaded yet
w.myvar = ‘hej’ # now we need the object so we load it…
p w.myvar # the loaded object is called once again
– 8< –
Using the method_missing to test if the object has changed after each
method call could solve your problem. You should be aware, tho, that
there could be a serious performance hit with this approach. Imagine a
Person object that needs a lot of changes:
p.first_name = “Anders” # update in db once first_name= has been called
p.last_name = “Borch” # update in db again
p.zip_code = 90210 # update in db again
This may not be what you really want. Rather I suggest that you have
some #checkpoint method that serializes the object, and you may want to
call that in an object finalizer.
/Anders
···
–
dc -e
4ddod3dddn1-89danrn10-dan3+ann6dan2an13dn1+dn2-dn3+5ddan2/9+an13nap