summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rwxr-xr-xspec/integration/parser/parser.rb21
-rwxr-xr-xspec/integration/util/rdoc/parser.rb4
-rw-r--r--spec/unit/parser/ast.rb6
-rwxr-xr-xspec/unit/parser/ast/definition.rb213
-rwxr-xr-xspec/unit/parser/ast/hostclass.rb148
-rwxr-xr-xspec/unit/parser/ast/leaf.rb72
-rwxr-xr-xspec/unit/parser/ast/node.rb145
-rwxr-xr-xspec/unit/parser/ast/resource_reference.rb6
-rwxr-xr-xspec/unit/parser/compiler.rb32
-rw-r--r--spec/unit/parser/loaded_code.rb218
-rwxr-xr-xspec/unit/parser/parser.rb126
-rwxr-xr-xspec/unit/parser/resource/reference.rb4
-rwxr-xr-xspec/unit/parser/resource_type.rb522
-rwxr-xr-xspec/unit/util/rdoc/parser.rb23
25 files changed, 1030 insertions, 1322 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
diff --git a/spec/integration/parser/parser.rb b/spec/integration/parser/parser.rb
new file mode 100755
index 000000000..71ae136ed
--- /dev/null
+++ b/spec/integration/parser/parser.rb
@@ -0,0 +1,21 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+describe Puppet::Parser::Parser do
+ before :each do
+ @loaded_code = Puppet::Parser::LoadedCode.new
+ @parser = Puppet::Parser::Parser.new :environment => "development", :loaded_code => @loaded_code
+ end
+
+ describe "when parsing comments before statement" do
+ it "should associate the documentation to the statement AST node" do
+ ast = @parser.parse("""
+ # comment
+ class test {}
+ """)
+
+ ast.hostclass("test").doc.should == "comment\n"
+ end
+ end
+end
diff --git a/spec/integration/util/rdoc/parser.rb b/spec/integration/util/rdoc/parser.rb
index df8c62df6..542660998 100755
--- a/spec/integration/util/rdoc/parser.rb
+++ b/spec/integration/util/rdoc/parser.rb
@@ -36,7 +36,7 @@ describe RDoc::Parser do
end
it "should parse to RDoc data structure" do
- @parser.expects(:document_class).with { |n,k,c| n == "::test" and k.is_a?(Puppet::Parser::AST::HostClass) }
+ @parser.expects(:document_class).with { |n,k,c| n == "::test" and k.is_a?(Puppet::Parser::ResourceType) }
@parser.scan
end
-end \ No newline at end of file
+end
diff --git a/spec/unit/parser/ast.rb b/spec/unit/parser/ast.rb
index 35f575b1b..ca6f8080a 100644
--- a/spec/unit/parser/ast.rb
+++ b/spec/unit/parser/ast.rb
@@ -20,9 +20,9 @@ describe Puppet::Parser::AST do
ast.should respond_to(:use_docs)
end
- [ Puppet::Parser::AST::Collection, Puppet::Parser::AST::Definition, Puppet::Parser::AST::Else,
- Puppet::Parser::AST::Function, Puppet::Parser::AST::HostClass, Puppet::Parser::AST::IfStatement,
- Puppet::Parser::AST::Node, Puppet::Parser::AST::Resource, Puppet::Parser::AST::ResourceDefaults,
+ [ Puppet::Parser::AST::Collection, Puppet::Parser::AST::Else,
+ Puppet::Parser::AST::Function, Puppet::Parser::AST::IfStatement,
+ Puppet::Parser::AST::Resource, Puppet::Parser::AST::ResourceDefaults,
Puppet::Parser::AST::ResourceOverride, Puppet::Parser::AST::VarDef
].each do |k|
it "#{k}.use_docs should return true" do
diff --git a/spec/unit/parser/ast/definition.rb b/spec/unit/parser/ast/definition.rb
deleted file mode 100755
index c26706524..000000000
--- a/spec/unit/parser/ast/definition.rb
+++ /dev/null
@@ -1,213 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../../../spec_helper'
-
-describe Puppet::Parser::AST::Definition, "when initializing" do
-end
-
-describe Puppet::Parser::AST::Definition, "when evaluating" do
- before do
- @type = Puppet::Parser::Resource
- @parser = Puppet::Parser::Parser.new :Code => ""
- @source = @parser.newclass ""
- @definition = @parser.newdefine "mydefine"
- @node = Puppet::Node.new("yaynode")
- @compiler = Puppet::Parser::Compiler.new(@node, @parser)
- @scope = @compiler.topscope
-
- @resource = Puppet::Parser::Resource.new(:type => "mydefine", :title => "myresource", :scope => @scope, :source => @source)
- end
-
- it "should create a new scope" do
- scope = nil
- code = mock 'code'
- code.expects(:safeevaluate).with do |scope|
- scope.object_id.should_not == @scope.object_id
- true
- end
- @definition.stubs(:code).returns(code)
- @definition.evaluate_code(@resource)
- end
-
- it "should have a get_classname method" do
- @definition.should respond_to(:get_classname)
- end
-
- it "should return the current classname with get_classname" do
- @definition.expects(:classname)
-
- @definition.get_classname(@scope)
- end
-
- describe "when evaluating" do
- it "should create a resource whose title comes from get_classname" do
- @definition.expects(:get_classname).returns("classname")
-
- @definition.evaluate(@scope)
- end
- end
-
-# it "should copy its namespace to the scope"
-#
-# it "should mark the scope virtual if the resource is virtual"
-#
-# it "should mark the scope exported if the resource is exported"
-#
-# it "should set the resource's parameters as variables in the scope"
-#
-# it "should set the resource's title as a variable in the scope"
-#
-# it "should copy the resource's title in a 'name' variable in the scope"
-#
-# it "should not copy the resource's title as the name if 'name' is one of the resource parameters"
-#
-# it "should evaluate the associated code with the new scope"
-
- def old_test_initialize
- parser = mkparser
-
- # Create a new definition
- klass = parser.newdefine "yayness",
- :arguments => [["owner", stringobj("nobody")], %w{mode}],
- :code => AST::ASTArray.new(
- :children => [resourcedef("file", "/tmp/$name",
- "owner" => varref("owner"), "mode" => varref("mode"))]
- )
-
- # Test validattr? a couple different ways
- [:owner, "owner", :schedule, "schedule"].each do |var|
- assert(klass.validattr?(var), "%s was not considered valid" % var.inspect)
- end
-
- [:random, "random"].each do |var|
- assert(! klass.validattr?(var), "%s was considered valid" % var.inspect)
- end
-
- end
-
- def oldtest_evaluate
- parser = mkparser
- config = mkcompiler
- config.send(:evaluate_main)
- scope = config.topscope
- klass = parser.newdefine "yayness",
- :arguments => [["owner", stringobj("nobody")], %w{mode}],
- :code => AST::ASTArray.new(
- :children => [resourcedef("file", "/tmp/$name",
- "owner" => varref("owner"), "mode" => varref("mode"))]
- )
-
- resource = Puppet::Parser::Resource.new(
- :title => "first",
- :type => "yayness",
- :exported => false,
- :virtual => false,
- :scope => scope,
- :source => scope.source
- )
- resource.send(:set_parameter, "name", "first")
- resource.send(:set_parameter, "mode", "755")
-
- resource.stubs(:title)
- assert_nothing_raised do
- klass.evaluate_code(resource)
- end
-
- firstobj = config.findresource("File[/tmp/first]")
- assert(firstobj, "Did not create /tmp/first obj")
-
- assert_equal("File", firstobj.type)
- assert_equal("/tmp/first", firstobj.title)
- assert_equal("nobody", firstobj[:owner])
- assert_equal("755", firstobj[:mode])
-
- # Make sure we can't evaluate it with the same args
- assert_raise(Puppet::ParseError) do
- klass.evaluate_code(resource)
- end
-
- # Now create another with different args
- resource2 = Puppet::Parser::Resource.new(
- :title => "second",
- :type => "yayness",
- :exported => false,
- :virtual => false,
- :scope => scope,
- :source => scope.source
- )
- resource2.send(:set_parameter, "name", "second")
- resource2.send(:set_parameter, "mode", "755")
- resource2.send(:set_parameter, "owner", "daemon")
-
- assert_nothing_raised do
- klass.evaluate_code(resource2)
- end
-
- secondobj = config.findresource("File[/tmp/second]")
- assert(secondobj, "Did not create /tmp/second obj")
-
- assert_equal("File", secondobj.type)
- assert_equal("/tmp/second", secondobj.title)
- assert_equal("daemon", secondobj[:owner])
- assert_equal("755", secondobj[:mode])
- end
-
- # #539 - definitions should support both names and titles
- def oldtest_names_and_titles
- parser = mkparser
- scope = mkscope :parser => parser
-
- [
- {:name => "one", :title => "two"},
- {:title => "mytitle"}
- ].each_with_index do |hash, i|
- # Create a definition that uses both name and title. Put this
- # inside the loop so the subscope expectations work.
- klass = parser.newdefine "yayness%s" % i
-
- resource = Puppet::Parser::Resource.new(
- :title => hash[:title],
- :type => "yayness%s" % i,
- :exported => false,
- :virtual => false,
- :scope => scope,
- :source => scope.source
- )
-
- subscope = klass.subscope(scope, resource)
-
- klass.expects(:subscope).returns(subscope)
-
- if hash[:name]
- resource.stubs(:to_hash).returns({:name => hash[:name]})
- end
-
- assert_nothing_raised("Could not evaluate definition with %s" % hash.inspect) do
- klass.evaluate_code(resource)
- end
-
- name = hash[:name] || hash[:title]
- title = hash[:title]
-
- assert_equal(name, subscope.lookupvar("name"),
- "Name did not get set correctly")
- assert_equal(title, subscope.lookupvar("title"),
- "title did not get set correctly")
-
- [:name, :title].each do |param|
- val = resource.send(param)
- assert(subscope.tags.include?(val),
- "Scope was not tagged with %s '%s'" % [param, val])
- end
- end
- end
-
- # Testing the root cause of #615. We should be using the fqname for the type, instead
- # of just the short name.
- def oldtest_fully_qualified_types
- parser = mkparser
- klass = parser.newclass("one::two")
-
- assert_equal("one::two", klass.classname, "Class did not get fully qualified class name")
- end
-end
diff --git a/spec/unit/parser/ast/hostclass.rb b/spec/unit/parser/ast/hostclass.rb
deleted file mode 100755
index 10aa62176..000000000
--- a/spec/unit/parser/ast/hostclass.rb
+++ /dev/null
@@ -1,148 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../../../spec_helper'
-
-describe Puppet::Parser::AST::HostClass do
- before :each do
- @node = Puppet::Node.new "testnode"
- @parser = Puppet::Parser::Parser.new :environment => "development"
- @scope_resource = stub 'scope_resource', :builtin? => true
- @compiler = Puppet::Parser::Compiler.new(@node, @parser)
-
- @scope = @compiler.topscope
- end
-
- describe Puppet::Parser::AST::HostClass, "when evaluating" do
-
- before do
- @top = @parser.newclass "top"
- @middle = @parser.newclass "middle", :parent => "top"
- end
-
- it "should create a resource that references itself" do
- @top.evaluate(@scope)
-
- @compiler.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource)
- end
-
- it "should evaluate the parent class if one exists" do
- @middle.evaluate(@scope)
-
- @compiler.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource)
- end
-
- it "should fail to evaluate if a parent class is defined but cannot be found" do
- othertop = @parser.newclass "something", :parent => "yay"
- lambda { othertop.evaluate(@scope) }.should raise_error(Puppet::ParseError)
- end
-
- it "should not create a new resource if one already exists" do
- @compiler.catalog.expects(:resource).with(:class, "top").returns("something")
- @compiler.catalog.expects(:add_resource).never
- @top.evaluate(@scope)
- end
-
- it "should return the existing resource when not creating a new one" do
- @compiler.catalog.expects(:resource).with(:class, "top").returns("something")
- @compiler.catalog.expects(:add_resource).never
- @top.evaluate(@scope).should == "something"
- end
-
- it "should not create a new parent resource if one already exists and it has a parent class" do
- @top.evaluate(@scope)
-
- top_resource = @compiler.catalog.resource(:class, "top")
-
- @middle.evaluate(@scope)
-
- @compiler.catalog.resource(:class, "top").should equal(top_resource)
- end
-
- # #795 - tag before evaluation.
- it "should tag the catalog with the resource tags when it is evaluated" do
- @middle.evaluate(@scope)
-
- @compiler.catalog.should be_tagged("middle")
- end
-
- it "should tag the catalog with the parent class tags when it is evaluated" do
- @middle.evaluate(@scope)
-
- @compiler.catalog.should be_tagged("top")
- end
- end
-
- describe Puppet::Parser::AST::HostClass, "when evaluating code" do
-
- before do
- @top_resource = stub "top_resource"
- @top = @parser.newclass "top", :code => @top_resource
-
- @middle_resource = stub "middle_resource"
- @middle = @parser.newclass "top::middle", :parent => "top", :code => @middle_resource
- end
-
- it "should set its namespace to its fully qualified name" do
- @middle.namespace.should == "top::middle"
- end
-
- it "should evaluate the code referred to by the class" do
- @top_resource.expects(:safeevaluate)
-
- resource = @top.evaluate(@scope)
-
- @top.evaluate_code(resource)
- end
-
- it "should evaluate the parent class's code if it has a parent" do
- @top_resource.expects(:safeevaluate)
- @middle_resource.expects(:safeevaluate)
-
- resource = @middle.evaluate(@scope)
-
- @middle.evaluate_code(resource)
- end
-
- it "should not evaluate the parent class's code if the parent has already been evaluated" do
- @top_resource.stubs(:safeevaluate)
- resource = @top.evaluate(@scope)
- @top.evaluate_code(resource)
-
- @top_resource.expects(:safeevaluate).never
- @middle_resource.stubs(:safeevaluate)
- resource = @middle.evaluate(@scope)
- @middle.evaluate_code(resource)
- end
-
- it "should use the parent class's scope as its parent scope" do
- @top_resource.stubs(:safeevaluate)
- @middle_resource.stubs(:safeevaluate)
- resource = @middle.evaluate(@scope)
- @middle.evaluate_code(resource)
-
- @compiler.class_scope(@middle).parent.should equal(@compiler.class_scope(@top))
- end
-
- it "should add the class's name and title to its own scope" do
- @top_resource.stubs(:safeevaluate)
- @middle_resource.stubs(:safeevaluate)
- resource = @middle.evaluate(@scope)
- scope = stub_everything 'scope', :compiler => @compiler
- @middle.stubs(:subscope).returns(scope)
-
- scope.expects(:setvar).with("title","top::middle")
- scope.expects(:setvar).with("name","top::middle")
-
- @middle.evaluate_code(resource)
- end
-
- it "should add the parent class's namespace to its namespace search path" do
- @top_resource.stubs(:safeevaluate)
- @middle_resource.stubs(:safeevaluate)
- resource = @middle.evaluate(@scope)
- @middle.evaluate_code(resource)
-
- @compiler.class_scope(@middle).namespaces.should be_include(@top.namespace)
- end
- end
-end
diff --git a/spec/unit/parser/ast/leaf.rb b/spec/unit/parser/ast/leaf.rb
index fecfba386..ee1ee04a7 100755
--- a/spec/unit/parser/ast/leaf.rb
+++ b/spec/unit/parser/ast/leaf.rb
@@ -195,40 +195,6 @@ describe Puppet::Parser::AST::HostName do
@host.evaluate(@scope).should == @value
end
- it "should implement to_classname" do
- @host.should respond_to(:to_classname)
- end
-
- it "should return the downcased nodename as classname" do
- host = Puppet::Parser::AST::HostName.new( :value => "KLASSNAME" )
- host.to_classname.should == "klassname"
- end
-
- it "should preserve '_' in to_classname with a string nodename" do
- host = Puppet::Parser::AST::HostName.new( :value => "node_with_underscore")
- host.to_classname.should == "node_with_underscore"
- end
-
- it "should preserve '_' in to_classname with a regex nodename" do
- host = Puppet::Parser::AST::HostName.new( :value => Puppet::Parser::AST::Regex.new(:value => "/\dnode_with_underscore\.+/") )
- host.to_classname.should == "dnode_with_underscore."
- end
-
- it "should return a string usable as classname when calling to_classname" do
- host = Puppet::Parser::AST::HostName.new( :value => Puppet::Parser::AST::Regex.new(:value => "/^this-is not@a classname$/") )
- host.to_classname.should == "this-isnotaclassname"
- end
-
- it "should return a string usable as a tag when calling to_classname" do
- host = Puppet::Parser::AST::HostName.new( :value => Puppet::Parser::AST::Regex.new(:value => "/.+.reductivelabs\.com/") )
- host.to_classname.should == "reductivelabs.com"
- end
-
- it "should delegate 'match' to the underlying value if it is an HostName" do
- @value.expects(:match).with("value")
- @host.match("value")
- end
-
it "should delegate eql? to the underlying value if it is an HostName" do
@value.expects(:eql?).with("value")
@host.eql?("value")
@@ -244,42 +210,4 @@ describe Puppet::Parser::AST::HostName do
@value.expects(:hash)
@host.hash
end
-
- it "should return true when regex? is called and value is a Regex" do
- @value.expects(:is_a?).with(Puppet::Parser::AST::Regex).returns(true)
- @host.regex?.should be_true
- end
-
- it "should return the results of comparing the regexes if asked whether a regex matches another regex" do
- hosts = [1,2].collect do |num|
- vreg = /vreg#{num}/
- value = Puppet::Parser::AST::Regex.new(:value => vreg)
- Puppet::Parser::AST::HostName.new(:value => value)
- end
-
- hosts[0].match(hosts[1]).should be_false
- hosts[0].match(hosts[0]).should be_true
- end
-
- it "should return false when comparing a non-regex to a regex" do
- vreg = /vreg/
- value = Puppet::Parser::AST::Regex.new(:value => vreg)
- regex = Puppet::Parser::AST::HostName.new(:value => value)
-
- value = Puppet::Parser::AST::Regex.new(:value => "foo")
- normal = Puppet::Parser::AST::HostName.new(:value => value)
-
- normal.match(regex).should be_false
- end
-
- it "should true when a provided string matches a regex" do
- vreg = /r/
- value = Puppet::Parser::AST::Regex.new(:value => vreg)
- regex = Puppet::Parser::AST::HostName.new(:value => value)
-
- value = Puppet::Parser::AST::Leaf.new(:value => "bar")
- normal = Puppet::Parser::AST::HostName.new(:value => value)
-
- regex.match(normal).should be_true
- end
end
diff --git a/spec/unit/parser/ast/node.rb b/spec/unit/parser/ast/node.rb
deleted file mode 100755
index 5a4a5efe4..000000000
--- a/spec/unit/parser/ast/node.rb
+++ /dev/null
@@ -1,145 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../../../spec_helper'
-
-describe Puppet::Parser::AST::Node do
- before :each do
- @node = Puppet::Node.new "testnode"
- @parser = Puppet::Parser::Parser.new :environment => "development"
- @scope_resource = stub 'scope_resource', :builtin? => true
- @compiler = Puppet::Parser::Compiler.new(@node, @parser)
-
- @scope = @compiler.topscope
- end
-
- describe "when calling get_classname" do
- it "should return current node name if name is a Regex" do
- name = stub 'name', :regex? => true
- node = @parser.newnode("node").shift
- node.stubs(:name).returns(name)
-
- @scope.expects(:host).returns("testnode")
-
- node.get_classname(@scope).should == "testnode"
- end
-
- it "should return the current node classname if name is not a Regex" do
- name = stub 'name', :regex? => false
- node = @parser.newnode("node").shift
- node.stubs(:name).returns(name)
-
- node.get_classname(@scope).should == "node"
- end
- end
-
- describe Puppet::Parser::AST::Node, "when evaluating" do
-
- before do
- @top = @parser.newnode("top").shift
- @middle = @parser.newnode("middle", :parent => "top").shift
- end
-
- it "should create a resource that references itself" do
- @top.evaluate(@scope)
-
- @compiler.catalog.resource(:node, "top").should be_an_instance_of(Puppet::Parser::Resource)
- end
-
- it "should evaluate the parent class if one exists" do
- @middle.evaluate(@scope)
-
- @compiler.catalog.resource(:node, "top").should be_an_instance_of(Puppet::Parser::Resource)
- end
-
- it "should fail to evaluate if a parent class is defined but cannot be found" do
- othertop = @parser.newnode("something", :parent => "yay").shift
- lambda { othertop.evaluate(@scope) }.should raise_error(Puppet::ParseError)
- end
-
- it "should not create a new resource if one already exists" do
- @compiler.catalog.expects(:resource).with(:node, "top").returns("something")
- @compiler.catalog.expects(:add_resource).never
- @top.evaluate(@scope)
- end
-
- it "should not create a new parent resource if one already exists and it has a parent class" do
- @top.evaluate(@scope)
-
- top_resource = @compiler.catalog.resource(:node, "top")
-
- @middle.evaluate(@scope)
-
- @compiler.catalog.resource(:node, "top").should equal(top_resource)
- end
-
- # #795 - tag before evaluation.
- it "should tag the catalog with the resource tags when it is evaluated" do
- @middle.evaluate(@scope)
-
- @compiler.catalog.should be_tagged("middle")
- end
-
- it "should tag the catalog with the parent class tags when it is evaluated" do
- @middle.evaluate(@scope)
-
- @compiler.catalog.should be_tagged("top")
- end
- end
-
- describe Puppet::Parser::AST::Node, "when evaluating code" do
-
- before do
- @top_resource = stub "top_resource"
- @top = @parser.newnode("top", :code => @top_resource).shift
-
- @middle_resource = stub "middle_resource"
- @middle = @parser.newnode("middle", :parent => "top", :code => @middle_resource).shift
- end
-
- it "should evaluate the code referred to by the class" do
- @top_resource.expects(:safeevaluate)
-
- resource = @top.evaluate(@scope)
-
- @top.evaluate_code(resource)
- end
-
- it "should evaluate the parent class's code if it has a parent" do
- @top_resource.expects(:safeevaluate)
- @middle_resource.expects(:safeevaluate)
-
- resource = @middle.evaluate(@scope)
-
- @middle.evaluate_code(resource)
- end
-
- it "should not evaluate the parent class's code if the parent has already been evaluated" do
- @top_resource.stubs(:safeevaluate)
- resource = @top.evaluate(@scope)
- @top.evaluate_code(resource)
-
- @top_resource.expects(:safeevaluate).never
- @middle_resource.stubs(:safeevaluate)
- resource = @middle.evaluate(@scope)
- @middle.evaluate_code(resource)
- end
-
- it "should use the parent class's scope as its parent scope" do
- @top_resource.stubs(:safeevaluate)
- @middle_resource.stubs(:safeevaluate)
- resource = @middle.evaluate(@scope)
- @middle.evaluate_code(resource)
-
- @compiler.class_scope(@middle).parent.should equal(@compiler.class_scope(@top))
- end
-
- it "should add the parent class's namespace to its namespace search path" do
- @top_resource.stubs(:safeevaluate)
- @middle_resource.stubs(:safeevaluate)
- resource = @middle.evaluate(@scope)
- @middle.evaluate_code(resource)
-
- @compiler.class_scope(@middle).namespaces.should be_include(@top.namespace)
- end
- end
-end
diff --git a/spec/unit/parser/ast/resource_reference.rb b/spec/unit/parser/ast/resource_reference.rb
index 24865e846..10d9678c3 100755
--- a/spec/unit/parser/ast/resource_reference.rb
+++ b/spec/unit/parser/ast/resource_reference.rb
@@ -21,7 +21,7 @@ describe Puppet::Parser::AST::ResourceReference do
%{ "one::two" "one-two"}.each do |type|
it "should evaluate correctly reference to define" do
- klass = stub 'klass', :title => "three", :classname => type
+ klass = stub 'klass', :title => "three", :name => type
@scope.stubs(:find_definition).returns(klass)
newref("three", type).evaluate(@scope).to_ref.should == Puppet::Parser::Resource::Reference.new( :type => type, :title => "three" ).to_ref
@@ -29,13 +29,13 @@ describe Puppet::Parser::AST::ResourceReference do
end
it "should be able to call qualified_class" do
- klass = stub 'klass', :title => "three", :classname => "one"
+ klass = stub 'klass', :title => "three", :name => "one"
@scope.expects(:find_hostclass).with("one").returns(klass)
newref("three","class").qualified_class(@scope,"one").should == "one"
end
it "should be able to find qualified classes when evaluating" do
- klass = stub 'klass', :title => "one", :classname => "one"
+ klass = stub 'klass', :title => "one", :name => "one"
@scope.stubs(:find_hostclass).returns(klass)
evaled = newref("one", "class").evaluate(@scope)
diff --git a/spec/unit/parser/compiler.rb b/spec/unit/parser/compiler.rb
index adc9732dc..8a41242d6 100755
--- a/spec/unit/parser/compiler.rb
+++ b/spec/unit/parser/compiler.rb
@@ -51,7 +51,7 @@ describe Puppet::Parser::Compiler do
it "should be able to retrieve class scopes by object" do
klass = mock 'ast_class'
- klass.expects(:classname).returns("myname")
+ klass.expects(:name).returns("myname")
@compiler.class_set "myname", "myscope"
@compiler.class_scope(klass).should == "myscope"
end
@@ -153,8 +153,8 @@ describe Puppet::Parser::Compiler do
it "should evaluate any existing classes named in the node" do
classes = %w{one two three four}
main = stub 'main'
- one = stub 'one', :classname => "one"
- three = stub 'three', :classname => "three"
+ one = stub 'one', :name => "one"
+ three = stub 'three', :name => "three"
@node.stubs(:name).returns("whatever")
@node.stubs(:classes).returns(classes)
@@ -396,7 +396,7 @@ describe Puppet::Parser::Compiler do
describe "when evaluating found classes" do
before do
- @class = stub 'class', :classname => "my::class"
+ @class = stub 'class', :name => "my::class"
@scope.stubs(:find_hostclass).with("myclass").returns(@class)
@resource = stub 'resource', :ref => "Class[myclass]", :type => "file"
@@ -405,7 +405,7 @@ describe Puppet::Parser::Compiler do
it "should evaluate each class" do
@compiler.catalog.stubs(:tag)
- @class.expects(:evaluate).with(@scope)
+ @class.expects(:mk_plain_resource).with(@scope)
@compiler.evaluate_classes(%w{myclass}, @scope)
end
@@ -415,7 +415,7 @@ describe Puppet::Parser::Compiler do
@resource.expects(:evaluate).never
- @class.expects(:evaluate).returns(@resource)
+ @class.expects(:mk_plain_resource).returns(@resource)
@compiler.evaluate_classes(%w{myclass}, @scope)
end
@@ -424,7 +424,7 @@ describe Puppet::Parser::Compiler do
@compiler.catalog.stubs(:tag)
@resource.expects(:evaluate)
- @class.expects(:evaluate).returns(@resource)
+ @class.expects(:mk_plain_resource).returns(@resource)
@compiler.evaluate_classes(%w{myclass}, @scope, false)
end
@@ -459,7 +459,7 @@ describe Puppet::Parser::Compiler do
@scope.stubs(:find_hostclass).with("notfound").returns(nil)
Puppet::Parser::Resource.stubs(:new).returns(@resource)
- @class.stubs :evaluate
+ @class.stubs :mk_plain_resource
@compiler.evaluate_classes(%w{myclass notfound}, @scope).should == %w{myclass}
end
end
@@ -495,31 +495,31 @@ describe Puppet::Parser::Compiler do
end
it "should evaluate the first node class matching the node name" do
- node_class = stub 'node', :classname => "c", :evaluate_code => nil
+ node_class = stub 'node', :name => "c", :evaluate_code => nil
@compiler.parser.stubs(:node).with("c").returns(node_class)
node_resource = stub 'node resource', :ref => "Node[c]", :evaluate => nil, :type => "node"
- node_class.expects(:evaluate).returns(node_resource)
+ node_class.expects(:mk_plain_resource).returns(node_resource)
@compiler.compile
end
it "should match the default node if no matching node can be found" do
- node_class = stub 'node', :classname => "default", :evaluate_code => nil
+ node_class = stub 'node', :name => "default", :evaluate_code => nil
@compiler.parser.stubs(:node).with("default").returns(node_class)
node_resource = stub 'node resource', :ref => "Node[default]", :evaluate => nil, :type => "node"
- node_class.expects(:evaluate).returns(node_resource)
+ node_class.expects(:mk_plain_resource).returns(node_resource)
@compiler.compile
end
it "should evaluate the node resource immediately rather than using lazy evaluation" do
- node_class = stub 'node', :classname => "c"
+ node_class = stub 'node', :name => "c"
@compiler.parser.stubs(:node).with("c").returns(node_class)
node_resource = stub 'node resource', :ref => "Node[c]", :type => "node"
- node_class.expects(:evaluate).returns(node_resource)
+ node_class.expects(:mk_plain_resource).returns(node_resource)
node_resource.expects(:evaluate)
@@ -528,13 +528,13 @@ describe Puppet::Parser::Compiler do
it "should set the node's scope as the top scope" do
node_resource = stub 'node resource', :ref => "Node[c]", :evaluate => nil, :type => "node"
- node_class = stub 'node', :classname => "c", :evaluate => node_resource
+ node_class = stub 'node', :name => "c", :mk_plain_resource => node_resource
@compiler.parser.stubs(:node).with("c").returns(node_class)
# The #evaluate method normally does this.
scope = stub 'scope', :source => "mysource"
- @compiler.class_set(node_class.classname, scope)
+ @compiler.class_set(node_class.name, scope)
node_resource.stubs(:evaluate)
@compiler.compile
diff --git a/spec/unit/parser/loaded_code.rb b/spec/unit/parser/loaded_code.rb
index 75f2bc7e2..9b72dab0d 100644
--- a/spec/unit/parser/loaded_code.rb
+++ b/spec/unit/parser/loaded_code.rb
@@ -3,23 +3,92 @@
require File.dirname(__FILE__) + '/../../spec_helper'
require 'puppet/parser/loaded_code'
+require 'puppet/parser/resource_type'
describe Puppet::Parser::LoadedCode do
+ before do
+ @instance = Puppet::Parser::ResourceType.new(:hostclass, "foo")
+ @code = Puppet::Parser::LoadedCode.new
+ end
+
+ it "should be able to add a resource type" do
+ Puppet::Parser::LoadedCode.new.should respond_to(:add)
+ end
+
+ it "should consider '<<' to be an alias to 'add' but should return self" do
+ loader = Puppet::Parser::LoadedCode.new
+ loader.expects(:add).with "foo"
+ loader.expects(:add).with "bar"
+ loader << "foo" << "bar"
+ end
+
+ it "should set itself as the code collection for added resource types" do
+ loader = Puppet::Parser::LoadedCode.new
+
+ node = Puppet::Parser::ResourceType.new(:node, "foo")
+
+ @code.add(node)
+ @code.node("foo").should equal(node)
+
+ node.code_collection.should equal(@code)
+ end
+
+ it "should store node resource types as nodes" do
+ node = Puppet::Parser::ResourceType.new(:node, "foo")
+
+ @code.add(node)
+ @code.node("foo").should equal(node)
+ end
+
+ it "should store hostclasses as hostclasses" do
+ klass = Puppet::Parser::ResourceType.new(:hostclass, "foo")
+
+ @code.add(klass)
+ @code.hostclass("foo").should equal(klass)
+ end
+
+ it "should store definitions as definitions" do
+ define = Puppet::Parser::ResourceType.new(:definition, "foo")
+
+ @code.add(define)
+ @code.definition("foo").should equal(define)
+ end
+
%w{hostclass node definition}.each do |data|
it "should have a method for adding a #{data}" do
Puppet::Parser::LoadedCode.new.should respond_to("add_" + data)
end
+ it "should use the name of the instance to add it" do
+ loader = Puppet::Parser::LoadedCode.new
+ loader.send("add_#{data}", @instance)
+ loader.send(data, @instance.name).should equal(@instance)
+ end
+
+ it "should fail to add a #{data} when one already exists" do
+ loader = Puppet::Parser::LoadedCode.new
+ loader.add @instance
+ lambda { loader.add(@instance) }.should raise_error(Puppet::ParseError)
+ end
+
+ it "should return the added #{data}" do
+ loader = Puppet::Parser::LoadedCode.new
+
+ loader.add(@instance).should equal(@instance)
+ end
+
it "should be able to retrieve #{data} by name" do
loader = Puppet::Parser::LoadedCode.new
- loader.send("add_" + data, "foo", "bar")
- loader.send(data, "foo").should == "bar"
+ instance = Puppet::Parser::ResourceType.new(data, "bar")
+ loader.add instance
+ loader.send(data, "bar").should equal(instance)
end
it "should retrieve #{data} insensitive to case" do
loader = Puppet::Parser::LoadedCode.new
- loader.send("add_" + data, "Foo", "bar")
- loader.send(data, "fOo").should == "bar"
+ instance = Puppet::Parser::ResourceType.new(data, "Bar")
+ loader.add instance
+ loader.send(data, "bAr").should equal(instance)
end
it "should return nil when asked for a #{data} that has not been added" do
@@ -29,16 +98,18 @@ describe Puppet::Parser::LoadedCode do
it "should be able to retrieve all #{data}s" do
plurals = { "hostclass" => "hostclasses", "node" => "nodes", "definition" => "definitions" }
loader = Puppet::Parser::LoadedCode.new
- loader.send("add_" + data , "foo", "bar")
- loader.send(plurals[data]).should == { "foo" => "bar" }
+ instance = Puppet::Parser::ResourceType.new(data, "foo")
+ loader.add instance
+ loader.send(plurals[data]).should == { "foo" => instance }
end
end
describe "when finding a qualified instance" do
it "should return any found instance if the instance name is fully qualified" do
loader = Puppet::Parser::LoadedCode.new
- loader.add_hostclass "foo::bar", "yay"
- loader.find("namespace", "::foo::bar", :hostclass).should == "yay"
+ instance = Puppet::Parser::ResourceType.new(:hostclass, "foo::bar")
+ loader.add instance
+ loader.find("namespace", "::foo::bar", :hostclass).should equal(instance)
end
it "should return nil if the instance name is fully qualified and no such instance exists" do
@@ -48,37 +119,43 @@ describe Puppet::Parser::LoadedCode do
it "should return the partially qualified object if it exists in the provided namespace" do
loader = Puppet::Parser::LoadedCode.new
- loader.add_hostclass "foo::bar::baz", "yay"
- loader.find("foo", "bar::baz", :hostclass).should == "yay"
+ instance = Puppet::Parser::ResourceType.new(:hostclass, "foo::bar::baz")
+ loader.add instance
+ loader.find("foo", "bar::baz", :hostclass).should equal(instance)
end
it "should return the unqualified object if it exists in the provided namespace" do
loader = Puppet::Parser::LoadedCode.new
- loader.add_hostclass "foo::bar", "yay"
- loader.find("foo", "bar", :hostclass).should == "yay"
+ instance = Puppet::Parser::ResourceType.new(:hostclass, "foo::bar")
+ loader.add instance
+ loader.find("foo", "bar", :hostclass).should equal(instance)
end
it "should return the unqualified object if it exists in the parent namespace" do
loader = Puppet::Parser::LoadedCode.new
- loader.add_hostclass "foo::bar", "yay"
- loader.find("foo::bar::baz", "bar", :hostclass).should == "yay"
+ instance = Puppet::Parser::ResourceType.new(:hostclass, "foo::bar")
+ loader.add instance
+ loader.find("foo::bar::baz", "bar", :hostclass).should equal(instance)
end
it "should should return the partially qualified object if it exists in the parent namespace" do
loader = Puppet::Parser::LoadedCode.new
- loader.add_hostclass "foo::bar::baz", "yay"
- loader.find("foo::bar", "bar::baz", :hostclass).should == "yay"
+ instance = Puppet::Parser::ResourceType.new(:hostclass, "foo::bar::baz")
+ loader.add instance
+ loader.find("foo::bar", "bar::baz", :hostclass).should equal(instance)
end
it "should return the qualified object if it exists in the root namespace" do
loader = Puppet::Parser::LoadedCode.new
- loader.add_hostclass "foo::bar::baz", "yay"
- loader.find("foo::bar", "foo::bar::baz", :hostclass).should == "yay"
+ instance = Puppet::Parser::ResourceType.new(:hostclass, "foo::bar::baz")
+ loader.add instance
+ loader.find("foo::bar", "foo::bar::baz", :hostclass).should equal(instance)
end
it "should return nil if the object cannot be found" do
loader = Puppet::Parser::LoadedCode.new
- loader.add_hostclass "foo::bar::baz", "yay"
+ instance = Puppet::Parser::ResourceType.new(:hostclass, "foo::bar::baz")
+ loader.add instance
loader.find("foo::bar", "eh", :hostclass).should be_nil
end
end
@@ -103,7 +180,7 @@ describe Puppet::Parser::LoadedCode do
it "should indicate whether any nodes are defined" do
loader = Puppet::Parser::LoadedCode.new
- loader.add_node("foo", "bar")
+ loader.add_node(Puppet::Parser::ResourceType.new(:node, "foo"))
loader.should be_nodes
end
@@ -111,105 +188,32 @@ describe Puppet::Parser::LoadedCode do
Puppet::Parser::LoadedCode.new.should_not be_nodes
end
- describe "when adding nodes" do
- it "should create an HostName if nodename is a string" do
- Puppet::Parser::AST::HostName.expects(:new).with(:value => "foo")
- loader = Puppet::Parser::LoadedCode.new
- loader.add_node("foo", "bar")
- end
-
- it "should not create an HostName if nodename is an HostName" do
- name = Puppet::Parser::AST::HostName.new(:value => "foo")
-
- Puppet::Parser::AST::HostName.expects(:new).with(:value => "foo").never
-
- loader = Puppet::Parser::LoadedCode.new
- loader.add_node(name, "bar")
- end
- end
-
describe "when finding nodes" do
before :each do
@loader = Puppet::Parser::LoadedCode.new
-
- @nodename1 = stub 'nodename1', :is_a? => true
- @node1 = stub 'node1'
- @nodename2 = stub 'nodename2', :is_a? => true
- @node2 = stub 'node2'
- end
- it "should create an HostName if nodename is a string" do
- Puppet::Parser::AST::HostName.expects(:new).with(:value => "foo")
-
- @loader.node("foo")
- end
-
- it "should not create an HostName if nodename is an HostName" do
- name = Puppet::Parser::AST::HostName.new(:value => "foo")
-
- Puppet::Parser::AST::HostName.expects(:new).with(:value => "foo").never
-
- @loader.node(name)
- end
-
- it "should be able to find node by HostName" do
- namein = Puppet::Parser::AST::HostName.new(:value => "foo")
- nameout = Puppet::Parser::AST::HostName.new(:value => "foo")
-
- @loader.add_node(namein, "bar")
- @loader.node(nameout).should == "bar"
end
- it "should be able to find node by HostName strict equality" do
- namein = Puppet::Parser::AST::HostName.new(:value => "foo")
- nameout = Puppet::Parser::AST::HostName.new(:value => "foo")
+ it "should return any node whose name exactly matches the provided node name" do
+ node = Puppet::Parser::ResourceType.new(:node, "foo")
+ @loader << node
- @loader.add_node(namein, "bar")
- @loader.node_exists?(nameout).should == "bar"
+ @loader.node("foo").should equal(node)
end
- it "should not use node name matching when finding with strict node HostName" do
- name1 = Puppet::Parser::AST::HostName.new(:value => "foo")
- name2 = Puppet::Parser::AST::HostName.new(:value => Puppet::Parser::AST::Regex.new(:value => /foo/))
+ it "should return the first regex node whose regex matches the provided node name" do
+ node1 = Puppet::Parser::ResourceType.new(:node, /\w/)
+ node2 = Puppet::Parser::ResourceType.new(:node, /\d/)
+ @loader << node1 << node2
- @loader.add_node(name1, "bar")
- @loader.add_node(name2, "baz")
- @loader.node_exists?(name1).should == "bar"
+ @loader.node("foo10").should equal(node1)
end
- it "should return the first matching regex nodename" do
- @nodename1.stubs(:regex?).returns(true)
- @nodename1.stubs(:match).returns(true)
- @nodename2.stubs(:regex?).returns(true)
- @nodename2.stubs(:match).returns(true)
-
- @loader.add_node(@nodename1, @node1)
- @loader.add_node(@nodename2, @node2)
-
- @loader.node("test").should == @node1
- end
-
- it "should not scan non-regex node" do
- @nodename1.stubs(:regex?).returns(true)
- @nodename1.stubs(:match).returns(false)
- @nodename2.stubs(:regex?).returns(false)
- @nodename2.expects(:match).never
-
- @loader.add_node(@nodename1,@node1)
- @loader.add_node(@nodename2,@node2)
-
- @loader.node("test")
- end
-
- it "should prefer non-regex nodes to regex nodes" do
- @nodename1.stubs(:regex?).returns(false)
- @nodename1.expects(:match).never
- @nodename2.stubs(:regex?).returns(true)
- @nodename2.expects(:match).never
-
- @loader.add_node(@nodename1,@node1)
- @loader.add_node(@nodename2,@node2)
+ it "should preferentially return a node whose name is string-equal over returning a node whose regex matches a provided name" do
+ node1 = Puppet::Parser::ResourceType.new(:node, /\w/)
+ node2 = Puppet::Parser::ResourceType.new(:node, "foo")
+ @loader << node1 << node2
- @loader.node(@nodename1)
+ @loader.node("foo").should equal(node2)
end
end
end
diff --git a/spec/unit/parser/parser.rb b/spec/unit/parser/parser.rb
index 78caf18b0..a04444674 100755
--- a/spec/unit/parser/parser.rb
+++ b/spec/unit/parser/parser.rb
@@ -174,56 +174,62 @@ describe Puppet::Parser do
end
end
- describe "when instantiating class of same name" do
-
- before :each do
- @one = stub 'one', :is_a? => true
- @one.stubs(:is_a?).with(ast::ASTArray).returns(false)
- @one.stubs(:is_a?).with(ast).returns(true)
-
- @two = stub 'two'
- @two.stubs(:is_a?).with(ast::ASTArray).returns(false)
- @two.stubs(:is_a?).with(ast).returns(true)
+ describe "when providing AST context" do
+ before do
+ @lexer = stub 'lexer', :line => 50, :file => "/foo/bar", :getcomment => "whev"
+ @parser.stubs(:lexer).returns @lexer
end
- it "should return the first class" do
-
- klass1 = @parser.newclass("one", { :code => @one })
+ it "should include the lexer's line" do
+ @parser.ast_context[:line].should == 50
+ end
- @parser.newclass("one", { :code => @two }).should == klass1
+ it "should include the lexer's file" do
+ @parser.ast_context[:file].should == "/foo/bar"
end
- it "should concatenate code" do
- klass1 = @parser.newclass("one", { :code => @one })
+ it "should include the docs if directed to do so" do
+ @parser.ast_context(true)[:doc].should == "whev"
+ end
- @parser.newclass("one", { :code => @two })
+ it "should not include the docs when told not to" do
+ @parser.ast_context(false)[:doc].should be_nil
+ end
- klass1.code.children.should == [@one,@two]
+ it "should not include the docs by default" do
+ @parser.ast_context()[:doc].should be_nil
end
end
- describe "when parsing comments before statement" do
- it "should associate the documentation to the statement AST node" do
- ast = @parser.parse("""
- # comment
- class test {}
- """)
+ describe "when building ast nodes" do
+ before do
+ @lexer = stub 'lexer', :line => 50, :file => "/foo/bar", :getcomment => "whev"
+ @parser.stubs(:lexer).returns @lexer
+ @class = stub 'class', :use_docs => false
+ end
- ast.hostclass("test").doc.should == "comment\n"
+ it "should return a new instance of the provided class created with the provided options" do
+ @class.expects(:new).with { |opts| opts[:foo] == "bar" }
+ @parser.ast(@class, :foo => "bar")
end
- end
- describe "when building ast nodes" do
- it "should get lexer comments if ast node declares use_docs" do
- lexer = stub 'lexer'
- ast = mock 'ast', :nil? => false, :use_docs => true, :doc => ""
- @parser.stubs(:lexer).returns(lexer)
+ it "should merge the ast context into the provided options" do
+ @class.expects(:new).with { |opts| opts[:file] == "/foo" }
+ @parser.expects(:ast_context).returns :file => "/foo"
+ @parser.ast(@class, :foo => "bar")
+ end
- Puppet::Parser::AST::Definition.expects(:new).returns(ast)
- lexer.expects(:getcomment).returns("comment")
- ast.expects(:doc=).with("comment")
+ it "should prefer provided options over AST context" do
+ @class.expects(:new).with { |opts| opts[:file] == "/bar" }
+ @parser.expects(:ast_context).returns :file => "/foo"
+ @parser.ast(@class, :file => "/bar")
+ end
- @parser.ast(Puppet::Parser::AST::Definition)
+ it "should include docs when the AST class uses them" do
+ @class.expects(:use_docs).returns true
+ @class.stubs(:new)
+ @parser.expects(:ast_context).with(true).returns({})
+ @parser.ast(@class, :file => "/bar")
end
end
@@ -233,59 +239,15 @@ describe Puppet::Parser do
@lexer.stubs(:getcomment)
@parser.stubs(:lexer).returns(@lexer)
@node = stub_everything 'node'
- @parser.stubs(:ast).returns(@node)
+ @parser.stubs(:ast_context).returns({})
@parser.stubs(:node).returns(nil)
- @nodename = stub 'nodename', :is_a? => false, :to_classname => "node"
+ @nodename = stub 'nodename', :is_a? => false, :value => "foo"
@nodename.stubs(:is_a?).with(Puppet::Parser::AST::HostName).returns(true)
end
- it "should get the lexer stacked comments" do
- @lexer.expects(:getcomment)
-
- @parser.newnode(@nodename)
- end
-
- it "should create an HostName if needed" do
- Puppet::Parser::AST::HostName.expects(:new).with(:value => "node").returns(@nodename)
-
- @parser.newnode("node")
- end
-
- it "should raise an error if the node already exists" do
- @loaded_code.stubs(:node_exists?).with(@nodename).returns(@node)
-
- lambda { @parser.newnode(@nodename) }.should raise_error
- end
-
- it "should store the created node in the loaded code" do
- @loaded_code.expects(:add_node).with(@nodename, @node)
-
- @parser.newnode(@nodename)
- end
-
- it "should create the node with code if provided" do
- @parser.stubs(:ast).with { |*args| args[1][:code] == :code }.returns(@node)
-
- @parser.newnode(@nodename, :code => :code)
- end
-
- it "should create the node with a parentclass if provided" do
- @parser.stubs(:ast).with { |*args| args[1][:parent] == :parent }.returns(@node)
-
- @parser.newnode(@nodename, :parent => :parent)
- end
-
- it "should set the node classname from the HostName" do
- @nodename.stubs(:to_classname).returns(:classname)
-
- @node.expects(:classname=).with(:classname)
-
- @parser.newnode(@nodename)
- end
-
it "should return an array of nodes" do
- @parser.newnode(@nodename).should == [@node]
+ @parser.newnode(@nodename).should be_instance_of(Array)
end
end
diff --git a/spec/unit/parser/resource/reference.rb b/spec/unit/parser/resource/reference.rb
index 6284e67cc..e082136c5 100755
--- a/spec/unit/parser/resource/reference.rb
+++ b/spec/unit/parser/resource/reference.rb
@@ -84,7 +84,7 @@ describe Puppet::Parser::Resource::Reference, " when modeling defined types" do
scope = @compiler.topscope.class.new(:parent => @compiler.topscope, :namespace => "other", :parser => @parser)
ref = @type.new(:type => "class", :title => "top", :scope => scope)
- ref.definedtype.classname.should equal(top.classname)
+ ref.definedtype.name.should equal(top.name)
end
it "should only look for fully qualified definitions" do
@@ -94,6 +94,6 @@ describe Puppet::Parser::Resource::Reference, " when modeling defined types" do
scope = @compiler.topscope.class.new(:parent => @compiler.topscope, :namespace => "other", :parser => @parser)
ref = @type.new(:type => "top", :title => "foo", :scope => scope)
- ref.definedtype.classname.should equal(top.classname)
+ ref.definedtype.name.should equal(top.name)
end
end
diff --git a/spec/unit/parser/resource_type.rb b/spec/unit/parser/resource_type.rb
new file mode 100755
index 000000000..ddf8ce951
--- /dev/null
+++ b/spec/unit/parser/resource_type.rb
@@ -0,0 +1,522 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/parser/resource_type'
+
+describe Puppet::Parser::ResourceType do
+ it "should have a 'name' attribute" do
+ Puppet::Parser::ResourceType.new(:hostclass, "foo").name.should == "foo"
+ end
+
+ [:code, :doc, :line, :file, :code_collection].each do |attr|
+ it "should have a '#{attr}' attribute" do
+ type = Puppet::Parser::ResourceType.new(:hostclass, "foo")
+ type.send(attr.to_s + "=", "yay")
+ type.send(attr).should == "yay"
+ end
+ end
+
+ describe "when a node" do
+ it "should allow a regex as its name" do
+ lambda { Puppet::Parser::ResourceType.new(:node, /foo/) }.should_not raise_error
+ end
+
+ it "should allow a AST::HostName instance as its name" do
+ regex = Puppet::Parser::AST::Regex.new(:value => /foo/)
+ name = Puppet::Parser::AST::HostName.new(:value => regex)
+ lambda { Puppet::Parser::ResourceType.new(:node, name) }.should_not raise_error
+ end
+
+ it "should match against the regexp in the AST::HostName when a HostName instance is provided" do
+ regex = Puppet::Parser::AST::Regex.new(:value => /\w/)
+ name = Puppet::Parser::AST::HostName.new(:value => regex)
+ node = Puppet::Parser::ResourceType.new(:node, name)
+
+ node.match("foo").should be_true
+ end
+
+ it "should return the value of the hostname if provided a string-form AST::HostName instance as the name" do
+ name = Puppet::Parser::AST::HostName.new(:value => "foo")
+ node = Puppet::Parser::ResourceType.new(:node, name)
+
+ node.name.should == "foo"
+ end
+
+ describe "and the name is a regex" do
+ it "should have a method that indicates that this is the case" do
+ Puppet::Parser::ResourceType.new(:node, /w/).should be_name_is_regex
+ end
+
+ it "should set its namespace to ''" do
+ Puppet::Parser::ResourceType.new(:node, /w/).namespace.should == ""
+ end
+
+ it "should return the regex converted to a string when asked for its name" do
+ Puppet::Parser::ResourceType.new(:node, /ww/).name.should == "ww"
+ end
+
+ it "should downcase the regex when returning the name as a string" do
+ Puppet::Parser::ResourceType.new(:node, /W/).name.should == "w"
+ end
+
+ it "should remove non-alpha characters when returning the name as a string" do
+ Puppet::Parser::ResourceType.new(:node, /w*w/).name.should_not include("*")
+ end
+
+ it "should remove leading dots when returning the name as a string" do
+ Puppet::Parser::ResourceType.new(:node, /.ww/).name.should_not =~ /^\./
+ end
+
+ it "should have a method for matching its regex name against a provided name" do
+ Puppet::Parser::ResourceType.new(:node, /.ww/).should respond_to(:match)
+ end
+
+ it "should return true when its regex matches the provided name" do
+ Puppet::Parser::ResourceType.new(:node, /\w/).match("foo").should be_true
+ end
+
+ it "should return false when its regex does not match the provided name" do
+ (!!Puppet::Parser::ResourceType.new(:node, /\d/).match("foo")).should be_false
+ end
+
+ it "should return true when its name, as a string, is matched against an equal string" do
+ Puppet::Parser::ResourceType.new(:node, "foo").match("foo").should be_true
+ end
+
+ it "should return false when its name is matched against an unequal string" do
+ Puppet::Parser::ResourceType.new(:node, "foo").match("bar").should be_false
+ end
+
+ it "should match names insensitive to case" do
+ Puppet::Parser::ResourceType.new(:node, "fOo").match("foO").should be_true
+ end
+ end
+
+ it "should return the name converted to a string when the name is not a regex" do
+ pending "Need to define LoadedCode behaviour first"
+ name = Puppet::Parser::AST::HostName.new(:value => "foo")
+ Puppet::Parser::ResourceType.new(:node, name).name.should == "foo"
+ end
+
+ it "should return the name converted to a string when the name is a regex" do
+ pending "Need to define LoadedCode behaviour first"
+ name = Puppet::Parser::AST::HostName.new(:value => /regex/)
+ Puppet::Parser::ResourceType.new(:node, name).name.should == /regex/.to_s
+ end
+
+ it "should mark any created scopes as a node scope" do
+ pending "Need to define LoadedCode behaviour first"
+ name = Puppet::Parser::AST::HostName.new(:value => /regex/)
+ Puppet::Parser::ResourceType.new(:node, name).name.should == /regex/.to_s
+ end
+ end
+
+ describe "when initializing" do
+ it "should require a resource super type" do
+ Puppet::Parser::ResourceType.new(:hostclass, "foo").type.should == :hostclass
+ end
+
+ it "should fail if provided an invalid resource super type" do
+ lambda { Puppet::Parser::ResourceType.new(:nope, "foo") }.should raise_error(ArgumentError)
+ end
+
+ it "should set its name to the downcased, stringified provided name" do
+ Puppet::Parser::ResourceType.new(:hostclass, "Foo::Bar".intern).name.should == "foo::bar"
+ end
+
+ it "should set its namespace to the downcased, stringified qualified portion of the name" do
+ Puppet::Parser::ResourceType.new(:hostclass, "Foo::Bar::Baz".intern).namespace.should == "foo::bar"
+ end
+
+ %w{code line file doc}.each do |arg|
+ it "should set #{arg} if provided" do
+ type = Puppet::Parser::ResourceType.new(:hostclass, "foo", arg.to_sym => "something")
+ type.send(arg).should == "something"
+ end
+ end
+
+ it "should set any provided arguments with the keys as symbols" do
+ type = Puppet::Parser::ResourceType.new(:hostclass, "foo", :arguments => {:foo => "bar", :baz => "biz"})
+ type.should be_validattr("foo")
+ type.should be_validattr("baz")
+ end
+
+ it "should set any provided arguments with they keys as strings" do
+ type = Puppet::Parser::ResourceType.new(:hostclass, "foo", :arguments => {"foo" => "bar", "baz" => "biz"})
+ type.should be_validattr(:foo)
+ type.should be_validattr(:baz)
+ end
+
+ it "should function if provided no arguments" do
+ type = Puppet::Parser::ResourceType.new(:hostclass, "foo")
+ type.should_not be_validattr(:foo)
+ end
+ end
+
+ describe "when testing the validity of an attribute" do
+ it "should return true if the parameter was typed at initialization" do
+ Puppet::Parser::ResourceType.new(:hostclass, "foo", :arguments => {"foo" => "bar"}).should be_validattr("foo")
+ end
+
+ it "should return true if it is a metaparam" do
+ Puppet::Parser::ResourceType.new(:hostclass, "foo").should be_validattr("require")
+ end
+
+ it "should return true if the parameter is named 'name'" do
+ Puppet::Parser::ResourceType.new(:hostclass, "foo").should be_validattr("name")
+ end
+
+ it "should return false if it is not a metaparam and was not provided at initialization" do
+ Puppet::Parser::ResourceType.new(:hostclass, "foo").should_not be_validattr("yayness")
+ end
+ end
+
+ describe "when creating a subscope" do
+ before do
+ @scope = stub 'scope', :newscope => nil
+ @resource = stub 'resource'
+ @type = Puppet::Parser::ResourceType.new(:hostclass, "foo")
+ end
+
+ it "should return a new scope created with the provided scope as the parent" do
+ @scope.expects(:newscope).returns "foo"
+ @type.subscope(@scope, @resource).should == "foo"
+ end
+
+ it "should set the source as itself" do
+ @scope.expects(:newscope).with { |args| args[:source] == @type }
+ @type.subscope(@scope, @resource)
+ end
+
+ it "should set the scope's namespace to its namespace" do
+ @type.expects(:namespace).returns "yayness"
+ @scope.expects(:newscope).with { |args| args[:namespace] == "yayness" }
+ @type.subscope(@scope, @resource)
+ end
+
+ it "should set the scope's resource to the provided resource" do
+ @scope.expects(:newscope).with { |args| args[:resource] == @resource }
+ @type.subscope(@scope, @resource)
+ end
+ end
+
+ describe "when setting its parameters in the scope" do
+ before do
+ @scope = stub 'scope', :newscope => nil, :setvar => nil
+ @resource = stub 'resource', :title => "yay", :name => "yea", :ref => "Foo[bar]"
+ @type = Puppet::Parser::ResourceType.new(:hostclass, "foo")
+ end
+
+ it "should set each of the resource's parameters as variables in the scope" do
+ @type.set_arguments :foo => nil, :boo => nil
+ @resource.expects(:to_hash).returns(:foo => "bar", :boo => "baz")
+
+ @scope.expects(:setvar).with("foo", "bar")
+ @scope.expects(:setvar).with("boo", "baz")
+
+ @type.set_resource_parameters(@resource, @scope)
+ end
+
+ it "should set the variables as strings" do
+ @type.set_arguments :foo => nil
+ @resource.expects(:to_hash).returns(:foo => "bar")
+ @scope.expects(:setvar).with("foo", "bar")
+
+ @type.set_resource_parameters(@resource, @scope)
+ end
+
+ it "should fail if any of the resource's parameters are not valid attributes" do
+ @type.set_arguments :foo => nil
+ @resource.expects(:to_hash).returns(:boo => "baz")
+
+ lambda { @type.set_resource_parameters(@resource, @scope) }.should raise_error(Puppet::ParseError)
+ end
+
+ it "should evaluate and set its default values as variables for parameters not provided by the resource" do
+ @type.set_arguments :foo => stub("value", :safeevaluate => "something")
+ @resource.expects(:to_hash).returns({})
+
+ @scope.expects(:setvar).with("foo", "something")
+
+ @type.set_resource_parameters(@resource, @scope)
+ end
+
+ it "should fail if the resource does not provide a value for a required argument" do
+ @type.set_arguments :foo => nil
+ @resource.expects(:to_hash).returns({})
+
+ lambda { @type.set_resource_parameters(@resource, @scope) }.should raise_error(Puppet::ParseError)
+ end
+
+ it "should set the resource's title as a variable if not otherwise provided" do
+ @resource.expects(:to_hash).returns({})
+
+ @resource.expects(:title).returns 'teetle'
+ @scope.expects(:setvar).with("title", "teetle")
+
+ @type.set_resource_parameters(@resource, @scope)
+ end
+
+ it "should set the resource's name as a variable if not otherwise provided" do
+ @resource.expects(:to_hash).returns({})
+
+ @resource.expects(:name).returns 'nombre'
+ @scope.expects(:setvar).with("name", "nombre")
+
+ @type.set_resource_parameters(@resource, @scope)
+ end
+ end
+
+ describe "when describing and managing parent classes" do
+ before do
+ @code = Puppet::Parser::LoadedCode.new
+ @parent = Puppet::Parser::ResourceType.new(:hostclass, "bar")
+ @code.add @parent
+
+ @child = Puppet::Parser::ResourceType.new(:hostclass, "foo", :parent => "bar")
+ @code.add @child
+ end
+
+ it "should be able to define a parent" do
+ Puppet::Parser::ResourceType.new(:hostclass, "foo", :parent => "bar")
+ end
+
+ it "should use the code collection to find the parent resource type" do
+ @child.parent_type.should equal(@parent)
+ end
+
+ it "should be able to find parent nodes" do
+ parent = Puppet::Parser::ResourceType.new(:node, "bar")
+ @code.add parent
+ child = Puppet::Parser::ResourceType.new(:node, "foo", :parent => "bar")
+ @code.add child
+
+ child.parent_type.should equal(parent)
+ end
+
+ it "should cache a reference to the parent type" do
+ @code.expects(:hostclass).once.with("bar").returns @parent
+ @child.parent_type
+ @child.parent_type
+ end
+
+ it "should correctly state when it is another type's child" do
+ @child.should be_child_of(@parent)
+ end
+
+ it "should be considered the child of a parent's parent" do
+ @grandchild = Puppet::Parser::ResourceType.new(:hostclass, "baz", :parent => "foo")
+ @code.add @grandchild
+
+ @grandchild.should be_child_of(@parent)
+ end
+
+ it "should correctly state when it is not another type's child" do
+ @notchild = Puppet::Parser::ResourceType.new(:hostclass, "baz")
+ @code.add @notchild
+
+ @notchild.should_not be_child_of(@parent)
+ end
+ end
+
+ describe "when evaluating its code" do
+ before do
+ @scope = stub 'scope', :newscope => nil, :setvar => nil
+ @resource = stub 'resource', :title => "yay", :name => "yea", :ref => "Foo[bar]", :scope => @scope
+ @type = Puppet::Parser::ResourceType.new(:hostclass, "foo")
+ @type.stubs(:set_resource_parameters)
+ end
+
+ it "should set all of its parameters in a subscope" do
+ subscope = stub 'subscope'
+ @type.expects(:subscope).with(@scope, @resource).returns subscope
+ @type.expects(:set_resource_parameters).with(@resource, subscope)
+
+ @type.evaluate_code(@resource)
+ end
+
+ it "should evaluate the code if any is provided" do
+ code = stub 'code'
+ @type.expects(:code).returns code
+ @type.stubs(:subscope).returns stub("subscope")
+ code.expects(:safeevaluate).with @type.subscope
+
+ @type.evaluate_code(@resource)
+ end
+
+ it "should noop if there is no code" do
+ @type.expects(:code).returns nil
+ @type.stubs(:subscope).returns stub("subscope")
+
+ @type.evaluate_code(@resource)
+ end
+ end
+
+ describe "when creating a resource" do
+ before do
+ @catalog = Puppet::Resource::Catalog.new
+ @node = stub 'node', :name => "foo", :classes => []
+ @compiler = Puppet::Parser::Compiler.new(@node, @catalog)
+ @scope = Puppet::Parser::Scope.new
+ @scope.stubs(:compiler).returns @compiler
+
+ @top = Puppet::Parser::ResourceType.new :hostclass, "top"
+ @middle = Puppet::Parser::ResourceType.new :hostclass, "middle", :parent => "top"
+
+ @code = Puppet::Parser::LoadedCode.new
+ @code.add @top
+ @code.add @middle
+ end
+
+ it "should create a resource instance" do
+ @top.mk_plain_resource(@scope).should be_instance_of(Puppet::Parser::Resource)
+ end
+
+ it "should set its resource type to 'class' when it is a hostclass" do
+ Puppet::Parser::ResourceType.new(:hostclass, "top").mk_plain_resource(@scope).type.should == "Class"
+ end
+
+ it "should set its resource type to 'node' when it is a node" do
+ Puppet::Parser::ResourceType.new(:node, "top").mk_plain_resource(@scope).type.should == "Node"
+ end
+
+ it "should fail when it is a definition" do
+ lambda { Puppet::Parser::ResourceType.new(:definition, "top").mk_plain_resource(@scope) }.should raise_error(ArgumentError)
+ end
+
+ it "should add the created resource to the scope's catalog" do
+ @top.mk_plain_resource(@scope)
+
+ @compiler.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource)
+ end
+
+ it "should evaluate the parent class if one exists" do
+ @middle.mk_plain_resource(@scope)
+
+ @compiler.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource)
+ end
+
+ it "should fail to evaluate if a parent class is defined but cannot be found" do
+ othertop = Puppet::Parser::ResourceType.new :hostclass, "something", :parent => "yay"
+ @code.add othertop
+ lambda { othertop.mk_plain_resource(@scope) }.should raise_error(Puppet::ParseError)
+ end
+
+ it "should not create a new resource if one already exists" do
+ @compiler.catalog.expects(:resource).with(:class, "top").returns("something")
+ @compiler.catalog.expects(:add_resource).never
+ @top.mk_plain_resource(@scope)
+ end
+
+ it "should return the existing resource when not creating a new one" do
+ @compiler.catalog.expects(:resource).with(:class, "top").returns("something")
+ @compiler.catalog.expects(:add_resource).never
+ @top.mk_plain_resource(@scope).should == "something"
+ end
+
+ it "should not create a new parent resource if one already exists and it has a parent class" do
+ @top.mk_plain_resource(@scope)
+
+ top_resource = @compiler.catalog.resource(:class, "top")
+
+ @middle.mk_plain_resource(@scope)
+
+ @compiler.catalog.resource(:class, "top").should equal(top_resource)
+ end
+
+ # #795 - tag before evaluation.
+ it "should tag the catalog with the resource tags when it is evaluated" do
+ @middle.mk_plain_resource(@scope)
+
+ @compiler.catalog.should be_tagged("middle")
+ end
+
+ it "should tag the catalog with the parent class tags when it is evaluated" do
+ @middle.mk_plain_resource(@scope)
+
+ @compiler.catalog.should be_tagged("top")
+ end
+ end
+
+ describe "when merging code from another instance" do
+ def code(str)
+ Puppet::Parser::AST::Leaf.new :value => str
+ end
+
+ it "should fail unless it is a class" do
+ lambda { Puppet::Parser::ResourceType.new(:node, "bar").merge("foo") }.should raise_error(ArgumentError)
+ end
+
+ it "should fail unless the source instance is a class" do
+ dest = Puppet::Parser::ResourceType.new(:hostclass, "bar")
+ source = Puppet::Parser::ResourceType.new(:node, "foo")
+ lambda { dest.merge(source) }.should raise_error(ArgumentError)
+ end
+
+ it "should fail if both classes have different parent classes" do
+ code = Puppet::Parser::LoadedCode.new
+ {"a" => "b", "c" => "d"}.each do |parent, child|
+ code.add Puppet::Parser::ResourceType.new(:hostclass, parent)
+ code.add Puppet::Parser::ResourceType.new(:hostclass, child, :parent => parent)
+ end
+ lambda { code.hostclass("b").merge(code.hostclass("d")) }.should raise_error(ArgumentError)
+ end
+
+ it "should copy the other class's parent if it has not parent" do
+ dest = Puppet::Parser::ResourceType.new(:hostclass, "bar")
+
+ parent = Puppet::Parser::ResourceType.new(:hostclass, "parent")
+ source = Puppet::Parser::ResourceType.new(:hostclass, "foo", :parent => "parent")
+ dest.merge(source)
+
+ dest.parent.should == "parent"
+ end
+
+ it "should copy the other class's documentation as its docs if it has no docs" do
+ dest = Puppet::Parser::ResourceType.new(:hostclass, "bar")
+ source = Puppet::Parser::ResourceType.new(:hostclass, "foo", :doc => "yayness")
+ dest.merge(source)
+
+ dest.doc.should == "yayness"
+ end
+
+ it "should append the other class's docs to its docs if it has any" do
+ dest = Puppet::Parser::ResourceType.new(:hostclass, "bar", :doc => "fooness")
+ source = Puppet::Parser::ResourceType.new(:hostclass, "foo", :doc => "yayness")
+ dest.merge(source)
+
+ dest.doc.should == "foonessyayness"
+ end
+
+ it "should turn its code into an ASTArray if necessary" do
+ dest = Puppet::Parser::ResourceType.new(:hostclass, "bar", :code => code("foo"))
+ source = Puppet::Parser::ResourceType.new(:hostclass, "foo", :code => code("bar"))
+
+ dest.merge(source)
+
+ dest.code.should be_instance_of(Puppet::Parser::AST::ASTArray)
+ end
+
+ it "should set the other class's code as its code if it has none" do
+ dest = Puppet::Parser::ResourceType.new(:hostclass, "bar")
+ source = Puppet::Parser::ResourceType.new(:hostclass, "foo", :code => code("bar"))
+
+ dest.merge(source)
+
+ dest.code.value.should == "bar"
+ end
+
+ it "should append the other class's code to its code if it has any" do
+ dcode = Puppet::Parser::AST::ASTArray.new :children => [code("dest")]
+ dest = Puppet::Parser::ResourceType.new(:hostclass, "bar", :code => dcode)
+
+ scode = Puppet::Parser::AST::ASTArray.new :children => [code("source")]
+ source = Puppet::Parser::ResourceType.new(:hostclass, "foo", :code => scode)
+
+ dest.merge(source)
+
+ dest.code.children.collect { |l| l.value }.should == %w{dest source}
+ end
+ end
+end
diff --git a/spec/unit/util/rdoc/parser.rb b/spec/unit/util/rdoc/parser.rb
index 593e6acc8..19c91bb9a 100755
--- a/spec/unit/util/rdoc/parser.rb
+++ b/spec/unit/util/rdoc/parser.rb
@@ -137,9 +137,9 @@ describe RDoc::Parser do
describe "when parsing AST elements" do
before :each do
- @klass = stub_everything 'klass', :file => "module/manifests/init.pp", :classname => "myclass"
- @definition = stub_everything 'definition', :file => "module/manifests/init.pp"
- @node = stub_everything 'node', :file => "module/manifests/init.pp"
+ @klass = stub_everything 'klass', :file => "module/manifests/init.pp", :name => "myclass", :type => :hostclass
+ @definition = stub_everything 'definition', :file => "module/manifests/init.pp", :type => :definition, :name => "mydef"
+ @node = stub_everything 'node', :file => "module/manifests/init.pp", :type => :node, :name => "mynode"
@loadedcode = Puppet::Parser::LoadedCode.new
@parser.ast = @loadedcode
@@ -148,7 +148,7 @@ describe RDoc::Parser do
end
it "should document classes in the parsed file" do
- @loadedcode.add_hostclass("myclass", @klass)
+ @loadedcode.add_hostclass(@klass)
@parser.expects(:document_class).with("myclass", @klass, @container)
@@ -157,7 +157,7 @@ describe RDoc::Parser do
it "should not document class parsed in an other file" do
@klass.stubs(:file).returns("/not/same/path/file.pp")
- @loadedcode.add_hostclass("myclass", @klass)
+ @loadedcode.add_hostclass(@klass)
@parser.expects(:document_class).with("myclass", @klass, @container).never
@@ -165,10 +165,11 @@ describe RDoc::Parser do
end
it "should document vardefs for the main class" do
- @loadedcode.add_hostclass(:main, @klass)
+ @klass.stubs(:name).returns :main
+ @loadedcode.add_hostclass(@klass)
code = stub 'code', :is_a? => false
- @klass.stubs(:classname).returns("")
+ @klass.stubs(:name).returns("")
@klass.stubs(:code).returns(code)
@parser.expects(:scan_for_vardef).with(@container, code)
@@ -177,7 +178,7 @@ describe RDoc::Parser do
end
it "should document definitions in the parsed file" do
- @loadedcode.add_definition("mydef", @definition)
+ @loadedcode.add_definition(@definition)
@parser.expects(:document_define).with("mydef", @definition, @container)
@@ -186,7 +187,7 @@ describe RDoc::Parser do
it "should not document definitions parsed in an other file" do
@definition.stubs(:file).returns("/not/same/path/file.pp")
- @loadedcode.add_definition("mydef", @definition)
+ @loadedcode.add_definition(@definition)
@parser.expects(:document_define).with("mydef", @definition, @container).never
@@ -194,7 +195,7 @@ describe RDoc::Parser do
end
it "should document nodes in the parsed file" do
- @loadedcode.add_node("mynode", @node)
+ @loadedcode.add_node(@node)
@parser.expects(:document_node).with("mynode", @node, @container)
@@ -203,7 +204,7 @@ describe RDoc::Parser do
it "should not document node parsed in an other file" do
@node.stubs(:file).returns("/not/same/path/file.pp")
- @loadedcode.add_node("mynode", @node)
+ @loadedcode.add_node(@node)
@parser.expects(:document_node).with("mynode", @node, @container).never