class Puppet::Parser::AST # Evaluate the stored parse tree for a given component. This will # receive the arguments passed to the component and also the type and # name of the component. class Component < AST::Branch class << self attr_accessor :name end # The class name @name = :component attr_accessor :type, :args, :code, :scope, :keyword #def evaluate(scope,hash,objtype,objname) def evaluate(hash) scope = hash[:scope] objtype = hash[:type] objname = hash[:name] arguments = hash[:arguments] || {} scope = scope.newscope( :type => @type, :name => objname, :keyword => self.keyword ) if hash[:newcontext] #scope.warning "Setting context to %s" % self.object_id scope.context = self.object_id end @scope = scope # The type is the component or class name #scope.type = objtype # The name is the name the user has chosen or that has # been dynamically generated. This is almost never used #scope.name = objname #scope.keyword = self.keyword #if self.is_a?(Node) # scope.isnodescope #end # Additionally, add a tag for whatever kind of class # we are scope.tag(@type) unless objname.nil? #Puppet.info "tagging with %s" % objname.inspect scope.tag(objname) end #scope.base = self.class.name # define all of the arguments in our local scope if self.args # Verify that all required arguments are either present or # have been provided with defaults. # FIXME This should probably also require each parent # class's arguments... self.args.each { |arg, default| unless arguments.include?(arg) if defined? default and ! default.nil? arguments[arg] = default #Puppet.debug "Got default %s for %s in %s" % # [default.inspect, arg.inspect, objname.inspect] else error = Puppet::ParseError.new( "Must pass %s to %s of type %s" % [arg.inspect,objname,@type] ) error.line = self.line error.file = self.file raise error end end } end # Set each of the provided arguments as variables in the # component's scope. arguments["name"] = objname arguments.each { |arg,value| begin scope.setvar(arg,arguments[arg]) rescue Puppet::ParseError => except except.line = self.line except.file = self.file raise except rescue Puppet::ParseError => except except.line = self.line except.file = self.file raise except rescue => except error = Puppet::ParseError.new(except.message) error.line = self.line error.file = self.file error.backtrace = except.backtrace raise error end } # Now just evaluate the code with our new bindings. self.code.safeevaluate(:scope => scope) # We return the scope, so that our children can make their scopes # under ours. This allows them to find our definitions. return scope end # Check whether a given argument is valid. Searches up through # any parent classes that might exist. def validarg?(param) found = false unless @args.is_a? Array @args = [@args] end found = @args.detect { |arg| if arg.is_a? Array arg[0] == param else arg == param end } if found # It's a valid arg for us return true elsif defined? @parentclass and @parentclass # Else, check any existing parent parent = @scope.lookuptype(@parentclass) if parent and parent != [] return parent.validarg?(param) else raise Puppet::Error, "Could not find parent class %s" % @parentclass end else # Or just return false return false end end end end # $Id$