Here is what I ended up doing:
(1) In the class app/lib/foo.rb, i added a static method to require the appropriate files
def self.load_foos
Dir["#{Rails.root}/app/lib/foos/*_foo.rb"].each do |file|
require file
end
end
(2) in foo.rb, I added a static method so that subclasses could register themselves
def self.register
if @@subclasses.include?( self.registration_symbol )
raise FooExceptionSymbolAlreadyUsed, "symbol [#{self.registration_symbol}] is already in use."
end
@@subclasses[self.registration_symbol] = [self.registration_priority,self]
end
(3) I created a directory at app/lib/foos where in I put the various subclasses of foo and named them this_foo.rb and that_foo.rb.
(4) In the subclass app/lib/foos/this_foo.rb, I added the following
class Foos::ThisFoo < Foo
def self.registration_symbol
:this
end
def self.registration_priority
100
end
# other methods removed to make example easier to read
register
end
(5) I added a config/initializers/load_foos.rb which simply had
Foo::load_foos
Any subclass of Foo that I put in app/lib/foos/ and name correctly, will automatically be loaded at startup. Each subclass overrides and implements the methods for registration_symbol and registration_priority (the priority is used later to sort an enumeration) and the symbol is used in a create method.
Thus, I can publish a spec to my developers that shows them which methods of Foo to implement in their subclasses and how to register it and where to save it and then the Rails application will automatically load those files on the next startup.