# Observing changes in object state

**URL:** <https://www.ruby-forum.com/t/observing-changes-in-object-state/66241>\
**Category:** Ruby\
**Created:** [August 24, 2006, 7:47am UTC](https://www.ruby-forum.com/t/observing-changes-in-object-state/66241 "2006-08-24T07:47:14Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![fangheuschrecke](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/58956e/32.png) [@fangheuschrecke](https://www.ruby-forum.com/u/fangheuschrecke)\
**Post date:** [August 24, 2006, 7:47am UTC](https://www.ruby-forum.com/t/observing-changes-in-object-state/66241/1 "2006-08-24T07:47:14Z")

</div>

Hi all,

I was playing around with the observer library and thought I’d  
reimplement somthing I had done in Java a while back. It uses the  
observer pattern but automatically adds interceptors to every  
attribute setter method - once on the first include and then  
dynamically as more setter methods are added. If anybody has some  
comments or hints on how to implement this in a better way, I’d be  
delighted to hear them.

You can do this:

require ‘state\_observer’

# Model to be watched for attribute changes

class Model  
attr\_accessor :name

include StateObserver

def id  
return @id  
end

def id= nid  
@id = nid  
end  
end

# Observer

class Watcher  
def update( name, value )  
p “#{name} set to #{value}”  
end  
end

# change some stuff

m = Model.new  
m.add\_observer Watcher.new  
m.id=‘000’  
m.name=‘test’  
m.id=‘000’

# add an attribute

class Model  
attr\_accessor :new\_attribute  
end

# change the atttribute

m.new\_attribute=“new”

Output:

“id set to 000”  
“name set to test”  
“new\_attribute set to new”

StateObserver is implemented thus:

require ‘observer’  
module StateObserver  
include Observable

# hacky bits - see RDoc for define\_method for explanation

def StateObserver.create\_method(target, name, &block)  
target.send(:define\_method, name, &block)  
end

def StateObserver.store\_method(target, new\_name, old\_name)  
target.send(:alias\_method, new\_name, old\_name)  
end

# end hacky bits

def StateObserver.method\_interceptor\_block  
lambda do |target, method\_name|  
# intercept new methods ending with ‘=’  
if method\_name.to\_s =~ /[a-zA-Z0-9\_]=$/  
# alias this method to allow method redefinition  
return if @skip  
# prevent hooking a setter twice, in case it is redefined in a  
subclass or similar  
return if respond\_to? “**#{method\_name}"  
 @skip = true  
# alias the method  
store\_method( target, "**#{method\_name}”, method\_name)  
create\_method(target, method\_name) do |arg|  
# save current value  
attr\_name = method\_name.to\_s.chop  
old = send(attr\_name)  
# call original method to set new value  
self.send("\_\_#{method\_name}", arg)  
# set observer changed flag if value is different  
changed if arg != old  
# call the observer hook  
notify\_observers( attr\_name, arg )  
end  
@skip = nil  
end  
end  
end

def StateObserver.included( othermod )  
# intercept existing setter methods  
othermod.public\_instance\_methods.each do |method\_name|  
StateObserver.method\_interceptor\_block.call othermod, method\_name  
end

```
# intercept setters defined in the future
create_method(othermod.class, :method_added) do |method_name|
  StateObserver.method_interceptor_block.call othermod, method_name
end

```

end  
end

Cheers,  
Max

---

<div class="post-metadata">

**Author:** ![fangheuschrecke](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/58956e/32.png) [@fangheuschrecke](https://www.ruby-forum.com/u/fangheuschrecke)\
**Post date:** [August 24, 2006, 9:06pm UTC](https://www.ruby-forum.com/t/observing-changes-in-object-state/66241/2 "2006-08-24T21:06:59Z")

</div>

Max M. wrote:

> Hi all,
> 
> I was playing around with the observer library and thought I’d  
> reimplement somthing I had done in Java a while back. It uses the  
> observer pattern but automatically adds interceptors to every  
> attribute setter method - once on the first include and then  
> dynamically as more setter methods are added. If anybody has some  
> comments or hints on how to implement this in a better way, I’d be  
> delighted to hear them.

Here’s a somewhat different approach, but it might be interesting to  
compare:

require ‘observable’ # see [http://raa.ruby-lang.org/project/observable/](http://raa.ruby-lang.org/project/observable/)

class Model  
extend Observable  
attr\_accessor :id # avoid confusion with Object#id  
observable :name, :id  
end

# Observer

class Watcher  
def initialize m  
m.when\_name Object do  
puts “name set to #{m.name.inspect}”  
end

```
 m.when_id Object do
   puts "id set to #{m.id.inspect}"
 end
 # note that each method is treated separately

```

end  
end

# change some stuff

m = Model.new  
Watcher.new m  
m.id=‘000’  
m.name=‘test’  
m.id=‘000’

# note this does not trigger the observer since value

# doesn’t change. Use the “signal” mechanism from the

# observable lib for that behavior

**END**

Output:

name set to nil  
id set to nil  
id set to “000”  
name set to “test”

---

<div class="post-metadata">

**Author:** ![fangheuschrecke](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/58956e/32.png) [@fangheuschrecke](https://www.ruby-forum.com/u/fangheuschrecke)\
**Post date:** [August 25, 2006, 12:07am UTC](https://www.ruby-forum.com/t/observing-changes-in-object-state/66241/3 "2006-08-25T00:07:23Z")

</div>

> ```
> end
> # note that each method is treated separately
> 
> ```

Yes, this is probably the most widely useful approach. I have found  
that sometimes, though, you want to be notified if _any_ of the state  
in an object changes. For example, checking an model object for  
“dirty” and enabling a save button or similar. In those cases, I think  
a generic solution that does not explicitly require defining a watcher  
method on each attribute may be useful.

By the way, thanks for bringing this up - I wasn’t aware of the  
observable :field notation.

Cheers,  
Max

---

<div class="post-metadata">

**Author:** ![fangheuschrecke](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/58956e/32.png) [@fangheuschrecke](https://www.ruby-forum.com/u/fangheuschrecke)\
**Post date:** [August 25, 2006, 12:57am UTC](https://www.ruby-forum.com/t/observing-changes-in-object-state/66241/4 "2006-08-25T00:57:29Z")

</div>

Max M. wrote:

> > ```
> > end
> > # note that each method is treated separately
> > 
> > ```
> 
> Yes, this is probably the most widely useful approach. I have found  
> that sometimes, though, you want to be notified if _any_ of the state  
> in an object changes. For example, checking an model object for  
> “dirty” and enabling a save button or similar. In those cases, I think  
> a generic solution that does not explicitly require defining a watcher  
> method on each attribute may be useful.

That’s a good point, though I think I would handle it with a #dirty  
method that gets called from within some of the when\_ clauses, since  
there are often attributes whose state is not saved.

> By the way, thanks for bringing this up - I wasn’t aware of the  
> observable :field notation.

It’s not a general ruby notation, just something defined in this one  
library.

---

<div class="post-metadata">

**Author:** ![fangheuschrecke](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/58956e/32.png) [@fangheuschrecke](https://www.ruby-forum.com/u/fangheuschrecke)\
**Post date:** [August 25, 2006, 3:33am UTC](https://www.ruby-forum.com/t/observing-changes-in-object-state/66241/5 "2006-08-25T03:33:40Z")

</div>

> > By the way, thanks for bringing this up - I wasn’t aware of the  
> > observable :field notation.
> 
> It’s not a general ruby notation, just something defined in this one  
> library.
> 
> –  
> vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Am aware of that - sorry for the sloppy language.

Max
