summaryrefslogtreecommitdiffstats
path: root/lib/puppet
diff options
context:
space:
mode:
Diffstat (limited to 'lib/puppet')
-rw-r--r--lib/puppet/parser/ast.rb3
-rw-r--r--lib/puppet/parser/ast/definition.rb207
-rw-r--r--lib/puppet/parser/ast/hostclass.rb95
-rw-r--r--lib/puppet/parser/ast/leaf.rb24
-rw-r--r--lib/puppet/parser/ast/node.rb42
-rw-r--r--lib/puppet/parser/ast/resource_reference.rb4
-rw-r--r--lib/puppet/parser/compiler.rb8
-rw-r--r--lib/puppet/parser/loaded_code.rb55
-rw-r--r--lib/puppet/parser/parser_support.rb133
-rw-r--r--lib/puppet/parser/resource_type.rb235
-rw-r--r--lib/puppet/util/rdoc/parser.rb6
11 files changed, 294 insertions, 518 deletions
diff --git a/lib/puppet/parser/ast.rb b/lib/puppet/parser/ast.rb
index ad8af7496..feceb60e0 100644
--- a/lib/puppet/parser/ast.rb
+++ b/lib/puppet/parser/ast.rb
@@ -99,15 +99,12 @@ require 'puppet/parser/ast/casestatement'
require 'puppet/parser/ast/collection'
require 'puppet/parser/ast/collexpr'
require 'puppet/parser/ast/comparison_operator'
-require 'puppet/parser/ast/definition'
require 'puppet/parser/ast/else'
require 'puppet/parser/ast/function'
-require 'puppet/parser/ast/hostclass'
require 'puppet/parser/ast/ifstatement'
require 'puppet/parser/ast/leaf'
require 'puppet/parser/ast/match_operator'
require 'puppet/parser/ast/minus'
-require 'puppet/parser/ast/node'
require 'puppet/parser/ast/nop'
require 'puppet/parser/ast/not'
require 'puppet/parser/ast/resource'
diff --git a/lib/puppet/parser/ast/definition.rb b/lib/puppet/parser/ast/definition.rb
deleted file mode 100644
index 00b0416a0..000000000
--- a/lib/puppet/parser/ast/definition.rb
+++ /dev/null
@@ -1,207 +0,0 @@
-require 'puppet/parser/ast/branch'
-
-require 'puppet/util/warnings'
-
-# The AST class for defined types, which is also the base class
-# nodes and classes.
-class Puppet::Parser::AST::Definition < Puppet::Parser::AST::Branch
- include Puppet::Util::Warnings
- class << self
- attr_accessor :name
- end
-
- associates_doc
-
- # The class name
- @name = :definition
-
- attr_accessor :classname, :arguments, :code, :scope, :keyword
- attr_accessor :exported, :namespace, :parser, :virtual, :name
-
- attr_reader :parentclass
-
- def child_of?(klass)
- false
- end
-
- def get_classname(scope)
- self.classname
- end
-
- # Create a resource that knows how to evaluate our actual code.
- def evaluate(scope)
- resource = Puppet::Parser::Resource.new(:type => self.class.name, :title => get_classname(scope), :scope => scope, :source => scope.source)
-
- scope.catalog.tag(*resource.tags)
-
- scope.compiler.add_resource(scope, resource)
-
- return resource
- end
-
- # Now evaluate the code associated with this class or definition.
- def evaluate_code(resource)
- # Create a new scope.
- scope = subscope(resource.scope, resource)
-
- set_resource_parameters(scope, resource)
-
- if self.code
- return self.code.safeevaluate(scope)
- else
- return nil
- end
- end
-
- def initialize(hash = {})
- @arguments = nil
- @parentclass = nil
- super
-
- # Convert the arguments to a hash for ease of later use.
- if @arguments
- unless @arguments.is_a? Array
- @arguments = [@arguments]
- end
- oldargs = @arguments
- @arguments = {}
- oldargs.each do |arg, val|
- @arguments[arg] = val
- end
- else
- @arguments = {}
- end
-
- # Deal with metaparams in the argument list.
- @arguments.each do |arg, defvalue|
- next unless Puppet::Type.metaparamclass(arg)
- if defvalue
- warnonce "%s is a metaparam; this value will inherit to all contained resources" % arg
- else
- raise Puppet::ParseError, "%s is a metaparameter; please choose another parameter name in the %s definition" % [arg, self.classname]
- end
- end
- end
-
- def find_parentclass
- @parser.find_hostclass(namespace, parentclass)
- end
-
- # Set our parent class, with a little check to avoid some potential
- # weirdness.
- def parentclass=(name)
- if name == self.classname
- parsefail "Parent classes must have dissimilar names"
- end
-
- @parentclass = name
- end
-
- # Hunt down our class object.
- def parentobj
- return nil unless @parentclass
-
- # Cache our result, since it should never change.
- unless defined?(@parentobj)
- unless tmp = find_parentclass
- parsefail "Could not find %s parent %s" % [self.class.name, @parentclass]
- end
-
- if tmp == self
- parsefail "Parent classes must have dissimilar names"
- end
-
- @parentobj = tmp
- end
- @parentobj
- end
-
- # Create a new subscope in which to evaluate our code.
- def subscope(scope, resource)
- args = {
- :resource => resource,
- :keyword => self.keyword,
- :namespace => self.namespace,
- :source => self
- }
-
- oldscope = scope
- scope = scope.newscope(args)
- scope.source = self
-
- return scope
- end
-
- def to_s
- classname
- end
-
- # Check whether a given argument is valid. Searches up through
- # any parent classes that might exist.
- def validattr?(param)
- param = param.to_s
-
- if @arguments.include?(param)
- # It's a valid arg for us
- return true
- elsif param == "name"
- return true
-# elsif defined? @parentclass and @parentclass
-# # Else, check any existing parent
-# if parent = @scope.lookuptype(@parentclass) and parent != []
-# return parent.validarg?(param)
-# elsif builtin = Puppet::Type.type(@parentclass)
-# return builtin.validattr?(param)
-# else
-# raise Puppet::Error, "Could not find parent class %s" %
-# @parentclass
-# end
- elsif Puppet::Type.metaparam?(param)
- return true
- else
- # Or just return false
- return false
- end
- end
-
- private
-
- # Set any arguments passed by the resource as variables in the scope.
- def set_resource_parameters(scope, resource)
- args = symbolize_options(resource.to_hash || {})
-
- # Verify that all required arguments are either present or
- # have been provided with defaults.
- if self.arguments
- self.arguments.each { |arg, default|
- arg = arg.to_sym
- unless args.include?(arg)
- if defined? default and ! default.nil?
- default = default.safeevaluate scope
- args[arg] = default
- #Puppet.debug "Got default %s for %s in %s" %
- # [default.inspect, arg.inspect, @name.inspect]
- else
- parsefail "Must pass %s to %s of type %s" %
- [arg, resource.title, @classname]
- end
- end
- }
- end
-
- # Set each of the provided arguments as variables in the
- # definition's scope.
- args.each { |arg,value|
- unless validattr?(arg)
- parsefail "%s does not accept attribute %s" % [@classname, arg]
- end
-
- exceptwrap do
- scope.setvar(arg.to_s, args[arg])
- end
- }
-
- scope.setvar("title", resource.title) unless args.include? :title
- scope.setvar("name", resource.name) unless args.include? :name
- end
-end
diff --git a/lib/puppet/parser/ast/hostclass.rb b/lib/puppet/parser/ast/hostclass.rb
deleted file mode 100644
index 23d9a00e5..000000000
--- a/lib/puppet/parser/ast/hostclass.rb
+++ /dev/null
@@ -1,95 +0,0 @@
-require 'puppet/parser/ast/definition'
-
-# The code associated with a class. This is different from definitions
-# in that each class is a singleton -- only one will exist for a given
-# node.
-class Puppet::Parser::AST::HostClass < Puppet::Parser::AST::Definition
-
- associates_doc
-
- @name = :class
-
- # Are we a child of the passed class? Do a recursive search up our
- # parentage tree to figure it out.
- def child_of?(klass)
- return false unless self.parentclass
-
- if klass == self.parentobj
- return true
- else
- return self.parentobj.child_of?(klass)
- end
- end
-
- # Make sure our parent class has been evaluated, if we have one.
- def evaluate(scope)
- if parentclass and ! scope.catalog.resource(self.class.name, parentclass)
- parent_resource = parentobj.evaluate(scope)
- end
-
- # Do nothing if the resource already exists; this makes sure we don't
- # get multiple copies of the class resource, which helps provide the
- # singleton nature of classes.
- if resource = scope.catalog.resource(self.class.name, self.classname)
- return resource
- end
-
- super
- end
-
- # Evaluate the code associated with this class.
- def evaluate_code(resource)
- scope = resource.scope
- # Verify that we haven't already been evaluated. This is
- # what provides the singleton aspect.
- if existing_scope = scope.compiler.class_scope(self)
- Puppet.debug "Class '%s' already evaluated; not evaluating again" % (classname == "" ? "main" : classname)
- return nil
- end
-
- pnames = nil
- if pklass = self.parentobj
- parent_resource = resource.scope.compiler.catalog.resource(self.class.name, pklass.classname)
- # This shouldn't evaluate if the class has already been evaluated.
- pklass.evaluate_code(parent_resource)
-
- scope = parent_scope(scope, pklass)
- pnames = scope.namespaces
- end
-
- # Don't create a subscope for the top-level class, since it already
- # has its own scope.
- unless resource.title == :main
- scope = subscope(scope, resource)
-
- scope.setvar("title", resource.title)
- scope.setvar("name", resource.name)
- end
-
- # Add the parent scope namespaces to our own.
- if pnames
- pnames.each do |ns|
- scope.add_namespace(ns)
- end
- end
-
- # Set the class before we evaluate the code, so that it's set during
- # the evaluation and can be inspected.
- scope.compiler.class_set(self.classname, scope)
-
- # Now evaluate our code, yo.
- if self.code
- return self.code.safeevaluate(scope)
- else
- return nil
- end
- end
-
- def parent_scope(scope, klass)
- if s = scope.compiler.class_scope(klass)
- return s
- else
- raise Puppet::DevError, "Could not find scope for %s" % klass.classname
- end
- end
-end
diff --git a/lib/puppet/parser/ast/leaf.rb b/lib/puppet/parser/ast/leaf.rb
index b73c781e1..07bba1b4c 100644
--- a/lib/puppet/parser/ast/leaf.rb
+++ b/lib/puppet/parser/ast/leaf.rb
@@ -94,6 +94,7 @@ class Puppet::Parser::AST
def initialize(hash)
super
+ # Note that this is an AST::Regex, not a Regexp
@value = @value.to_s.downcase unless @value.is_a?(Regex)
if @value =~ /[^-\w.]/
raise Puppet::DevError,
@@ -101,10 +102,6 @@ class Puppet::Parser::AST
end
end
- def to_classname
- to_s.downcase.gsub(/[^-\w:.]/,'').sub(/^\.+/,'')
- end
-
# implementing eql? and hash so that when an HostName is stored
# in a hash it has the same hashing properties as the underlying value
def eql?(value)
@@ -116,25 +113,6 @@ class Puppet::Parser::AST
return @value.hash
end
- def match(value)
- return @value.match(value) unless value.is_a?(HostName)
-
- if value.regex? and self.regex?
- # Wow this is some sweet design; maybe a touch of refactoring
- # in order here.
- return value.value.value == self.value.value
- elsif value.regex? # we know if the existing name is not a regex, it won't match a regex
- return false
- else
- # else, we could be either a regex or normal and it doesn't matter
- return @value.match(value.value)
- end
- end
-
- def regex?
- @value.is_a?(Regex)
- end
-
def to_s
@value.to_s
end
diff --git a/lib/puppet/parser/ast/node.rb b/lib/puppet/parser/ast/node.rb
deleted file mode 100644
index 4f75201eb..000000000
--- a/lib/puppet/parser/ast/node.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-require 'puppet/parser/ast/hostclass'
-
-# The specific code associated with a host. Nodes are annoyingly unlike
-# other objects. That's just the way it is, at least for now.
-class Puppet::Parser::AST::Node < Puppet::Parser::AST::HostClass
-
- associates_doc
-
- @name = :node
-
- def initialize(options)
- @parentclass = nil
- super
- end
-
- def namespace
- ""
- end
-
- # in Regex mode, our classname can't be our Regex.
- # so we use the currently connected client as our
- # classname, mimicing exactly what would have happened
- # if there was a specific node definition for this node.
- def get_classname(scope)
- return scope.host if name.regex?
- classname
- end
-
- # Make sure node scopes are marked as such.
- def subscope(*args)
- scope = super
- scope.nodescope = true
- scope
- end
-
- private
-
- # Search for the object matching our parent class.
- def find_parentclass
- @parser.node(parentclass)
- end
-end
diff --git a/lib/puppet/parser/ast/resource_reference.rb b/lib/puppet/parser/ast/resource_reference.rb
index 117bc88af..794e505b8 100644
--- a/lib/puppet/parser/ast/resource_reference.rb
+++ b/lib/puppet/parser/ast/resource_reference.rb
@@ -44,7 +44,7 @@ class Puppet::Parser::AST
def qualified_class(scope, title)
# Look up the full path to the class
if classobj = scope.find_hostclass(title)
- title = classobj.classname
+ title = classobj.name
else
raise Puppet::ParseError, "Could not find class %s" % title
end
@@ -57,7 +57,7 @@ class Puppet::Parser::AST
objtype = @type.downcase
unless builtintype?(objtype)
if dtype = scope.find_definition(objtype)
- objtype = dtype.classname
+ objtype = dtype.name
else
raise Puppet::ParseError, "Could not find resource type %s" % objtype
end
diff --git a/lib/puppet/parser/compiler.rb b/lib/puppet/parser/compiler.rb
index 77b0bb98e..6b6cd6815 100644
--- a/lib/puppet/parser/compiler.rb
+++ b/lib/puppet/parser/compiler.rb
@@ -71,8 +71,8 @@ class Puppet::Parser::Compiler
# variables.
def class_scope(klass)
# They might pass in either the class or class name
- if klass.respond_to?(:classname)
- @class_scopes[klass.classname]
+ if klass.respond_to?(:name)
+ @class_scopes[klass.name]
else
@class_scopes[klass]
end
@@ -140,7 +140,7 @@ class Puppet::Parser::Compiler
if klass = scope.find_hostclass(name)
found << name and next if class_scope(klass)
- resource = klass.evaluate(scope)
+ resource = klass.mk_plain_resource(scope)
# If they've disabled lazy evaluation (which the :include function does),
# then evaluate our resource immediately.
@@ -230,7 +230,7 @@ class Puppet::Parser::Compiler
# Create a resource to model this node, and then add it to the list
# of resources.
- resource = astnode.evaluate(topscope)
+ resource = astnode.mk_plain_resource(topscope)
resource.evaluate
diff --git a/lib/puppet/parser/loaded_code.rb b/lib/puppet/parser/loaded_code.rb
index 3efd115bc..d7f179ae7 100644
--- a/lib/puppet/parser/loaded_code.rb
+++ b/lib/puppet/parser/loaded_code.rb
@@ -8,44 +8,62 @@ class Puppet::Parser::LoadedCode
@node_list = []
end
- def add_hostclass(name, code)
- @hostclasses[munge_name(name)] = code
+ def <<(thing)
+ add(thing)
+ self
+ end
+
+ def add(instance)
+ method = "add_#{instance.type}"
+ send(method, instance)
+ instance.code_collection = self
+ instance
+ end
+
+ def add_hostclass(instance)
+ dupe_check(instance, @hostclasses) { |dupe| "Class #{instance.name} is already defined#{dupe.error_context}; cannot redefine" }
+ dupe_check(instance, @definitions) { |dupe| "Definition #{instance.name} is already defined#{dupe.error_context}; cannot be redefined as a class" }
+
+ @hostclasses[instance.name] = instance
+ instance
end
def hostclass(name)
@hostclasses[munge_name(name)]
end
- def add_node(name, code)
- name = check_name(name)
- @node_list << name unless @node_list.include?(name)
- @nodes[name] = code
+ def add_node(instance)
+ dupe_check(instance, @nodes) { |dupe| "Node #{instance.name} is already defined#{dupe.error_context}; cannot redefine" }
+
+ @node_list << instance
+ @nodes[instance.name] = instance
+ instance
end
def node(name)
- name = check_name(name)
+ name = munge_name(name)
if node = @nodes[name]
return node
end
- @node_list.each do |nodename|
- n = @nodes[nodename]
- return n if nodename.regex? and nodename.match(name)
+ @node_list.each do |node|
+ next unless node.name_is_regex?
+ return node if node.match(name)
end
nil
end
def node_exists?(name)
- @nodes[check_name(name)]
+ @nodes[munge_name(name)]
end
def nodes?
@nodes.length > 0
end
- def add_definition(name, code)
- @definitions[munge_name(name)] = code
+ def add_definition(code)
+ @definitions[code.name] = code
end
def definition(name)
@@ -108,12 +126,9 @@ class Puppet::Parser::LoadedCode
name.to_s.downcase
end
- # Check that the given (node) name is an HostName instance
- # We're doing this so that hashing of node in the @nodes hash
- # is consistent (see AST::HostName#hash and AST::HostName#eql?)
- # and that the @nodes hash still keep its O(1) get/put properties.
- def check_name(name)
- name = Puppet::Parser::AST::HostName.new(:value => name) unless name.is_a?(Puppet::Parser::AST::HostName)
- name
+ def dupe_check(instance, hash)
+ return unless dupe = hash[instance.name]
+ message = yield dupe
+ instance.fail Puppet::ParseError, message
end
end
diff --git a/lib/puppet/parser/parser_support.rb b/lib/puppet/parser/parser_support.rb
index 7a8fa812a..1b961cd04 100644
--- a/lib/puppet/parser/parser_support.rb
+++ b/lib/puppet/parser/parser_support.rb
@@ -4,6 +4,7 @@ class Puppet::Parser::Parser
require 'puppet/parser/functions'
require 'puppet/parser/files'
require 'puppet/parser/loaded_code'
+ require 'puppet/parser/resource_type'
require 'monitor'
AST = Puppet::Parser::AST
@@ -42,17 +43,16 @@ class Puppet::Parser::Parser
# Create an AST object, and automatically add the file and line information if
# available.
def ast(klass, hash = {})
- hash[:line] = @lexer.line unless hash.include?(:line)
-
- unless hash.include?(:file)
- if file = @lexer.file
- hash[:file] = file
- end
- end
+ klass.new ast_context(klass.use_docs).merge(hash)
+ end
- k = klass.new(hash)
- k.doc = lexer.getcomment(hash[:line]) if !k.nil? and k.use_docs and k.doc.empty?
- return k
+ def ast_context(include_docs = false)
+ result = {
+ :line => lexer.line,
+ :file => lexer.file
+ }
+ result[:doc] = lexer.getcomment(result[:line]) if include_docs
+ result
end
# The fully qualifed name, with the full namespace.
@@ -276,126 +276,21 @@ class Puppet::Parser::Parser
# Create a new class, or merge with an existing class.
def newclass(name, options = {})
- name = name.downcase
-
- if @loaded_code.definition(name)
- raise Puppet::ParseError, "Cannot redefine class %s as a definition" % name
- end
- code = options[:code]
- parent = options[:parent]
- doc = options[:doc]
-
- # If the class is already defined, then add code to it.
- if other = @loaded_code.hostclass(name) || @loaded_code.definition(name)
- # Make sure the parents match
- if parent and other.parentclass and (parent != other.parentclass)
- error("Class %s is already defined at %s:%s; cannot redefine" % [name, other.file, other.line])
- end
-
- # This might be dangerous...
- if parent and ! other.parentclass
- other.parentclass = parent
- end
-
- # This might just be an empty, stub class.
- if code
- tmp = name
- if tmp == ""
- tmp = "main"
- end
-
- Puppet.debug addcontext("Adding code to %s" % tmp)
- # Else, add our code to it.
- if other.code and code
- # promote if neededcodes to ASTArray so that we can append code
- # ASTArray knows how to evaluate its members.
- other.code = ast AST::ASTArray, :children => [other.code] unless other.code.is_a?(AST::ASTArray)
- code = ast AST::ASTArray, :children => [code] unless code.is_a?(AST::ASTArray)
- other.code.children += code.children
- else
- other.code ||= code
- end
- end
-
- if other.doc and doc
- other.doc += doc
- else
- other.doc ||= doc
- end
- else
- # Define it anew.
- # Note we're doing something somewhat weird here -- we're setting
- # the class's namespace to its fully qualified name. This means
- # anything inside that class starts looking in that namespace first.
- args = {:namespace => name, :classname => name, :parser => self}
- args[:code] = code if code
- args[:parentclass] = parent if parent
- args[:doc] = doc
- args[:line] = options[:line]
-
- @loaded_code.add_hostclass(name, ast(AST::HostClass, args))
- end
-
- return @loaded_code.hostclass(name)
+ @loaded_code.add Puppet::Parser::ResourceType.new(:hostclass, name, ast_context(true).merge(options))
end
# Create a new definition.
def newdefine(name, options = {})
- name = name.downcase
- if @loaded_code.hostclass(name)
- raise Puppet::ParseError, "Cannot redefine class %s as a definition" %
- name
- end
- # Make sure our definition doesn't already exist
- if other = @loaded_code.definition(name)
- error("%s is already defined at %s:%s; cannot redefine" % [name, other.file, other.line])
- end
-
- ns, whatever = namesplit(name)
- args = {
- :namespace => ns,
- :arguments => options[:arguments],
- :code => options[:code],
- :parser => self,
- :classname => name,
- :doc => options[:doc],
- :line => options[:line]
- }
-
- [:code, :arguments].each do |param|
- args[param] = options[param] if options[param]
- end
-
- @loaded_code.add_definition(name, ast(AST::Definition, args))
+ @loaded_code.add Puppet::Parser::ResourceType.new(:definition, name, ast_context(true).merge(options))
end
# Create a new node. Nodes are special, because they're stored in a global
# table, not according to namespaces.
def newnode(names, options = {})
names = [names] unless names.instance_of?(Array)
- doc = lexer.getcomment
+ context = ast_context(true)
names.collect do |name|
- name = AST::HostName.new :value => name unless name.is_a?(AST::HostName)
- if other = @loaded_code.node_exists?(name)
- error("Node %s is already defined at %s:%s; cannot redefine" % [other.name, other.file, other.line])
- end
- name = name.to_s if name.is_a?(Symbol)
- args = {
- :name => name,
- :parser => self,
- :doc => doc,
- :line => options[:line]
- }
- if options[:code]
- args[:code] = options[:code]
- end
- if options[:parent]
- args[:parentclass] = options[:parent]
- end
- node = ast(AST::Node, args)
- node.classname = name.to_classname
- @loaded_code.add_node(name, node)
- node
+ @loaded_code.add(Puppet::Parser::ResourceType.new(:node, name, context.merge(options)))
end
end
diff --git a/lib/puppet/parser/resource_type.rb b/lib/puppet/parser/resource_type.rb
new file mode 100644
index 000000000..a67965960
--- /dev/null
+++ b/lib/puppet/parser/resource_type.rb
@@ -0,0 +1,235 @@
+require 'puppet/parser/parser'
+require 'puppet/util/warnings'
+require 'puppet/util/errors'
+require 'puppet/util/inline_docs'
+require 'puppet/parser/ast/leaf'
+
+class Puppet::Parser::ResourceType
+ include Puppet::Util::InlineDocs
+ include Puppet::Util::Warnings
+ include Puppet::Util::Errors
+
+ RESOURCE_SUPERTYPES = [:hostclass, :node, :definition]
+
+ attr_accessor :file, :line, :doc, :code, :parent, :code_collection
+ attr_reader :type, :namespace, :arguments, :behaves_like
+
+ # Are we a child of the passed class? Do a recursive search up our
+ # parentage tree to figure it out.
+ def child_of?(klass)
+ return false unless parent
+
+ return true if klass == parent_type
+ return parent_type.child_of?(klass)
+ end
+
+ # Now evaluate the code associated with this class or definition.
+ def evaluate_code(resource)
+ # Create a new scope.
+ scope = subscope(resource.scope, resource)
+
+ set_resource_parameters(resource, scope)
+
+ return nil unless c = self.code
+ return c.safeevaluate(scope)
+ end
+
+ def initialize(type, name, options = {})
+ @type = type.to_s.downcase.to_sym
+ raise ArgumentError, "Invalid resource supertype '#{type}'" unless RESOURCE_SUPERTYPES.include?(@type)
+
+ name = convert_from_ast(name) if name.is_a?(Puppet::Parser::AST::HostName)
+
+ set_name_and_namespace(name)
+
+ [:code, :doc, :line, :file, :parent].each do |param|
+ next unless value = options[param]
+ send(param.to_s + "=", value)
+ end
+
+ set_arguments(options[:arguments])
+ end
+
+ # This is only used for node names, and really only when the node name
+ # is a regexp.
+ def match(string)
+ return string.to_s.downcase == name unless name_is_regex?
+
+ return @name =~ string
+ end
+
+ # Add code from a new instance to our code.
+ def merge(other)
+ fail ArgumentError, "#{name} is not a class; cannot add code to it" unless type == :hostclass
+ fail ArgumentError, "#{other.name} is not a class; cannot add code from it" unless other.type == :hostclass
+
+ if parent and other.parent and parent != other.parent
+ fail ArgumentError, "Cannot merge classes with different parent classes"
+ end
+
+ # We know they're either equal or only one is set, so keep whichever parent is specified.
+ self.parent ||= other.parent
+
+ if other.doc
+ self.doc ||= ""
+ self.doc += other.doc
+ end
+
+ # This might just be an empty, stub class.
+ return unless other.code
+
+ unless self.code
+ self.code = other.code
+ return
+ end
+
+ array_class = Puppet::Parser::AST::ASTArray
+ unless self.code.is_a?(array_class)
+ self.code = array_class.new(:children => [self.code])
+ end
+
+ if other.code.is_a?(array_class)
+ code.children += other.code.children
+ else
+ code.children << other.code
+ end
+ end
+
+ # Make an instance of our resource type. This is only possible
+ # for those classes and nodes that don't have any arguments, and is
+ # only useful for things like the 'include' function.
+ def mk_plain_resource(scope)
+ type == :definition and raise ArgumentError, "Cannot create resources for defined resource types"
+ resource_type = type == :hostclass ? :class : :node
+
+ # Make sure our parent class has been evaluated, if we have one.
+ if parent and ! scope.catalog.resource(resource_type, parent)
+ parent_type.mk_plain_resource(scope)
+ end
+
+ # Do nothing if the resource already exists; this makes sure we don't
+ # get multiple copies of the class resource, which helps provide the
+ # singleton nature of classes.
+ if resource = scope.catalog.resource(resource_type, name)
+ return resource
+ end
+
+ resource = Puppet::Parser::Resource.new(:type => resource_type, :title => name, :scope => scope, :source => self)
+ scope.compiler.add_resource(scope, resource)
+ scope.catalog.tag(*resource.tags)
+ resource
+ end
+
+ def name
+ return @name unless @name.is_a?(Regexp)
+ return @name.source.downcase.gsub(/[^-\w:.]/,'').sub(/^\.+/,'')
+ end
+
+ def name_is_regex?
+ @name.is_a?(Regexp)
+ end
+
+ def parent_type
+ return nil unless parent
+
+ unless @parent_type ||= code_collection.send(type, parent)
+ fail Puppet::ParseError, "Could not find parent resource type '#{parent}'"
+ end
+
+ @parent_type
+ end
+
+ # Set any arguments passed by the resource as variables in the scope.
+ def set_resource_parameters(resource, scope)
+ set = {}
+ resource.to_hash.each do |param, value|
+ param = param.to_sym
+ fail Puppet::ParseError, "#{resource.ref} does not accept attribute #{param}" unless validattr?(param)
+
+ exceptwrap { scope.setvar(param.to_s, value) }
+
+ set[param] = true
+ end
+
+ # Verify that all required arguments are either present or
+ # have been provided with defaults.
+ arguments.each do |param, default|
+ param = param.to_sym
+ next if set.include?(param)
+
+ # Even if 'default' is a false value, it's an AST value, so this works fine
+ fail Puppet::ParseError, "Must pass #{param} to #{resource.ref}" unless default
+
+ scope.setvar(param.to_s, default.safeevaluate(scope))
+ end
+
+ scope.setvar("title", resource.title) unless set.include? :title
+ scope.setvar("name", resource.name) unless set.include? :name
+ end
+
+ # Create a new subscope in which to evaluate our code.
+ def subscope(scope, resource)
+ scope.newscope :resource => resource, :namespace => self.namespace, :source => self
+ end
+
+ # Check whether a given argument is valid.
+ def validattr?(param)
+ param = param.to_s
+
+ return true if param == "name"
+ return true if Puppet::Type.metaparam?(param)
+ return false unless defined?(@arguments)
+ return true if arguments.include?(param)
+ return false
+ end
+
+ def set_arguments(arguments)
+ @arguments = {}
+ return if arguments.nil?
+
+ arguments.each do |arg, default|
+ arg = arg.to_s
+ warn_if_metaparam(arg, default)
+ @arguments[arg] = default
+ end
+ end
+
+ private
+
+ def convert_from_ast(name)
+ value = name.value
+ if value.is_a?(Puppet::Parser::AST::Regex)
+ name = value.value
+ else
+ name = value
+ end
+ end
+
+ # Split an fq name into a namespace and name
+ def namesplit(fullname)
+ ary = fullname.split("::")
+ n = ary.pop || ""
+ ns = ary.join("::")
+ return ns, n
+ end
+
+ def set_name_and_namespace(name)
+ if name.is_a?(Regexp)
+ @name = name
+ @namespace = ""
+ else
+ @name = name.to_s.downcase
+ @namespace, ignored_shortname = namesplit(@name)
+ end
+ end
+
+ def warn_if_metaparam(param, default)
+ return unless Puppet::Type.metaparamclass(param)
+
+ if default
+ warnonce "#{param} is a metaparam; this value will inherit to all contained resources"
+ else
+ raise Puppet::ParseError, "#{param} is a metaparameter; please choose another parameter name in the #{self.name} definition"
+ end
+ end
+end
diff --git a/lib/puppet/util/rdoc/parser.rb b/lib/puppet/util/rdoc/parser.rb
index c2d307751..3f04fbf52 100644
--- a/lib/puppet/util/rdoc/parser.rb
+++ b/lib/puppet/util/rdoc/parser.rb
@@ -323,8 +323,8 @@ class Parser
# that contains the documentation
def parse_elements(container)
Puppet.debug "rdoc: scanning manifest"
- @ast.hostclasses.values.sort { |a,b| a.classname <=> b.classname }.each do |klass|
- name = klass.classname
+ @ast.hostclasses.values.sort { |a,b| a.name <=> b.name }.each do |klass|
+ name = klass.name
if klass.file == @input_file_name
unless name.empty?
document_class(name,klass,container)
@@ -463,4 +463,4 @@ class Parser
comment.sub!(/^#--.*/m, '')
end
end
-end \ No newline at end of file
+end