module Puppet
class ConstantAlreadyDefined < Error; end
class SubclassAlreadyDefined < Error; end
end
module Puppet::Util::ClassGen
include Puppet::Util::MetaID
include Puppet::Util::MethodHelper
include Puppet::Util
# Create a new subclass. Valid options are:
# * :array: An array of existing classes. If specified, the new
# class is added to this array.
# * :attributes: A hash of attributes to set before the block is
# evaluated.
# * :block: The block to evaluate in the context of the class.
# You can also just pass the block normally, but it will still be evaluated
# with class_eval.
# * :constant: What to set the constant as. Defaults to the
# capitalized name.
# * :hash: A hash of existing classes. If specified, the new
# class is added to this hash, and it is also used for overwrite tests.
# * :overwrite: Whether to overwrite an existing class.
# * :parent: The parent class for the generated class. Defaults to
# self.
# * :prefix: The constant prefix. Default to nothing; if specified,
# the capitalized name is appended and the result is set as the constant.
def genclass(name, options = {}, &block)
options = symbolize_options(options)
parent = options[:parent] || self
name = symbolize(name.to_s.downcase)
# Create the class, with the correct name.
klass = Class.new(parent) do
@name = name
end
unless const = options[:constant]
prefix = options[:prefix] || ""
const = prefix + name2const(name)
end
if const_defined? const
if options[:overwrite]
Puppet.info "Redefining %s subclass %s" % [parent, name]
remove_const(const)
else
raise Puppet::ConstantAlreadyDefined,
"Class %s is already defined in %s" % [const, parent]
end
end
const_set(const, klass)
# Initialize any necessary variables.
if klass.respond_to? :initvars
klass.initvars
end
if attrs = options[:attributes]
attrs.each do |param, value|
method = param.to_s + "="
if klass.respond_to? method
klass.send(method, value)
end
end
end
block ||= options[:block]
# Evaluate the passed block if there is one. This should usually
# define all of the work.
if block
klass.class_eval(&block)
end
# If we were told to stick it in a hash, then do so
if hash = options[:hash]
if hash.include? name and ! options[:overwrite]
raise SubclassAlreadyDefined,
"Already a generated class named %s" % name
end
hash[name] = klass
end
# If we were told to stick it in a hash, then do so
if array = options[:array]
if (klass.respond_to? :name and
array.find { |c| c.name == name } and
! options[:overwrite])
raise SubclassAlreadyDefined,
"Already a generated class named %s" % name
end
array << klass
end
return klass
end
# Remove an existing class
def rmclass(name, options)
options = symbolize_options(options)
const = name2const(name)
retval = false
if const_defined? const
remove_const(const)
retval = true
end
if hash = options[:hash] and hash.include? name
hash.delete(name)
retval = true
end
# Let them know whether we did actually delete a subclass.
return retval
end
private
def name2const(name)
name.to_s.capitalize
end
end
# $Id$