# A module for loading subclasses into an array and retrieving
# them by name. Also sets up a method for each class so
# that you can just do Klass.subclass, rather than Klass.subclass(:subclass).
#
# This module is currently used by network handlers and clients.
module Puppet::Util::SubclassLoader
attr_accessor :loader, :classloader
# Iterate over each of the subclasses.
def each
@subclasses ||= []
@subclasses.each { |c| yield c }
end
# The hook method that sets up subclass loading. We need the name
# of the method to create and the path in which to look for them.
def handle_subclasses(name, path)
unless self.is_a?(Class)
raise ArgumentError, "Must be a class to use SubclassLoader"
end
@subclasses = []
@loader = Puppet::Util::Autoload.new(self,
path, :wrap => false
)
@subclassname = name
@classloader = self
# Now create a method for retrieving these subclasses by name. Note
# that we're defining a class method here, not an instance.
meta_def(name) do |subname|
subname = subname.to_s.downcase
unless c = @subclasses.find { |c| c.name.to_s.downcase == subname }
loader.load(subname)
c = @subclasses.find { |c| c.name.to_s.downcase == subname }
# Now make the method that returns this subclass. This way we
# normally avoid the method_missing method.
if c and ! respond_to?(subname)
define_method(subname) { c }
end
end
return c
end
end
# Add a new class to our list. Note that this has to handle subclasses of
# subclasses, thus the reason we're keeping track of the @@classloader.
def inherited(sub)
@subclasses ||= []
sub.classloader = self.classloader
if self.classloader == self
@subclasses << sub
else
@classloader.inherited(sub)
end
end
# See if we can load a class.
def method_missing(method, *args)
unless self == self.classloader
super
end
return nil unless defined? @subclassname
if c = self.send(@subclassname, method)
return c
else
return nil
end
end
# Retrieve or calculate a name.
def name
unless defined? @name
@name = self.to_s.sub(/.+::/, '').intern
end
return @name
end
# Provide a list of all subclasses.
def subclasses
@loader.loadall
@subclasses.collect { |klass| klass.name }
end
end
# $Id: subclass_loader.rb 2479 2007-05-07 22:29:44Z luke $
syntax highlighted by Code2HTML, v. 0.9.1