On 09/12/2010 02:10 PM, Knut Franke wrote: > Some time ago I stumbled over Cells[1], a Common Lisp extension allowing > one > to declare relations between instance variables (called slots in CL); > i.e. a > change to one variable will automatically recompute other variables > depending > on it. I think it's pretty neat, but using it in any interesting context > is > somewhat hampered by the fact that few people go through the > considerable > trouble involved in learning Common Lisp. > > Just today it occurred to me that it should be pretty easy to do > something > similar in Ruby. Indeed, a couple of codelines later, I had a Ruby > version of > the standard Cells example (well, a simplified version) running: > > class Motor > cell :temperature, :status > def initialize > self.temperature = 0 > calculate :status do > if self.temperature< 100 > :on > else > :off > end > end > end > end > m = Motor.new > m.observe(:temperature) {|old, new| puts "temperature: #{old} -> > #{new}" } > m.observe(:status) {|old, new| puts "status: #{old} -> #{new}" } > m.temperature = 80 > m.temperature = 110 > I wrote a library called observable for use in GUI MVC programming (with FXRuby), something along those lines. One nice feature was pattern matching on the changed value, so you could have separate handlers for different ranges etc. Ruby's #=== methods are very cool and somewhat underused. That might be a nice feature to add to your #observe method. Here's the code: http://redshift.sourceforge.net/observable/ Here's my version of your example: require 'observable' # Let's just include Observable globally. Conservatively, one would do: # # class C # extend Observable # include Observable::Match # if desired # ... # end include Observable include Observable::Match class Motor observable :temperature, :status def initialize self.temperature = 0 self.status = :on when_temperature 0..100 do self.status = :on end when_temperature 100..100000 do self.status = :off end end end m = Motor.new m.when_temperature CHANGES do |new, old| puts "temperature: #{old} -> #{new}" end m.when_status CHANGES do |new, old| puts "status: #{old} -> #{new}" end m.temperature = 80 m.temperature = 110 __END__ temperature: -> 0 status: -> on temperature: 0 -> 80 temperature: 80 -> 110 status: on -> off