> 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.

I think it will turn out to be much simpler than the examples you have
written; there is no need to make a class hierarchy as you would in C++. In
Ruby, the concept of "class" is nowhere near as important as in C++; it's
just a convenient factory for creating objects which happen to implement the
same set of methods, at least at the time when they were created. Each
object individually can have methods added and removed dynamically, so
what's important is whether a particular object X has method Y right now,
rather than the class it came from.

So what I suggest is that you just make objects, which respond to methods
which make sense to them, in any way which is simple and convenient.

class DumbLight
  def initialize(location) ... end
  def turn_on ... end
  def turn_off ... end
end

class DimmerLight
  def initialize(location) ... end
  def turn_on ... end
  def turn_off ... end
  def level=(x) ... end
  def level ... end
end

switches = []
switches << DumbLight.new('hallway')
switches << DumbLight.new('staircase')
switches << DimmerLight.new('lounge')

If you try to send a "level=" method to a DumbLight, then you will get a
NoMethodError exception, which you can catch easily. All it's saying is,
this object doesn't know how to do that.

If it saves you work, you can make class DimmerLight a subclass of
DumbLight; but you really don't have to if it doesn't make sense to do so,
e.g. if you don't re-use any significant amount of code.

Most importantly, you really don't have to have a common ancestor class
which contains methods that most or all your objects are expected to respond
to.

> 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.

All classes are instantiable, and the methods they respond to may vary at
run-time (even after the object has been instantiated), so it usually
doesn't make sense to do this.

Just take a pool of objects representing the things you want to control and
present it to the user. If you want to have the GUI dynamically adjust
itself for each object, then you can check if the method exists for each
object before you present it:

    gui.add_button("Turn On", foo, :turn_on) if foo.respond_to?(:turn_on)
    gui.add_button("Turn Off", foo, :turn_off) if foo.respond_to?(:turn_off)

(or the objects themselves could contain code which knows how to create the
appropriate GUI controls, but personally I prefer to keep knowledge about
presentation in the GUI. After all, you could have many different types of
interface controlling the same set of objects: web, command-line, Tcl/Tk,
etc)

You can also use #arity to work out how many parameters a method takes, if
you want your GUI to present the right number of fields automatically:

  class OnOffSwitch
    def initialize(ipaddress, port)
      @addr = ipaddress
      @port = port
    end
    ...
  end

  p OnOffSwitch.instance_method(:initialize).arity
  => 2

However, in this case, it may be better to return a data structure designed
for the GUI to prompt the information. This can include a human-readable
description, a validation regexp, and perhaps a method to call to convert it
from a string into the desired format.

  class OnOffSwitch
    def self.initialize_parameters
      [
        ["IP Address", 15, /\A\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\z/, nil],
        ["Port", 5, /\A\d+\z/, :to_i],
      ]
    end
  end

  p OnOffSwitch.initialize_parameters

Equally, you can ask what methods an object has, but it probably makes sense
to return an array of methods which the user can *sensibly* call on this
object.

> Questions
> 1) Is there a way to inspect the runtime state and figure out which
> subclasses exist for a given class?

Yes, there is:
   ObjectSpace.each_object(Class) { |klass| p klass, klass.ancestors }
But usually that's not what you want to do.

> 2) Is there a better way to force/detect if a subclass implements
> certain methods?

Yes, use #respond_to?(:foo) to check if an object implements method foo,
rather than worrying about what class it is in. Or just call it anyway, and
catch the exception if it fails.

If you have a common set of methods which are shared by many objects,
consider putting them into a Module which can then be included in a class:

module OnOff
  def turn_on ... end
  def turn_off ... end
end

class DumbLight
  include OnOff
  ...
end

class DimmerLight
  include OnOff
  ...
end

as that's more flexible than straightforward class inheritance. Also you can
add the methods to individual objects:

  fishes = FishTank.new('hallway')
  fishes.extend OnOff
  # this is the only fishtank with an on/off switch

Finally, as a general point, do consider delegation rather than inheritance;
that is, object X "has_a" Y, rather than object X "is_a" Y. It often turns
out to be a far more flexible way to make objects with composite or more
'intelligent' behaviour than the base object.

  class Fishtank
    def initialize
      @light = OnOffSwitch.new
      @pump = OnOffSwitch.new
    end
    def turn_on
      @light.turn_on
      @pump.turn_on
    end
    def turn_off
      @light.turn_off
      @pump.turn_off
    end
  end

> 3) Is there a better way overall to achieve my goal?

I hope the above makes some sense :-)

Regards,

Brian.