On Sep 24, 2004, at 6:07 AM, Brian Candler wrote: > If I understand rightly, I think the main constraint here is that you > want > to organise the classes logically for the user to see when selecting > one (to > create a new instance of a DimmerSwitch, for example, selecting it > from a > tree rather than a long linear scrolling list). I'd say it's one of two main constraints, and I'd expand upon it a little: 1) I want to organize the classes logically into a thought-out hierarchy, ensuring that similar classes are correctly presented to the user. 2) I want to ensure that the methods exposed by similar classes are presented to the user in a very consistent manner. In both cases, my philosophy says that I shouldn't trust authors to to the Right thing, despite any clear guidelines I might provide. They either won't read them, or where it's a matter of taste ("What's the best place for this in a hierarchy?") they'll differ from my Grand Plan. My philosophy says that I should make it hard for them to screw up, not hard for them to succeed. It's hard for many people to come up with something elegant, given a blank canvas. My goal is to define the equivalent of a layout template for a magazine page, making it easier for them to create the end product. "Just plug stuff in here, here, and here, and choose one of the existing hierarchy categories, and you're done!" Now, the implementation of these goals is not necessarily best served through the class hierarchy. For example, you're dead right-on that the namespace issue should be organized by author/manufacturer. I don't know what I was thinking, trying to place it under the hierarchy-of-devices namespace. (Well, I do know: I was yet-again confusing thoughts of namespace hierarchy with inheritance hierarchy.) module GavinKistner def author; "Gavin Kistner; end def author_url; "http://phrogz.net/"; end module Lutron def manufacturer; "Lutron"; end def manufacturer_url; "http://www.lutron.com/"; end class OnOffDimmer < Foo::Bar::Electrical::Switches::Dimmer include GavinKistner include Lutron def name; "Lutron RadioRA Dimmer"; end #... register_adaptor end end end That's what I'm leaning towards now, and it's so much cleaner than Foo::Bar::Electrical::Switches::Dimmer::LutronRadioRADimmer < Foo::Bar::Electrical::Switches::Dimmer Authors *will* be able to screw up my application, due to the gloriously dynamic nature of Ruby. It would be trivial for a stubborn author to add their own bizarre path to the classification hierarchy. (And should be allowed, as well; I am not so egotistical to imagine that my initial hierarchy will be perfect.) But I'd prefer to provide them with an existing hierarchy to drop their class into, and provide guidelines for the basic functionality they should provide. [Hrm, aside: given the need to allow authors to run arbitrary code to communicate to/from the device, is there any hope of preventing the malicious author from supplying a trojan-horse module which does nefarious things alongside a bit of benefit?] > You can always have a separate hierarchy for display purposes - or even > multiple different hierarchies, or the same class popping up in > multiple > places in the same displayed hierarchy. It doesn't have to follow a > class or > module hierarchy, and although it could, I think it will limit your > flexibility if you do. > > You might, for example, want to give one view organised by > manufacturer, and > another organised by device type. Using a single class hierarchy to classify devices will make it hard to place the objects in more than one classification hierarchy, and hard to place the same object in more than one spot in the hierarchy. I think I need to ponder fully whether or not either of these are problems, however. At the moment, I don't think they are, but I haven't really tried to categorize every sort of automation device that I can think of. However, it doesn't prevent me from creating alternate views which sort by manufacturer, author, etc. ... provided that each adaptor class exposes this information. (Yet another reason that I need to ensure that certain methods are present on every class.) > require 'homecontrol' > module ACMEwidgets > class OnOffSwitch > def self.indexcard > [Homecontrol::DevType::Switch, "ACME Widgets model 345X mains > controller"] > end > end > end Although I think there's far too much information (and too dynamic) to handle in a single 'card', this makes me think of an interesting idea, allowing multiple classification hierarchies, and placement within more than one spot in the same hierarchy: module ACMEwidgets class OnOffSwitch < Foo::Bar::Device stick_in( ByType::Electrical::Switch, ByType::Switches::Special, ByUse::Lighting::Switch ) end end class Foo::Bar::Device def self.stick_in( *classes ) classes.flatten.each{ |k| k.add_device( self ) } end end Basically, creating namespace hierarchies which aren't used for inheritance, but simply for their hierarchical classification potential. > Although really, I think that end users are not likely to be invoking > methods on their devices directly (unless they are Hal), in which case > the > GUI can take care of it. You are correct; the GUI will invoke all methods directly. However, I can't have: module Author1 class OnOffSwitch def turn_on; ...; end def turn_off; ...; end end end module Author2 class DimmerSwitch def get_jiggy; ...; end def sleepy_time; ...; end end end I "can't" have that because I'm planning on displaying exposed methods to the user via pretty_names = DimmerSwitch.instance_methods.map{ |meth_name| meth_name.gsub(/_/,' ').gsub(/\b\w/){ |c| c.upcase } } Hence my desire to specify certain methods which they must supply (methods which are reasonable for that class of device). In doing so, I both ensure that the adaptor has a bare-minimum of functionality, and that its functionality is consistent with similar adaptors. > What exactly are you > going to do if the class turns out not to have a method that you claim > is > mandatory? I guess you could write code which automatically mails the > offending module back to the author and rm's it from the filesystem! > :-) No, but in addition to throwing a warning to stdout, I very well may choose not to expose the adaptor in the GUI. "Finish the bare minimum of functionality if you want your code to be useful." Thanks for the good advice, and continuing to make me think through details. (Planning? What's that?) -- (-, /\ \/ / /\/