From: Mark H. <di...@ma...> - 2005-07-14 22:20:39
|
On Jul 14, 2005, at 2:53 PM, Dave Howell wrote: > Climb over one hill, find another behind it. I think this is mostly > a plain Ruby question, but let's see what happens. > > I have a RubyCocoa app I'm working on, a To Do list manager. I can > pass a "ToDo" task to a subclassed NSWindowManager, and voila! I > have a window with that task in it. Happy me! Make changes, make > changes, have changes written back to the task, et cetera. > > If I open a *second* window on the same task, however, they're each > writing back to the task but not aware of what the other window's > doing. Obviously (I hope?) my task needs to know what windows are > open onto it, and when it changes, it should tell them all to update. > > [Because of RubyCocoa's incomplete support for Bindings and > whatnot, I have abandoned trying to do this with CoreData. I figure > I'm probably better off learning this one the "old fashioned way," > especially since it's not really that big a project.] > > My plan is to give each task a "ViewsOfMe" array property. Whenever > a task window controller opens a window, it tells the task it did, > and when it closes, ditto. The task would tell all registered > window controllers to update whenever one of its relevant > properties is changed. > > This seemed like a good plan up to this point. > > > But my Task class starts out like this: > > attr_accessor :title, :description, :priority [8 more > symbols here....] > > I *could* just replace all this with > > def title > @title > end > def title= > @title=title > #put update windows code here > end > [repeat 10 more times] > > But that seems horribly unRubyesque. I figured I'd just modify/mix- > in/replace attr_accessor with one that also sets up the window > update triggers. OTOH, I'm absolutely mystified how to modify > attr_accessor to stick the updating code in the right spot. I > cannot find any reference for how attr actually works. I couldn't > even find a file that contained its code. One doc said it was in > "objects.c" but I can't find that either. LOL. > > Part of what makes this tricky is that I can't just add something > to attr, I have to change something it already does. > > Thoughts? Suggestions? Roll your own attr_accessor. attr_accessor is just a method: Class#attr_accessor.[1] Define one that creates methods that you want. In this case, you want instance variables set, and a hook that will let you notify observers. Here's a quick example done in irb: class Class def observable_attr(*names) # Make sure we have the right scope self.class_eval do names.each do |name| define_method name do # the getter instance_variable_get :"@#{name}" end define_method :"#{name}=" do |value| # the setter instance_variable_set :"@#{name}", value update_observers(name) end end end end end ==>nil class Foo def update_observers(name) # the hook method puts "updating observers regarding '#{name}'" end observable_attr :foo, :bar, :baz end ==>[:foo, :bar, :baz] f = Foo.new ==>#<Foo:0x121eaa0> f.foo, f.bar, f.baz = 23, 42, 93 updating observers regarding 'foo' updating observers regarding 'bar' updating observers regarding 'baz' ==>[23, 42, 93] [f.foo, f.bar, f.baz] ==>[23, 42, 93] [1] actually, it's Module#attr_accessor, but that's another story. |