Inherited Data

Background:
As part of the home automation core I'm writing, I need a way to have introspection on methods which are exposed to the UI by various author-created 'plugins'. I've created the majority of the code for describing methods, but one problem is preventing me from continuing, and I'd appreciate your input:

Summary:
How would you store information about a class, which exposes that information in an inherited manner that matches the inheritance hierarchy of the class?

Details:
Consider the following simple case:

require 'DescribeMethods.rb'
class LightSwitch
  def turn_on
    #...
  end
  def turn_off
    #...
  end
  describe_method :turn_on, "Turn the switch on"
  describe_method :turn_off, "Turn the switch off"
end

class Dimmer < LightSwitch
  def set_level( n )
    #...
  end
  describe_method :set_level, "Set the brightness level of the light", ...
end

I'd like to be able to know that a Dimmer instance has three methods which are described. How should I do it?

a) Require the user to copy/paste descriptions from ancestor classes into the child?

b) Copy the methods from an ancestor class into the storage for the subclass when it is inherited? (Failing to add new methods if they're later described in the parent and duplicating storage.)

c) Store each method in a collection for that class, and every time I inspect the described methods for a class, iterate up the #superclass tree and look at ancestors?

d) Store the description as a custom property in the method itself?

e) ???

···

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

I forgot to add: I also need it to be able to support the 'inheritance hierarchy' that comes when using mixing to extend a class.

So the previous example I gave really needs to be extended (no pun indended) to more accurately reflect what I'm trying to do. In the following code excerpt, I'd like to be able to later list all methods described for the GavinKistner::Lutron::RadioRADimmer class, including those described in the Automatron::Adaptor::Electrical::Switches class and those described in GavinKistner::Lutron module.

require 'DescribeMethods.rb'
class Automatron::Adaptor
  self.extend( DescribeMethods )
    self.mandatory_methods = :name, :manufacturer, :models,
    :adaptor_author, :adaptor_url, :adaptor_version, :unique_id

    class Electrical < self
      self.mandatory_methods = :on?, :on=, :turn_on, :turn_off, :toggle
      class Switches < self
      describe_method :turn_on, "Turn the switch on"
      describe_method :turn_off, "Turn the switch off"
      #...
        class Dimmers < self
          self.mandatory_methods = :level=, :level
        describe_method :level, "Returns the brightness level of the light"
        describe_method :"level=", "Set the brightness level of the light", ...
        end
      end
    end
end

#In an author-supplied Adaptor 'plugin'
module GavinKistner
  module Lutron
    self.extend( DescribeMethods )
    def turn_on; ...; end #implementation of required method
    def turn_off; ...; end #implementation of required method
    def set_scheme( new_scheme )
      #...
    end
    describe_method :set_scheme, "Set the lighting scheme used", ...
    
    #...
    module Dimmers
      def level; ...; end
      def level=(n); ...; end
    end
    class RadioRADimmer < Automatron::Adaptor::Electrical::Switches::Dimmers
      include GavinKistner
      include Lutron
      include Dimmers
      def unique_id; ...; end #implementation of required method
    end
  end
end

···

On Nov 21, 2004, at 3:05 PM, Gavin Kistner wrote:

Summary:
How would you store information about a class, which exposes that information in an inherited manner that matches the inheritance hierarchy of the class?

Gavin Kistner wrote:

Summary:
How would you store information about a class, which exposes that information in an inherited manner that matches the inheritance hierarchy of the class?

I forgot to add: I also need it to be able to support the 'inheritance hierarchy' that comes when using mixing to extend a class.

You could do it with constants. So, instead of your original example:

     class LightSwitch
         def turn_on
             #...
         end
         def turn_off
             #...
         end
         describe_method :turn_on, "Turn the switch on"
         describe_method :turn_off, "Turn the switch off"
     end

     class Dimmer < LightSwitch
         def set_level( n )
             #...
         end
         describe_method :set_level, "Set the brightness level"
     end

You might use a naming scheme like the following (to avoid conflicts):

     class LightSwitch
         def turn_on
             #...
         end
         def turn_off
             #...
         end
         DESCRIBE_METHOD_turn_on = "Turn the switch on"
         DESCRIBE_METHOD_turn_off = "Turn the switch off"
     end

     class Dimmer < LightSwitch
         def set_level( n )
             #...
         end
         DESCRIBE_METHOD_set_level = "Set the brightness level"
     end

That approach handles inheritance, and works fine with modules, but you have to use const_get (or eval) to look up method descriptions given a method name. You could even make the interface look like describe_method() using const_set. Another option is to use a data structure that provides some kind of inheritance. I wrote superhash (see RAA) to do just that. There is some sugar called "class_superhash" that is almost what you want, but it doesn't deal with module inclusion. Could be adapted to do so, though.

···

On Nov 21, 2004, at 3:05 PM, Gavin Kistner wrote: