class Puppet::Parser::Scope

This class is part of the internal parser/evaluator/compiler functionality of Puppet. It is passed between the various classes that participate in evaluation. None of its methods are API except those that are clearly marked as such.

@api public

Constants

BUILT_IN_VARS

Variables that always exist with nil value even if not set

EMPTY_HASH
RESERVED_VARIABLE_NAMES
TYPENAME_CLASS
TYPENAME_NODE
UNCAUGHT_THROW_EXCEPTION

The exception raised when a throw is uncaught is different in different versions of ruby. In >=2.2.0 it is UncaughtThrowError (which did not exist prior to this)

UNDEFINED_VARIABLES_KIND
VARNAME_FACTS
VARNAME_SERVER_FACTS
VARNAME_TRUSTED

Attributes

compiler[R]
defaults[R]

Hash of hashes of default values per type name

parent[RW]
resource[RW]
source[RW]

Public Class Methods

new(compiler, source: nil, resource: nil) click to toggle source

Initialize our new scope. Defaults to having no parent.

    # File lib/puppet/parser/scope.rb
373 def initialize(compiler, source: nil, resource: nil)
374   if compiler.is_a? Puppet::Parser::AbstractCompiler
375     @compiler = compiler
376   else
377     raise Puppet::DevError, _("you must pass a compiler instance to a new scope object")
378   end
379 
380   @source = source
381   @resource = resource
382 
383   extend_with_functions_module
384 
385   # The symbol table for this scope.  This is where we store variables.
386   #    @symtable = Ephemeral.new(nil, true)
387   @symtable = LocalScope.new(nil)
388 
389   @ephemeral = [ MatchScope.new(@symtable, nil) ]
390 
391   # All of the defaults set for types.  It's a hash of hashes,
392   # with the first key being the type, then the second key being
393   # the parameter.
394   @defaults = Hash.new { |dhash,type|
395     dhash[type] = {}
396   }
397 
398   # The table for storing class singletons.  This will only actually
399   # be used by top scopes and node scopes.
400   @class_scopes = {}
401 end
number?(value) click to toggle source

Coerce value to a number, or return `nil` if it isn't one.

    # File lib/puppet/parser/scope.rb
327 def self.number?(value)
328   case value
329   when Numeric
330     value
331   when /^-?\d+(:?\.\d+|(:?\.\d+)?e\d+)$/
332     value.to_f
333   when /^0x[0-9a-f]+$/i
334     value.to_i(16)
335   when /^0[0-7]+$/
336     value.to_i(8)
337   when /^-?\d+$/
338     value.to_i
339   else
340     nil
341   end
342 end
true?(value) click to toggle source

Is the value true? This allows us to control the definition of truth in one place.

    # File lib/puppet/parser/scope.rb
315 def self.true?(value)
316   case value
317   when ''
318     false
319   when :undef
320     false
321   else
322     !!value
323   end
324 end

Public Instance Methods

[](varname, options = EMPTY_HASH) click to toggle source

Retrieves the variable value assigned to the name given as an argument. The name must be a String, and namespace can be qualified with '::'. The value is looked up in this scope, its parent scopes, or in a specific visible named scope.

@param varname [String] the name of the variable (may be a qualified name using `(ns'::')*varname` @param options [Hash] Additional options, not part of api. @return [Object] the value assigned to the given varname @see []= @api public

    # File lib/puppet/parser/scope.rb
553 def [](varname, options = EMPTY_HASH)
554   lookupvar(varname, options)
555 end
[]=(varname, value, _ = nil) click to toggle source

Sets the variable value of the name given as an argument to the given value. The value is set in the current scope and may shadow a variable with the same name in a visible outer scope. It is illegal to re-assign a variable in the same scope. It is illegal to set a variable in some other scope/namespace than the scope passed to a method.

@param varname [String] The variable name to which the value is assigned. Must not contain `::` @param value [String] The value to assign to the given variable name. @param options [Hash] Additional options, not part of api and no longer used.

@api public

    # File lib/puppet/parser/scope.rb
868 def []=(varname, value, _ = nil)
869   setvar(varname, value)
870 end
bound?(name) click to toggle source

Returns true if the given name is bound in the current (most nested) scope for assignments.

    # File lib/puppet/parser/scope.rb
308 def bound?(name)
309   # Do not look in ephemeral (match scope), the semantics is to answer if an assignable variable is bound
310   effective_symtable(false).bound?(name)
311 end
call_function(func_name, args, &block) click to toggle source

Calls a 3.x or 4.x function by name with arguments given in an array using the 4.x calling convention and returns the result. Note that it is the caller's responsibility to rescue the given ArgumentError and provide location information to aid the user find the problem. The problem is otherwise reported against the source location that invoked the function that ultimately called this method.

@return [Object] the result of the called function @raise ArgumentError if the function does not exist

     # File lib/puppet/parser/scope.rb
1100 def call_function(func_name, args, &block)
1101   Puppet::Pops::Parser::EvaluatingParser.new.evaluator.external_call_function(func_name, args, self, &block)
1102 end
catalog() click to toggle source

Alias for `compiler.catalog`

   # File lib/puppet/parser/scope.rb
37 def catalog
38   @compiler.catalog
39 end
class_scope(klass) click to toggle source

Return the scope associated with a class. This is just here so that subclasses can set their parent scopes to be the scope of their parent class, and it's also used when looking up qualified variables.

    # File lib/puppet/parser/scope.rb
417 def class_scope(klass)
418   # They might pass in either the class or class name
419   k = klass.respond_to?(:name) ? klass.name : klass
420   @class_scopes[k] || (parent && parent.class_scope(k))
421 end
class_set(name, scope) click to toggle source

Store the fact that we've evaluated a class, and store a reference to the scope in which it was evaluated, so that we can look it up later.

    # File lib/puppet/parser/scope.rb
405 def class_set(name, scope)
406   if parent
407     parent.class_set(name, scope)
408   else
409     @class_scopes[name] = scope
410   end
411 end
define_settings(type, params) click to toggle source

Set defaults for a type. The typename should already be downcased, so that the syntax is isolated. We don't do any kind of type-checking here; instead we let the resource do it when the defaults are used.

    # File lib/puppet/parser/scope.rb
695 def define_settings(type, params)
696   table = @defaults[type]
697 
698   # if we got a single param, it'll be in its own array
699   params = [params] unless params.is_a?(Array)
700 
701   params.each { |param|
702     if table.include?(param.name)
703       raise Puppet::ParseError.new(_("Default already defined for %{type} { %{param} }; cannot redefine") % { type: type, param: param.name }, param.file, param.line)
704     end
705     table[param.name] = param
706   }
707 end
effective_symtable(use_ephemeral) click to toggle source

Return the effective “table” for setting variables. This method returns the first ephemeral “table” that acts as a local scope, or this scope's symtable. If the parameter `use_ephemeral` is true, the “top most” ephemeral “table” will be returned (irrespective of it being a match scope or a local scope).

@param use_ephemeral [Boolean] whether the top most ephemeral (of any kind) should be used or not

    # File lib/puppet/parser/scope.rb
847 def effective_symtable(use_ephemeral)
848   s = @ephemeral[-1]
849   return s || @symtable if use_ephemeral
850 
851   while s && !s.is_local_scope?()
852     s = s.parent
853   end
854   s || @symtable
855 end
enclosing_scope() click to toggle source

The enclosing scope (topscope or nodescope) of this scope. The enclosing scopes are produced when a class or define is included at some point. The parent scope of the included class or define becomes the scope in which it was included. The chain of parent scopes is followed until a node scope or the topscope is found

@return [Puppet::Parser::Scope] The scope or nil if there is no enclosing scope

    # File lib/puppet/parser/scope.rb
575 def enclosing_scope
576    if has_enclosing_scope?
577     if parent.is_topscope? || parent.is_nodescope?
578       parent
579     else
580       parent.enclosing_scope
581     end
582    end
583 end
environment() click to toggle source

Alias for `compiler.environment`

   # File lib/puppet/parser/scope.rb
32 def environment
33   @compiler.environment
34 end
ephemeral_from(match, file = nil, line = nil) click to toggle source
     # File lib/puppet/parser/scope.rb
1001 def ephemeral_from(match, file = nil, line = nil)
1002   case match
1003   when Hash
1004     # Create local scope ephemeral and set all values from hash
1005     new_ephemeral(true)
1006     match.each {|k,v| setvar(k, v, :file => file, :line => line, :ephemeral => true) }
1007     # Must always have an inner match data scope (that starts out as transparent)
1008     # In 3x slightly wasteful, since a new nested scope is created for a match
1009     # (TODO: Fix that problem)
1010     new_ephemeral(false)
1011   else
1012     raise(ArgumentError,_("Invalid regex match data. Got a %{klass}") % { klass: match.class }) unless match.is_a?(MatchData)
1013     # Create a match ephemeral and set values from match data
1014     new_match_scope(match)
1015   end
1016 end
ephemeral_level() click to toggle source
    # File lib/puppet/parser/scope.rb
914 def ephemeral_level
915   @ephemeral.size
916 end
exist?(name) click to toggle source

Returns true if the variable of the given name is set to any value (including nil)

@return [Boolean] if variable exists or not

    # File lib/puppet/parser/scope.rb
283 def exist?(name)
284   # Note !! ensure the answer is boolean
285   !! if name =~ /^(.*)::(.+)$/
286     class_name = $1
287     variable_name = $2
288     return true if class_name == '' && BUILT_IN_VARS.include?(variable_name)
289 
290     # lookup class, but do not care if it is not evaluated since that will result
291     # in it not existing anyway. (Tests may run with just scopes and no evaluated classes which
292     # will result in class_scope for "" not returning topscope).
293     klass = find_hostclass(class_name)
294     other_scope = klass.nil? ? nil : class_scope(klass)
295     if other_scope.nil?
296       class_name == '' ? compiler.topscope.exist?(variable_name) : false
297     else
298       other_scope.exist?(variable_name)
299     end
300   else
301     next_scope = inherited_scope || enclosing_scope
302     effective_symtable(true).include?(name) || next_scope && next_scope.exist?(name) || BUILT_IN_VARS.include?(name)
303   end
304 end
find_builtin_resource_type(type) click to toggle source

@api private

     # File lib/puppet/parser/scope.rb
1024 def find_builtin_resource_type(type)
1025   raise Puppet::DevError, _("Scope#find_builtin_resource_type() is no longer supported, use Puppet::Pops::Evaluator::Runtime3ResourceSupport instead")
1026 end
find_defined_resource_type(type) click to toggle source

@api private

     # File lib/puppet/parser/scope.rb
1029 def find_defined_resource_type(type)
1030   raise Puppet::DevError, _("Scope#find_defined_resource_type() is no longer supported, use Puppet::Pops::Evaluator::Runtime3ResourceSupport instead")
1031 end
find_definition(name) click to toggle source
    # File lib/puppet/parser/scope.rb
348 def find_definition(name)
349   environment.known_resource_types.find_definition(name)
350 end
find_global_scope() click to toggle source
    # File lib/puppet/parser/scope.rb
352 def find_global_scope()
353   # walk upwards until first found node_scope or top_scope
354   if is_nodescope? || is_topscope?
355     self
356   else
357     next_scope = inherited_scope || enclosing_scope
358     if next_scope.nil?
359       # this happens when testing, and there is only a single test scope and no link to any
360       # other scopes
361       self
362     else
363       next_scope.find_global_scope()
364     end
365   end
366 end
find_hostclass(name) click to toggle source
    # File lib/puppet/parser/scope.rb
344 def find_hostclass(name)
345   environment.known_resource_types.find_hostclass(name)
346 end
find_resource_type(type) click to toggle source

@api private

     # File lib/puppet/parser/scope.rb
1019 def find_resource_type(type)
1020   raise Puppet::DevError, _("Scope#find_resource_type() is no longer supported, use Puppet::Pops::Evaluator::Runtime3ResourceSupport instead")
1021 end
findresource(type, title = nil) click to toggle source
    # File lib/puppet/parser/scope.rb
368 def findresource(type, title = nil)
369   @compiler.catalog.resource(type, title)
370 end
get_local_variable(name) click to toggle source

@api private

    # File lib/puppet/parser/scope.rb
630 def get_local_variable(name)
631   @ephemeral.last[name]
632 end
handle_not_found(class_name, variable_name, position, reason = nil) click to toggle source
    # File lib/puppet/parser/scope.rb
634 def handle_not_found(class_name, variable_name, position, reason = nil)
635   unless Puppet[:strict_variables]
636     # Do not issue warning if strict variables are on, as an error will be raised by variable_not_found
637     location = if position[:lineproc]
638                  Puppet::Util::Errors.error_location_with_space(nil, position[:lineproc].call)
639                else
640                  Puppet::Util::Errors.error_location_with_space(position[:file], position[:line])
641                end
642     variable_not_found("#{class_name}::#{variable_name}", "#{reason}#{location}")
643     return nil
644   end
645   variable_not_found("#{class_name}::#{variable_name}", reason)
646 end
has_local_variable?(name) click to toggle source

@api private

    # File lib/puppet/parser/scope.rb
625 def has_local_variable?(name)
626   @ephemeral.last.include?(name)
627 end
include?(name) click to toggle source

Returns true if the variable of the given name has a non nil value. TODO: This has vague semantics - does the variable exist or not?

use ['name'] to get nil or value, and if nil check with exist?('name')
this include? is only useful because of checking against the boolean value false.
    # File lib/puppet/parser/scope.rb
272 def include?(name)
273   catch(:undefined_variable) {
274     return ! self[name].nil?
275   }
276   false
277 end
inherited_scope() click to toggle source

The class scope of the inherited thing of this scope's resource.

@return [Puppet::Parser::Scope] The scope or nil if there is not an inherited scope

    # File lib/puppet/parser/scope.rb
560 def inherited_scope
561   if resource && resource.type == TYPENAME_CLASS && !resource.resource_type.parent.nil?
562     qualified_scope(resource.resource_type.parent)
563   else
564     nil
565   end
566 end
inspect()
Alias for: to_s
is_classscope?() click to toggle source
    # File lib/puppet/parser/scope.rb
585 def is_classscope?
586   resource && resource.type == TYPENAME_CLASS
587 end
is_default?(type, key, value) click to toggle source

Check if the given value is a known default for the given type

    # File lib/puppet/parser/scope.rb
457 def is_default?(type, key, value)
458   defaults_for_type = @defaults[type]
459   unless defaults_for_type.nil?
460     default_param = defaults_for_type[key]
461     return true if !default_param.nil? && value == default_param.value
462   end
463   !parent.nil? && parent.is_default?(type, key, value)
464 end
is_nodescope?() click to toggle source
    # File lib/puppet/parser/scope.rb
589 def is_nodescope?
590   resource && resource.type == TYPENAME_NODE
591 end
is_topscope?() click to toggle source
    # File lib/puppet/parser/scope.rb
593 def is_topscope?
594   equal?(@compiler.topscope)
595 end
lookup_qualified_variable(fqn, options) click to toggle source

@api private

    # File lib/puppet/parser/scope.rb
598 def lookup_qualified_variable(fqn, options)
599   table = @compiler.qualified_variables
600   val = table[fqn]
601   return val if !val.nil? || table.include?(fqn)
602 
603   # not found - search inherited scope for class
604   leaf_index = fqn.rindex('::')
605   unless leaf_index.nil?
606     leaf_name = fqn[ (leaf_index+2)..-1 ]
607     class_name = fqn[ 0, leaf_index ]
608     begin
609       qs = qualified_scope(class_name)
610       unless qs.nil?
611         return qs.get_local_variable(leaf_name) if qs.has_local_variable?(leaf_name)
612         iscope = qs.inherited_scope
613         return lookup_qualified_variable("#{iscope.source.name}::#{leaf_name}", options) unless iscope.nil?
614       end
615     rescue RuntimeError => e
616       # because a failure to find the class, or inherited should be reported against given name
617       return handle_not_found(class_name, leaf_name, options, e.message)
618     end
619   end
620   # report with leading '::' by using empty class_name
621   return handle_not_found('', fqn, options)
622 end
lookupdefaults(type) click to toggle source

Collect all of the defaults set at any higher scopes. This is a different type of lookup because it's additive – it collects all of the defaults, with defaults in closer scopes overriding those in later scopes.

The lookupdefaults searches in the the order:

* inherited
* contained (recursive)
* self
    # File lib/puppet/parser/scope.rb
434 def lookupdefaults(type)
435   values = {}
436 
437   # first collect the values from the parents
438   if parent
439     parent.lookupdefaults(type).each { |var,value|
440       values[var] = value
441     }
442   end
443 
444   # then override them with any current values
445   # this should probably be done differently
446   if @defaults.include?(type)
447     @defaults[type].each { |var,value|
448       values[var] = value
449     }
450   end
451 
452   values
453 end
lookuptype(name) click to toggle source

Look up a defined type.

    # File lib/puppet/parser/scope.rb
467 def lookuptype(name)
468   # This happens a lot, avoid making a call to make a call
469   krt = environment.known_resource_types
470   krt.find_definition(name) || krt.find_hostclass(name)
471 end
lookupvar(name, options = EMPTY_HASH) click to toggle source

Lookup a variable within this scope using the Puppet language's scoping rules. Variables can be qualified using just as in a manifest.

@param [String] name the variable name to lookup @param [Hash] hash of options, only internal code should give this @param [Boolean] if resolution is of the leaf of a qualified name - only internal code should give this @return Object the value of the variable, or if not found; nil if `strict_variables` is false, and thrown :undefined_variable otherwise

@api public

    # File lib/puppet/parser/scope.rb
491 def lookupvar(name, options = EMPTY_HASH)
492   unless name.is_a? String
493     raise Puppet::ParseError, _("Scope variable name %{name} is a %{klass}, not a string") % { name: name.inspect, klass: name.class }
494   end
495 
496   # If name has '::' in it, it is resolved as a qualified variable
497   unless (idx = name.index('::')).nil?
498     # Always drop leading '::' if present as that is how the values are keyed.
499     return lookup_qualified_variable(idx == 0 ? name[2..-1] : name, options)
500   end
501 
502   # At this point, search is for a non qualified (simple) name
503   table = @ephemeral.last
504   val = table[name]
505   return val unless val.nil? && !table.include?(name)
506 
507   next_scope = inherited_scope || enclosing_scope
508   if next_scope
509     next_scope.lookupvar(name, options)
510   else
511     variable_not_found(name)
512   end
513 end
merge_settings(env_name, set_in_this_scope=true) click to toggle source

Merge all settings for the given env_name into this scope @param env_name [Symbol] the name of the environment @param set_in_this_scope [Boolean] if the settings variables should also be set in this instance of scope

    # File lib/puppet/parser/scope.rb
712 def merge_settings(env_name, set_in_this_scope=true)
713   settings = Puppet.settings
714   table = effective_symtable(false)
715   global_table = compiler.qualified_variables
716   all_local = {}
717   settings.each_key do |name|
718     next if :name == name
719     key = name.to_s
720     value = transform_setting(settings.value_sym(name, env_name))
721     if set_in_this_scope
722       table[key] = value
723     end
724     all_local[key] = value
725     # also write the fqn into global table for direct lookup
726     global_table["settings::#{key}"] = value
727   end
728   # set the 'all_local' - a hash of all settings
729   global_table["settings::all_local"] = all_local
730   nil
731 end
method_missing(method, *args, &block) click to toggle source
Calls superclass method
     # File lib/puppet/parser/scope.rb
1034 def method_missing(method, *args, &block)
1035   method.to_s =~ /^function_(.*)$/
1036   name = $1
1037   super unless name
1038   super unless Puppet::Parser::Functions.function(name)
1039   # In odd circumstances, this might not end up defined by the previous
1040   # method, so we might as well be certain.
1041   if respond_to? method
1042     send(method, *args)
1043   else
1044     raise Puppet::DevError, _("Function %{name} not defined despite being loaded!") % { name: name }
1045   end
1046 end
new_ephemeral(local_scope = false) click to toggle source

TODO: Who calls this?

    # File lib/puppet/parser/scope.rb
919 def new_ephemeral(local_scope = false)
920   if local_scope
921     @ephemeral.push(LocalScope.new(@ephemeral.last))
922   else
923     @ephemeral.push(MatchScope.new(@ephemeral.last, nil))
924   end
925 end
new_match_scope(match_data) click to toggle source

Nests a match data scope

    # File lib/puppet/parser/scope.rb
997 def new_match_scope(match_data)
998   @ephemeral.push(MatchScope.new(@ephemeral.last, match_data))
999 end
newscope(options = {}) click to toggle source

Create a new scope and set these options.

    # File lib/puppet/parser/scope.rb
683 def newscope(options = {})
684   compiler.newscope(self, options)
685 end
parent_module_name() click to toggle source
    # File lib/puppet/parser/scope.rb
687 def parent_module_name
688   return nil unless @parent && @parent.source
689   @parent.source.module_name
690 end
pop_ephemerals(level) click to toggle source

Pop ephemeral scopes up to level and return them

@param level [Integer] a positive integer @return [Array] the removed ephemeral scopes @api private

    # File lib/puppet/parser/scope.rb
903 def pop_ephemerals(level)
904   @ephemeral.pop(@ephemeral.size - level)
905 end
push_ephemerals(ephemeral_scopes) click to toggle source

Push ephemeral scopes onto the ephemeral scope stack @param ephemeral_scopes [Array] @api private

    # File lib/puppet/parser/scope.rb
910 def push_ephemerals(ephemeral_scopes)
911   ephemeral_scopes.each { |ephemeral_scope| @ephemeral.push(ephemeral_scope) } unless ephemeral_scopes.nil?
912 end
resolve_type_and_titles(type, titles) click to toggle source

To be removed when enough time has passed after puppet 5.0.0 @api private

     # File lib/puppet/parser/scope.rb
1050 def resolve_type_and_titles(type, titles)
1051   raise Puppet::DevError, _("Scope#resolve_type_and_title() is no longer supported, use Puppet::Pops::Evaluator::Runtime3ResourceSupport instead")
1052 end
set_facts(hash) click to toggle source
    # File lib/puppet/parser/scope.rb
810 def set_facts(hash)
811   setvar('facts', deep_freeze(hash), :privileged => true)
812 end
set_match_data(match_data) click to toggle source

Sets match data in the most nested scope (which always is a MatchScope), it clobbers match data already set there

    # File lib/puppet/parser/scope.rb
992 def set_match_data(match_data)
993   @ephemeral.last.match_data = match_data
994 end
set_server_facts(hash) click to toggle source
    # File lib/puppet/parser/scope.rb
814 def set_server_facts(hash)
815   setvar('server_facts', deep_freeze(hash), :privileged => true)
816 end
set_trusted(hash) click to toggle source
    # File lib/puppet/parser/scope.rb
806 def set_trusted(hash)
807   setvar('trusted', deep_freeze(hash), :privileged => true)
808 end
setvar(name, value, options = EMPTY_HASH) click to toggle source

Set a variable in the current scope. This will override settings in scopes above, but will not allow variables in the current scope to be reassigned.

It's preferred that you use self[]= instead of this; only use this

when you need to set options.

    # File lib/puppet/parser/scope.rb
761 def setvar(name, value, options = EMPTY_HASH)
762   if name =~ /^[0-9]+$/
763     raise Puppet::ParseError.new(_("Cannot assign to a numeric match result variable '$%{name}'") % { name: name }) # unless options[:ephemeral]
764   end
765   unless name.is_a? String
766     raise Puppet::ParseError, _("Scope variable name %{name} is a %{class_type}, not a string") % { name: name.inspect, class_type: name.class }
767   end
768 
769   # Check for reserved variable names
770   if (name == VARNAME_TRUSTED || name == VARNAME_FACTS) && !options[:privileged]
771     raise Puppet::ParseError, _("Attempt to assign to a reserved variable name: '%{name}'") % { name: name }
772   end
773 
774   # Check for server_facts reserved variable name
775   if name == VARNAME_SERVER_FACTS && !options[:privileged]
776     raise Puppet::ParseError, _("Attempt to assign to a reserved variable name: '%{name}'") % { name: name }
777   end
778 
779   table = effective_symtable(options[:ephemeral])
780   if table.bound?(name)
781     error = Puppet::ParseError.new(_("Cannot reassign variable '$%{name}'") % { name: name })
782     error.file = options[:file] if options[:file]
783     error.line = options[:line] if options[:line]
784     raise error
785   end
786 
787   table[name] = value
788 
789   # Assign the qualified name in the environment
790   # Note that Settings scope has a source set to Boolean true.
791   #
792   # Only meaningful to set a fqn globally if table to assign to is the top of the scope's ephemeral stack
793   if @symtable.equal?(table)
794     if is_topscope?
795       # the scope name is '::'
796       compiler.qualified_variables[name] = value
797     elsif source.is_a?(Puppet::Resource::Type) && source.type == :hostclass
798       # the name is the name of the class
799       sourcename = source.name
800       compiler.qualified_variables["#{sourcename}::#{name}"] = value
801     end
802   end
803   value
804 end
to_hash(recursive = true, include_undef = false) click to toggle source

Returns a Hash containing all variables and their values, optionally (and by default) including the values defined in parent. Local values shadow parent values. Ephemeral scopes for match results ($0 - $n) are not included. Optionally include the variables that are explicitly set to `undef`.

    # File lib/puppet/parser/scope.rb
667 def to_hash(recursive = true, include_undef = false)
668   if recursive and has_enclosing_scope?
669     target = enclosing_scope.to_hash(recursive)
670     if !(inherited = inherited_scope).nil?
671       target.merge!(inherited.to_hash(recursive))
672     end
673   else
674     target = Hash.new
675   end
676 
677   # add all local scopes
678   @ephemeral.last.add_entries_to(target, include_undef)
679   target
680 end
to_s() click to toggle source

Used mainly for logging

    # File lib/puppet/parser/scope.rb
873 def to_s
874   # As this is used for logging, this should really not be done in this class at all...
875   return "Scope(#{@resource})" unless @resource.nil?
876 
877   # For logging of function-scope - it is now showing the file and line.
878   detail = Puppet::Pops::PuppetStack.top_of_stack
879   return "Scope()" if detail.empty?
880 
881   # shorten the path if possible
882   path = detail[0]
883   env_path = nil
884   env_path = environment.configuration.path_to_env unless (environment.nil? || environment.configuration.nil?)
885   # check module paths first since they may be in the environment (i.e. they are longer)
886   module_path = environment.full_modulepath.detect {|m_path| path.start_with?(m_path) }
887   if module_path
888     path = "<module>" + path[module_path.length..-1]
889   elsif env_path && path && path.start_with?(env_path)
890     path = "<env>" + path[env_path.length..-1]
891   end
892   # Make the output appear as "Scope(path, line)"
893   "Scope(#{[path, detail[1]].join(', ')})" 
894 end
Also aliased as: inspect
transform_and_assert_classnames(names) click to toggle source

Transforms references to classes to the form suitable for lookup in the compiler.

Makes names passed in the names array absolute if they are relative.

Transforms Class[] and Resource[] type references to class name or raises an error if a Class[] is unspecific, if a Resource is not a 'class' resource, or if unspecific (no title).

@param names [Array<String>] names to (optionally) make absolute @return [Array<String>] names after transformation

     # File lib/puppet/parser/scope.rb
1067 def transform_and_assert_classnames(names)
1068   names.map do |name|
1069     case name
1070     when NilClass
1071       raise ArgumentError, _("Cannot use undef as a class name")
1072     when String
1073       raise ArgumentError, _("Cannot use empty string as a class name") if name.empty?
1074       name.sub(/^([^:]{1,2})/, '::\1')
1075 
1076     when Puppet::Resource
1077       assert_class_and_title(name.type, name.title)
1078       name.title.sub(/^([^:]{1,2})/, '::\1')
1079 
1080     when Puppet::Pops::Types::PClassType
1081       #TRANSLATORS "Class" and "Type" are Puppet keywords and should not be translated
1082       raise ArgumentError, _("Cannot use an unspecific Class[] Type") unless name.class_name
1083       name.class_name.sub(/^([^:]{1,2})/, '::\1')
1084 
1085     when Puppet::Pops::Types::PResourceType
1086       assert_class_and_title(name.type_name, name.title)
1087       name.title.sub(/^([^:]{1,2})/, '::\1')
1088     end.downcase
1089   end
1090 end
undef_as(x,v) click to toggle source
    # File lib/puppet/parser/scope.rb
473 def undef_as(x,v)
474   if v.nil? or v == :undef
475     x
476   else
477     v
478   end
479 end
variable_not_found(name, reason=nil) click to toggle source
    # File lib/puppet/parser/scope.rb
522 def variable_not_found(name, reason=nil)
523   # Built in variables and numeric variables always exist
524   if BUILT_IN_VARS.include?(name) || name =~ Puppet::Pops::Patterns::NUMERIC_VAR_NAME
525     return nil
526   end
527   begin
528     throw(:undefined_variable, reason)
529   rescue  UNCAUGHT_THROW_EXCEPTION
530     case Puppet[:strict]
531     when :off
532       # do nothing
533     when :warning
534       Puppet.warn_once(UNDEFINED_VARIABLES_KIND, _("Variable: %{name}") % { name: name },
535       _("Undefined variable '%{name}'; %{reason}") % { name: name, reason: reason } )
536     when :error
537       raise ArgumentError, _("Undefined variable '%{name}'; %{reason}") % { name: name, reason: reason }
538     end
539   end
540   nil
541 end
with_global_scope(&block) click to toggle source

Execute given block in global scope with no ephemerals present

@yieldparam [Scope] global_scope the global and ephemeral less scope @return [Object] the return of the block

@api private

    # File lib/puppet/parser/scope.rb
933 def with_global_scope(&block)
934   find_global_scope.without_ephemeral_scopes(&block)
935 end
with_guarded_scope() { || ... } click to toggle source

Execute given block and ensure that ephemeral level is restored

@return [Object] the return of the block

@api private

    # File lib/puppet/parser/scope.rb
981 def with_guarded_scope
982   elevel = ephemeral_level
983   begin
984     yield
985   ensure
986     pop_ephemerals(elevel)
987   end
988 end
with_local_scope(scope_variables) { |self| ... } click to toggle source

Execute given block with a ephemeral scope containing the given variables @api private

    # File lib/puppet/parser/scope.rb
939 def with_local_scope(scope_variables)
940   local = LocalScope.new(@ephemeral.last)
941   scope_variables.each_pair { |k, v| local[k] = v }
942   @ephemeral.push(local)
943   begin
944     yield(self)
945   ensure
946     @ephemeral.pop
947   end
948 end
with_parameter_scope(callee_name, param_names) { |param_scope| ... } click to toggle source

Nests a parameter scope @param [String] callee_name the name of the function, template, or resource that defines the parameters @param [Array<String>] param_names list of parameter names @yieldparam [ParameterScope] param_scope the nested scope @api private

    # File lib/puppet/parser/scope.rb
968 def with_parameter_scope(callee_name, param_names)
969   param_scope = ParameterScope.new(@ephemeral.last, callee_name, param_names)
970   with_guarded_scope do
971     @ephemeral.push(param_scope)
972     yield(param_scope)
973   end
974 end
without_ephemeral_scopes() { |self| ... } click to toggle source

Execute given block with all ephemeral popped from the ephemeral stack

@api private

    # File lib/puppet/parser/scope.rb
953 def without_ephemeral_scopes
954   save_ephemeral = @ephemeral
955   begin
956     @ephemeral = [ @symtable ]
957     yield(self)
958   ensure
959     @ephemeral = save_ephemeral
960   end
961 end

Private Instance Methods

assert_class_and_title(type_name, title) click to toggle source
     # File lib/puppet/parser/scope.rb
1106 def assert_class_and_title(type_name, title)
1107   if type_name.nil? || type_name == ''
1108     #TRANSLATORS "Resource" is a class name and should not be translated
1109     raise ArgumentError, _("Cannot use an unspecific Resource[] where a Resource['class', name] is expected")
1110   end
1111   unless type_name =~ /^[Cc]lass$/
1112     #TRANSLATORS "Resource" is a class name and should not be translated
1113     raise ArgumentError, _("Cannot use a Resource[%{type_name}] where a Resource['class', name] is expected") % { type_name: type_name }
1114   end
1115   if title.nil?
1116     #TRANSLATORS "Resource" is a class name and should not be translated
1117     raise ArgumentError, _("Cannot use an unspecific Resource['class'] where a Resource['class', name] is expected")
1118   end
1119 end
deep_freeze(object) click to toggle source

Deeply freezes the given object. The object and its content must be of the types: Array, Hash, Numeric, Boolean, Regexp, NilClass, or String. All other types raises an Error. (i.e. if they are assignable to Puppet::Pops::Types::Data type).

    # File lib/puppet/parser/scope.rb
822 def deep_freeze(object)
823   case object
824   when Array
825     object.each {|v| deep_freeze(v) }
826     object.freeze
827   when Hash
828     object.each {|k, v| deep_freeze(k); deep_freeze(v) }
829     object.freeze
830   when NilClass, Numeric, TrueClass, FalseClass
831     # do nothing
832   when String
833     object.freeze
834   else
835     raise Puppet::Error, _("Unsupported data type: '%{klass}'") % { klass: object.class }
836   end
837   object
838 end
extend_with_functions_module() click to toggle source
     # File lib/puppet/parser/scope.rb
1121 def extend_with_functions_module
1122   root = Puppet.lookup(:root_environment)
1123   extend Puppet::Parser::Functions.environment_module(root)
1124   extend Puppet::Parser::Functions.environment_module(environment) if environment != root
1125 end
has_enclosing_scope?() click to toggle source
    # File lib/puppet/parser/scope.rb
648 def has_enclosing_scope?
649   ! parent.nil?
650 end
qualified_scope(classname) click to toggle source
    # File lib/puppet/parser/scope.rb
653 def qualified_scope(classname)
654   klass = find_hostclass(classname)
655   raise _("class %{classname} could not be found") % { classname: classname }     unless klass
656   kscope = class_scope(klass)
657   raise _("class %{classname} has not been evaluated") % { classname: classname } unless kscope
658   kscope
659 end
transform_setting(val) click to toggle source
    # File lib/puppet/parser/scope.rb
733 def transform_setting(val)
734   if val.is_a?(String) || val.is_a?(Numeric) || true == val || false == val || nil == val
735     val
736   elsif val.is_a?(Array)
737     val.map {|entry| transform_setting(entry) }
738   elsif val.is_a?(Hash)
739     result = {}
740     val.each {|k,v| result[transform_setting(k)] = transform_setting(v) }
741     result
742   else
743     # not ideal, but required as there are settings values that are special
744     :undef == val ? nil : val.to_s
745   end
746 end