diff options
Diffstat (limited to 'lib/puppet/parser/ast/hostclass.rb')
-rw-r--r-- | lib/puppet/parser/ast/hostclass.rb | 166 |
1 files changed, 33 insertions, 133 deletions
diff --git a/lib/puppet/parser/ast/hostclass.rb b/lib/puppet/parser/ast/hostclass.rb index 44077983d..4a4664f0f 100644 --- a/lib/puppet/parser/ast/hostclass.rb +++ b/lib/puppet/parser/ast/hostclass.rb @@ -1,3 +1,5 @@ +require 'puppet/parser/ast/component' + class Puppet::Parser::AST # The code associated with a class. This is different from components # in that each class is a singleton -- only one will exist for a given @@ -5,152 +7,50 @@ class Puppet::Parser::AST class HostClass < AST::Component @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.parentclass + return true + else + return self.parentclass.child_of?(klass) + end + end + + # Evaluate the code associated with this class. def evaluate(hash) scope = hash[:scope] - objname = hash[:name] args = hash[:arguments] + # Verify that we haven't already been evaluated - # FIXME The second subclass won't evaluate the parent class - # code at all, and any overrides will throw an error. - if myscope = scope.lookupclass(self.object_id) + if scope.setclass?(self) Puppet.debug "%s class already evaluated" % @type - - # Not used, but will eventually be used to fix #140. - if myscope.is_a? Puppet::Parser::Scope - unless scope.object_id == myscope.object_id - #scope.parent = myscope - end - end return nil end - # Set the class before we do anything else, so that it's set - # during the evaluation and can be inspected. - scope.setclass(self.object_id, @type) - - origscope = scope - - # Default to creating a new context - newcontext = true - - # If we've got a parent, then we pass it the original scope we - # received. It will get passed all the way up to the top class, - # which will create a subscope and pass that subscope to its - # subclass. - if @parentscope = self.evalparent( - :scope => scope, :arguments => args, :name => objname - ) - if @parentscope.is_a? Puppet::TransBucket - raise Puppet::DevError, "Got a bucket instead of a scope" - end - - # Override our scope binding with the parent scope - # binding. - scope = @parentscope - - # But don't create a new context if our parent created one - newcontext = false - end - - # Just use the Component evaluate method, but change the type - # to our own type. - result = super( - :scope => scope, - :arguments => args, - :type => @type, - :name => objname, # might be nil - :newcontext => newcontext, - :asparent => hash[:asparent] || false # might be nil - ) - - # Now set the class again, this time using the scope. This way - # we can look up the parent scope of this class later, so we - # can hook the children together. - scope.setscope(self.object_id, result) - - # This is important but painfully difficult. If we're the top-level - # class, that is, we have no parent classes, then the transscope - # is our own scope, but if there are parent classes, then the topmost - # parent's scope is the transscope, since it contains its code and - # all of the subclass's code. - transscope ||= result - - if hash[:asparent] - # If we're a parent class, then return the scope object itself. - return result - else - transscope = nil - if @parentscope - transscope = @parentscope - until transscope.parent.object_id == origscope.object_id - transscope = transscope.parent - end + if @parentclass + if pklass = self.parentclass + pklass.safeevaluate :scope => scope else - transscope = result + parsefail "Could not find class %s" % @parentclass end - - # But if we're the final subclass, translate the whole scope tree - # into TransObjects and TransBuckets. - return transscope.to_trans end - end - # Evaluate our parent class. Parent classes are evaluated in the - # exact same scope as the children. This is maybe not a good idea - # but, eh. - #def evalparent(scope, args, name) - def evalparent(hash) - scope = hash[:scope] - args = hash[:arguments] - name = hash[:name] - if @parentclass - #scope.warning "parent class of %s is %s" % - # [@type, @parentclass.inspect] - parentobj = nil + # Set the class before we do anything else, so that it's set + # during the evaluation and can be inspected. + scope.setclass(self) - begin - parentobj = scope.lookuptype(@parentclass) - rescue Puppet::ParseError => except - except.line = self.line - except.file = self.file - raise except - rescue => detail - error = Puppet::ParseError.new(detail) - error.line = self.line - error.file = self.file - raise error - end - unless parentobj - error = Puppet::ParseError.new( - "Could not find parent '%s' of '%s'" % - [@parentclass,@name]) - error.line = self.line - error.file = self.file - raise error - end + unless hash[:nosubscope] + scope = subscope(scope) + end - # Verify that the parent and child are of the same type - unless parentobj.class == self.class - error = Puppet::ParseError.new( - "Class %s has incompatible parent type, %s vs %s" % - [@type, parentobj.class, self.class] - ) - error.file = self.file - error.line = self.line - raise error - end - # We don't need to pass the type, because the parent will just - # use its own type. Specify that it's being evaluated as a parent, - # so that it returns the scope, not a transbucket. - return parentobj.safeevaluate( - :scope => scope, - :arguments => args, - :name => name, - :asparent => true, - :collectable => self.collectable - ) + # Now evaluate our code, yo. + if self.code + return self.code.evaluate(:scope => scope) else - return false + return nil end end @@ -158,7 +58,7 @@ class Puppet::Parser::AST @parentclass = nil super end - end - end + +# $Id$ |