Is there a hook that is called whenever an instance variable is assigned?

J

Jeremy Henty

I'm developing an editing application with full undo/redo, so my
objects must log all changes to a history that can be rolled backwards
and forwards. This is just crying out for some fancy metaprogramming,
and it would be really neat if I could insert some code that is called
whenever an object assigns an instance variable. Is there anything
like that?

Regards,

Jeremy Henty
 
S

Sander Land

I'm developing an editing application with full undo/redo, so my
objects must log all changes to a history that can be rolled backwards
and forwards. This is just crying out for some fancy metaprogramming,
and it would be really neat if I could insert some code that is called
whenever an object assigns an instance variable. Is there anything
like that?

Regards,

Jeremy Henty

I'm not aware of any hooks for instance variables, but as long as
you're setting everything using setter methods or attr_accessor you
can just hook into all methods ending in a "=".

class A
attr_accessor :a, :b
instance_methods(false).each{|m|
alias_method "orig_#{m}",m
define_method(m){|*args|
puts "called #{m}"
send("orig_#{m}",*args)
} if m[-1] == ?=
}
end

o = A.new
o.a=[4, 8, 15, 16, 23] # => called a=
o.b=42 # => called b=

puts o.b # just 42, without any "called b"
 
J

Jeremy Henty

... it would be really neat if I could insert some code that is
called whenever an object assigns an instance variable. Is there
anything like that?

I'm not aware of any hooks for instance variables, but as long as
you're setting everything using setter methods or attr_accessor you
can just hook into all methods ending in a "=".

class A
attr_accessor :a, :b
instance_methods(false).each{|m|
alias_method "orig_#{m}",m
define_method(m){|*args|
puts "called #{m}"
send("orig_#{m}",*args)
} if m[-1] == ?=
}
end

Nice! My mind boggled a little over "if m[-1] == ?=" but I get it
now. I guess the industrial strength solution would be a mixin that
when included into Foo: (a) hooks all existing Foo#*= methods as you
do above, (b) defines Foo#method_added to hook all Foo#*= methods that
are subsequently def'ed, (c) defines Foo#method_missing to handle
Foo#*= methods similarly.

Of course this assumes only *= methods change the object, which is not
true of Hash, Array etc. I guess what I *really* want is an
Object#object_changed hook.

Regards,

Jeremy Henty
 
M

Max Muermann

If you grep through the mailing list for "Observing changes in object
state" you'll find two different solutions to the problem - longish
posts, so I won't repeat them here.

Cheers,
Max
 
J

Jeremy Henty

If you grep through the mailing list for "Observing changes in
object state" you'll find two different solutions to the problem -

Thanks. Will do.

Jeremy Henty
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top