Summary
I'm looking for advice on how to design code so that I can dynamically add/remove instantiable classes, where each of these classes have values for a set of properties defined by a parent class.
Details
I'm starting to design/write an uber-ambitious home automation hub, in Ruby. In addition to having convenient things like a web-based GUI front-end, scheduler, and so on, the heart of this application is that it will (eventually) work with any automation hardware whose communication protocol is open (or reverse-engineered).
The plan is to have 'adaptors' for each discrete hardware type, which encapsulate all the guts of the communication protocol and expose methods for that bit of hardware. The user can then 'instantiate' one or more of these adaptors, representing physical instances of that bit of hardware in the home.
(For example, there's a single "Lutron RadioRA Wall Dimmer" adaptor, but the user may have 4 such switches in the house, named "Front Kitchen Lights", "Rear Kitchen Lights", "Bedroom Lights", and "Entry Lights".)
In addition to custom methods, each adaptor needs to expose some common information, such as its name, manufacturer, category, sub-category, model number, and so on.
I initially decided to have code like this:
me = Foo::Bar::DeviceType.new( 'Lutron RadioRA Wall Dimmer', :Lutron, :Switches, :Dimmers, 'RA-ND6' )
me.add_action( :turn_on, Proc.new{ ... } )
me.add_action( :turn_off, Proc.new{ ... } )
me.add_action( :level=, Proc.new{ ... } )
me.add_action( :level, Proc.new{ ... } )
#...and then later do something like...
Foo::Bar::add_device( 'Entry Lights', blah )
# ...where blah is a pointer to the DeviceType instance
But then I realized that I'm mostly just putting a wrapper around a class definition. Further, I realized that I want all adaptors to support common methods (name, manufacturer, model number), all light switches to support some common methods (turn_on, turn_off), and all dimmers to support others still (level= and level). This reeks of a class hierarchy, so I was thinking that I might do something like:
# Core app
class Foo::Bar::DeviceType
def name; raise "Implement Me!"; end
def manufacturer; raise "Implement Me!"; end
def model; raise "Implement Me!"; end
class Light
def turn_on; raise "Implement Me!"; end
def turn_off; raise "Implement Me!"; end
class Dimmer
def level=(n); raise "Implement Me!"; end
def level; raise "Implement Me!"; end
end
end
end
#Adaptor file
class Foo::Bar::DeviceType::Light::Dimmer::RadioRA
def name; 'Lutron RadioRA Wall Dimmer'; end
def manufacturer; 'Lutron'; end
def name; 'RA-ND6'; end
def turn_on; ...; end;
def turn_off; ...; end;
def level=(n); ...; end;
def level; ...; end;
Foo::Bar::DeviceType::add_device( self )
end
... and the add_device method would
a) Create a dummy parent class and run through all the methods to see if they throw errors.
b) Add the class into a list of instantiable adaptors if it works.
Questions
1) Is there a way to inspect the runtime state and figure out which subclasses exist for a given class?
2) Is there a better way to force/detect if a subclass implements certain methods?
3) Is there a better way overall to achieve my goal?
Thanks if you even read this far. Thanks even more if you take the time to think about the problem and offer suggestions.
···
--
(-, /\ \/ / /\/