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?)

--
(-, /\ \/ / /\/