From: Dave H. <gr...@gr...> - 2005-07-14 21:54:18
|
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? |
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. |
From: Dave H. <gr...@gr...> - 2005-07-15 03:25:35
|
On Jul 14, 2005, at 15:20, Mark Hubbart wrote: > > Roll your own attr_accessor. Well, yes, but that was my point. I hadn't the faintest how to do that. I find symbols still quite mysterious. Looking at your example, I see I'm going to have to go read up on .class_eval, define_method, and instance_variable, all of which I didn't even know I was looking for. :) But that sure looks like exactly what I wanted to know. Thanks! |
From: Tom C. <ta...@ca...> - 2005-07-15 12:14:09
|
Hello Dave On 15 Jul 2005, at 04:25, Dave Howell wrote: > Well, yes, but that was my point. I hadn't the faintest how to do > that. I find symbols still quite mysterious. I find it easiest to think of symbols as strings that never change. You can often use a string in place of a symbol (attr_accessor "title" works the same as attr_accessor :title) but symbols are one character less, and send a signal to anyone reading your code that the string is for internal use only (ie it won't be shown on the screen to the user). > Looking at your example, I see I'm going to have to go read up > on .class_eval, define_method, and instance_variable, all of which > I didn't even know I was looking for. :) But that sure looks like > exactly what I wanted to know. Thanks! You may also want to look at the Observer class that is built into ruby http://www.ruby-doc.org/stdlib/libdoc/observer/rdoc/index.html which reduces the code you need to type a bit. Tom |
From: Dave H. <gr...@gr...> - 2005-07-22 20:34:56
|
On Jul 15, 2005, at 5:13, Tom Counsell wrote: > I find it easiest to think of symbols as strings that never change. Say, that's good. I like that. By the way, it works perfectly. :) :) |