Hi -- On Mon, 28 Aug 2006, 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? I don't know whether this will be of practical use to you, but your question got me wanting to brush up on Observable, so I did :-) See below. It probably threads a bit too narrow a needle, but maybe it will give you some ideas. And if someone knows an existing shortcut for this, let me know :-) I also recommend looking at observable.rb, in the standard libray, just to see a great example of how powerful very simple Ruby can be. require 'observer' # A module which redefines attr_writer for classes that include it. # The direct use of @observer_peers (the list of observers) is a bit # inelegant, but I didn't want to keep adding the object watcher to # the array over and over. module AttrWriterInterceptor def self.included(m) m.class_eval do include Observable def self.attr_writer(*attrs) attrs.each do |att| define_method("#{att}=") do |value| @observer_peers ||= [] unless @observer_peers.include?(ObjectWatcher.instance) add_observer(ObjectWatcher.instance) end instance_variable_set("@#{att}", value) changed notify_observers(self) end end end end end end # A class that uses the observable attr_writers class Item include AttrWriterInterceptor attr_writer :description end # A class to observe changes. It's a singleton to make it easier # to add it as an observer (see above) without having to be passed # an instance of it. class ObjectWatcher require 'singleton' include Singleton attr_accessor :changed def initialize self.changed = true end def update(obj) self.changed = true end def dump_objects_if_changed if self.changed self.changed = false "Dumping objects!" else "Not dumping objects!" end end end if __FILE__ == $0 require 'test/unit' class ObserverTest < Test::Unit::TestCase def setup @ow = ObjectWatcher.instance @i = Item.new end # Test dumping at the beginning, then make sure the second dump # doesn't happen, then change an attr and make sure it does happen # the third time. def test_three_dumps assert(@ow.changed) assert_equal("Dumping objects!", @ow.dump_objects_if_changed) assert(!@ow.changed) assert_equal("Not dumping objects!", @ow.dump_objects_if_changed) @i.description = "Some item" assert(@ow.changed) assert_equal("Dumping objects!", @ow.dump_objects_if_changed) end end end