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
374 def initialize(compiler, source: nil, resource: nil)
375   if compiler.is_a? Puppet::Parser::AbstractCompiler
376     @compiler = compiler
377   else
378     raise Puppet::DevError, _("you must pass a compiler instance to a new scope object")
379   end
380 
381   @source = source
382   @resource = resource
383 
384   extend_with_functions_module
385 
386   # The symbol table for this scope.  This is where we store variables.
387   #    @symtable = Ephemeral.new(nil, true)
388   @symtable = LocalScope.new(nil)
389 
390   @ephemeral = [ MatchScope.new(@symtable, nil) ]
391 
392   # All of the defaults set for types.  It's a hash of hashes,
393   # with the first key being the type, then the second key being
394   # the parameter.
395   @defaults = Hash.new { |dhash,type|
396     dhash[type] = {}
397   }
398 
399   # The table for storing class singletons.  This will only actually
400   # be used by top scopes and node scopes.
401   @class_scopes = {}
402 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
328 def self.number?(value)
329   case value
330   when Numeric
331     value
332   when /^-?\d+(:?\.\d+|(:?\.\d+)?e\d+)$/
333     value.to_f
334   when /^0x[0-9a-f]+$/i
335     value.to_i(16)
336   when /^0[0-7]+$/
337     value.to_i(8)
338   when /^-?\d+$/
339     value.to_i
340   else
341     nil
342   end
343 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
316 def self.true?(value)
317   case value
318   when ''
319     false
320   when :undef
321     false
322   else
323     !!value
324   end
325 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
559 def [](varname, options = EMPTY_HASH)
560   lookupvar(varname, options)
561 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
874 def []=(varname, value, _ = nil)
875   setvar(varname, value)
876 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
309 def bound?(name)
310   # Do not look in ephemeral (match scope), the semantics is to answer if an assignable variable is bound
311   effective_symtable(false).bound?(name)
312 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
1106 def call_function(func_name, args, &block)
1107   Puppet::Pops::Parser::EvaluatingParser.new.evaluator.external_call_function(func_name, args, self, &block)
1108 end
catalog() click to toggle source

Alias for `compiler.catalog`

   # File lib/puppet/parser/scope.rb
38 def catalog
39   @compiler.catalog
40 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
418 def class_scope(klass)
419   # They might pass in either the class or class name
420   k = klass.respond_to?(:name) ? klass.name : klass
421   @class_scopes[k] || (parent && parent.class_scope(k))
422 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
406 def class_set(name, scope)
407   if parent
408     parent.class_set(name, scope)
409   else
410     @class_scopes[name] = scope
411   end
412 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
701 def define_settings(type, params)
702   table = @defaults[type]
703 
704   # if we got a single param, it'll be in its own array
705   params = [params] unless params.is_a?(Array)
706 
707   params.each { |param|
708     if table.include?(param.name)
709       raise Puppet::ParseError.new(_("Default already defined for %{type} { %{param} }; cannot redefine") % { type: type, param: param.name }, param.file, param.line)
710     end
711     table[param.name] = param
712   }
713 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
853 def effective_symtable(use_ephemeral)
854   s = @ephemeral[-1]
855   return s || @symtable if use_ephemeral
856 
857   while s && !s.is_local_scope?()
858     s = s.parent
859   end
860   s || @symtable
861 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
581 def enclosing_scope
582    if has_enclosing_scope?
583     if parent.is_topscope? || parent.is_nodescope?
584       parent
585     else
586       parent.enclosing_scope
587     end
588    end
589 end
environment() click to toggle source

Alias for `compiler.environment`

   # File lib/puppet/parser/scope.rb
33 def environment
34   @compiler.environment
35 end
ephemeral_from(match, file = nil, line = nil) click to toggle source
     # File lib/puppet/parser/scope.rb
1007 def ephemeral_from(match, file = nil, line = nil)
1008   case match
1009   when Hash
1010     # Create local scope ephemeral and set all values from hash
1011     new_ephemeral(true)
1012     match.each {|k,v| setvar(k, v, :file => file, :line => line, :ephemeral => true) }
1013     # Must always have an inner match data scope (that starts out as transparent)
1014     # In 3x slightly wasteful, since a new nested scope is created for a match
1015     # (TODO: Fix that problem)
1016     new_ephemeral(false)
1017   else
1018     raise(ArgumentError,_("Invalid regex match data. Got a %{klass}") % { klass: match.class }) unless match.is_a?(MatchData)
1019     # Create a match ephemeral and set values from match data
1020     new_match_scope(match)
1021   end
1022 end
ephemeral_level() click to toggle source
    # File lib/puppet/parser/scope.rb
920 def ephemeral_level
921   @ephemeral.size
922 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
284 def exist?(name)
285   # Note !! ensure the answer is boolean
286   !! if name =~ /^(.*)::(.+)$/
287     class_name = $1
288     variable_name = $2
289     return true if class_name == '' && BUILT_IN_VARS.include?(variable_name)
290 
291     # lookup class, but do not care if it is not evaluated since that will result
292     # in it not existing anyway. (Tests may run with just scopes and no evaluated classes which
293     # will result in class_scope for "" not returning topscope).
294     klass = find_hostclass(class_name)
295     other_scope = klass.nil? ? nil : class_scope(klass)
296     if other_scope.nil?
297       class_name == '' ? compiler.topscope.exist?(variable_name) : false
298     else
299       other_scope.exist?(variable_name)
300     end
301   else
302     next_scope = inherited_scope || enclosing_scope
303     effective_symtable(true).include?(name) || next_scope && next_scope.exist?(name) || BUILT_IN_VARS.include?(name)
304   end
305 end
find_builtin_resource_type(type) click to toggle source

@api private

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

@api private

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

@api private

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

@api private

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

@api private

    # File lib/puppet/parser/scope.rb
631 def has_local_variable?(name)
632   @ephemeral.last.include?(name)
633 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
273 def include?(name)
274   catch(:undefined_variable) {
275     return ! self[name].nil?
276   }
277   false
278 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
566 def inherited_scope
567   if resource && resource.type == TYPENAME_CLASS && !resource.resource_type.parent.nil?
568     qualified_scope(resource.resource_type.parent)
569   else
570     nil
571   end
572 end
inspect()
Alias for: to_s
is_classscope?() click to toggle source
    # File lib/puppet/parser/scope.rb
591 def is_classscope?
592   resource && resource.type == TYPENAME_CLASS
593 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
458 def is_default?(type, key, value)
459   defaults_for_type = @defaults[type]
460   unless defaults_for_type.nil?
461     default_param = defaults_for_type[key]
462     return true if !default_param.nil? && value == default_param.value
463   end
464   !parent.nil? && parent.is_default?(type, key, value)
465 end
is_nodescope?() click to toggle source
    # File lib/puppet/parser/scope.rb
595 def is_nodescope?
596   resource && resource.type == TYPENAME_NODE
597 end
is_topscope?() click to toggle source
    # File lib/puppet/parser/scope.rb
599 def is_topscope?
600   equal?(@compiler.topscope)
601 end
lookup_qualified_variable(fqn, options) click to toggle source

@api private

    # File lib/puppet/parser/scope.rb
604 def lookup_qualified_variable(fqn, options)
605   table = @compiler.qualified_variables
606   val = table[fqn]
607   return val if !val.nil? || table.include?(fqn)
608 
609   # not found - search inherited scope for class
610   leaf_index = fqn.rindex('::')
611   unless leaf_index.nil?
612     leaf_name = fqn[ (leaf_index+2)..-1 ]
613     class_name = fqn[ 0, leaf_index ]
614     begin
615       qs = qualified_scope(class_name)
616       unless qs.nil?
617         return qs.get_local_variable(leaf_name) if qs.has_local_variable?(leaf_name)
618         iscope = qs.inherited_scope
619         return lookup_qualified_variable("#{iscope.source.name}::#{leaf_name}", options) unless iscope.nil?
620       end
621     rescue RuntimeError => e
622       # because a failure to find the class, or inherited should be reported against given name
623       return handle_not_found(class_name, leaf_name, options, e.message)
624     end
625   end
626   # report with leading '::' by using empty class_name
627   return handle_not_found('', fqn, options)
628 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
435 def lookupdefaults(type)
436   values = {}
437 
438   # first collect the values from the parents
439   if parent
440     parent.lookupdefaults(type).each { |var,value|
441       values[var] = value
442     }
443   end
444 
445   # then override them with any current values
446   # this should probably be done differently
447   if @defaults.include?(type)
448     @defaults[type].each { |var,value|
449       values[var] = value
450     }
451   end
452 
453   values
454 end
lookuptype(name) click to toggle source

Look up a defined type.

    # File lib/puppet/parser/scope.rb
468 def lookuptype(name)
469   # This happens a lot, avoid making a call to make a call
470   krt = environment.known_resource_types
471   krt.find_definition(name) || krt.find_hostclass(name)
472 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
492 def lookupvar(name, options = EMPTY_HASH)
493   unless name.is_a? String
494     raise Puppet::ParseError, _("Scope variable name %{name} is a %{klass}, not a string") % { name: name.inspect, klass: name.class }
495   end
496 
497   # If name has '::' in it, it is resolved as a qualified variable
498   unless (idx = name.index('::')).nil?
499     # Always drop leading '::' if present as that is how the values are keyed.
500     return lookup_qualified_variable(idx == 0 ? name[2..-1] : name, options)
501   end
502 
503   # At this point, search is for a non qualified (simple) name
504   table = @ephemeral.last
505   val = table[name]
506   return val unless val.nil? && !table.include?(name)
507 
508   next_scope = inherited_scope || enclosing_scope
509   if next_scope
510     next_scope.lookupvar(name, options)
511   else
512     variable_not_found(name)
513   end
514 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
718 def merge_settings(env_name, set_in_this_scope=true)
719   settings = Puppet.settings
720   table = effective_symtable(false)
721   global_table = compiler.qualified_variables
722   all_local = {}
723   settings.each_key do |name|
724     next if :name == name
725     key = name.to_s
726     value = transform_setting(settings.value_sym(name, env_name))
727     if set_in_this_scope
728       table[key] = value
729     end
730     all_local[key] = value
731     # also write the fqn into global table for direct lookup
732     global_table["settings::#{key}"] = value
733   end
734   # set the 'all_local' - a hash of all settings
735   global_table["settings::all_local"] = all_local
736   nil
737 end
method_missing(method, *args, &block) click to toggle source
Calls superclass method
     # File lib/puppet/parser/scope.rb
1040 def method_missing(method, *args, &block)
1041   method.to_s =~ /^function_(.*)$/
1042   name = $1
1043   super unless name
1044   super unless Puppet::Parser::Functions.function(name)
1045   # In odd circumstances, this might not end up defined by the previous
1046   # method, so we might as well be certain.
1047   if respond_to? method
1048     send(method, *args)
1049   else
1050     raise Puppet::DevError, _("Function %{name} not defined despite being loaded!") % { name: name }
1051   end
1052 end
new_ephemeral(local_scope = false) click to toggle source

TODO: Who calls this?

    # File lib/puppet/parser/scope.rb
925 def new_ephemeral(local_scope = false)
926   if local_scope
927     @ephemeral.push(LocalScope.new(@ephemeral.last))
928   else
929     @ephemeral.push(MatchScope.new(@ephemeral.last, nil))
930   end
931 end
new_match_scope(match_data) click to toggle source

Nests a match data scope

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

Create a new scope and set these options.

    # File lib/puppet/parser/scope.rb
689 def newscope(options = {})
690   compiler.newscope(self, options)
691 end
parent_module_name() click to toggle source
    # File lib/puppet/parser/scope.rb
693 def parent_module_name
694   return nil unless @parent && @parent.source
695   @parent.source.module_name
696 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
909 def pop_ephemerals(level)
910   @ephemeral.pop(@ephemeral.size - level)
911 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
916 def push_ephemerals(ephemeral_scopes)
917   ephemeral_scopes.each { |ephemeral_scope| @ephemeral.push(ephemeral_scope) } unless ephemeral_scopes.nil?
918 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
1056 def resolve_type_and_titles(type, titles)
1057   raise Puppet::DevError, _("Scope#resolve_type_and_title() is no longer supported, use Puppet::Pops::Evaluator::Runtime3ResourceSupport instead")
1058 end
set_facts(hash) click to toggle source
    # File lib/puppet/parser/scope.rb
816 def set_facts(hash)
817   setvar('facts', deep_freeze(hash), :privileged => true)
818 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
 998 def set_match_data(match_data)
 999   @ephemeral.last.match_data = match_data
1000 end
set_server_facts(hash) click to toggle source
    # File lib/puppet/parser/scope.rb
820 def set_server_facts(hash)
821   setvar('server_facts', deep_freeze(hash), :privileged => true)
822 end
set_trusted(hash) click to toggle source
    # File lib/puppet/parser/scope.rb
812 def set_trusted(hash)
813   setvar('trusted', deep_freeze(hash), :privileged => true)
814 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
767 def setvar(name, value, options = EMPTY_HASH)
768   if name =~ /^[0-9]+$/
769     raise Puppet::ParseError.new(_("Cannot assign to a numeric match result variable '$%{name}'") % { name: name }) # unless options[:ephemeral]
770   end
771   unless name.is_a? String
772     raise Puppet::ParseError, _("Scope variable name %{name} is a %{class_type}, not a string") % { name: name.inspect, class_type: name.class }
773   end
774 
775   # Check for reserved variable names
776   if (name == VARNAME_TRUSTED || name == VARNAME_FACTS) && !options[:privileged]
777     raise Puppet::ParseError, _("Attempt to assign to a reserved variable name: '%{name}'") % { name: name }
778   end
779 
780   # Check for server_facts reserved variable name
781   if name == VARNAME_SERVER_FACTS && !options[:privileged]
782     raise Puppet::ParseError, _("Attempt to assign to a reserved variable name: '%{name}'") % { name: name }
783   end
784 
785   table = effective_symtable(options[:ephemeral])
786   if table.bound?(name)
787     error = Puppet::ParseError.new(_("Cannot reassign variable '$%{name}'") % { name: name })
788     error.file = options[:file] if options[:file]
789     error.line = options[:line] if options[:line]
790     raise error
791   end
792 
793   table[name] = value
794 
795   # Assign the qualified name in the environment
796   # Note that Settings scope has a source set to Boolean true.
797   #
798   # Only meaningful to set a fqn globally if table to assign to is the top of the scope's ephemeral stack
799   if @symtable.equal?(table)
800     if is_topscope?
801       # the scope name is '::'
802       compiler.qualified_variables[name] = value
803     elsif source.is_a?(Puppet::Resource::Type) && source.type == :hostclass
804       # the name is the name of the class
805       sourcename = source.name
806       compiler.qualified_variables["#{sourcename}::#{name}"] = value
807     end
808   end
809   value
810 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
673 def to_hash(recursive = true, include_undef = false)
674   if recursive and has_enclosing_scope?
675     target = enclosing_scope.to_hash(recursive)
676     if !(inherited = inherited_scope).nil?
677       target.merge!(inherited.to_hash(recursive))
678     end
679   else
680     target = Hash.new
681   end
682 
683   # add all local scopes
684   @ephemeral.last.add_entries_to(target, include_undef)
685   target
686 end
to_s() click to toggle source

Used mainly for logging

    # File lib/puppet/parser/scope.rb
879 def to_s
880   # As this is used for logging, this should really not be done in this class at all...
881   return "Scope(#{@resource})" unless @resource.nil?
882 
883   # For logging of function-scope - it is now showing the file and line.
884   detail = Puppet::Pops::PuppetStack.top_of_stack
885   return "Scope()" if detail.empty?
886 
887   # shorten the path if possible
888   path = detail[0]
889   env_path = nil
890   env_path = environment.configuration.path_to_env unless (environment.nil? || environment.configuration.nil?)
891   # check module paths first since they may be in the environment (i.e. they are longer)
892   module_path = environment.full_modulepath.detect {|m_path| path.start_with?(m_path) }
893   if module_path
894     path = "<module>" + path[module_path.length..-1]
895   elsif env_path && path && path.start_with?(env_path)
896     path = "<env>" + path[env_path.length..-1]
897   end
898   # Make the output appear as "Scope(path, line)"
899   "Scope(#{[path, detail[1]].join(', ')})" 
900 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
1073 def transform_and_assert_classnames(names)
1074   names.map do |name|
1075     case name
1076     when NilClass
1077       raise ArgumentError, _("Cannot use undef as a class name")
1078     when String
1079       raise ArgumentError, _("Cannot use empty string as a class name") if name.empty?
1080       name.sub(/^([^:]{1,2})/, '::\1')
1081 
1082     when Puppet::Resource
1083       assert_class_and_title(name.type, name.title)
1084       name.title.sub(/^([^:]{1,2})/, '::\1')
1085 
1086     when Puppet::Pops::Types::PClassType
1087       #TRANSLATORS "Class" and "Type" are Puppet keywords and should not be translated
1088       raise ArgumentError, _("Cannot use an unspecific Class[] Type") unless name.class_name
1089       name.class_name.sub(/^([^:]{1,2})/, '::\1')
1090 
1091     when Puppet::Pops::Types::PResourceType
1092       assert_class_and_title(name.type_name, name.title)
1093       name.title.sub(/^([^:]{1,2})/, '::\1')
1094     end.downcase
1095   end
1096 end
undef_as(x,v) click to toggle source
    # File lib/puppet/parser/scope.rb
474 def undef_as(x,v)
475   if v.nil? or v == :undef
476     x
477   else
478     v
479   end
480 end
variable_not_found(name, reason=nil) click to toggle source
    # File lib/puppet/parser/scope.rb
523 def variable_not_found(name, reason=nil)
524   # Built in variables and numeric variables always exist
525   if BUILT_IN_VARS.include?(name) || name =~ Puppet::Pops::Patterns::NUMERIC_VAR_NAME
526     return nil
527   end
528   begin
529     throw(:undefined_variable, reason)
530   rescue  UNCAUGHT_THROW_EXCEPTION
531     case Puppet[:strict]
532     when :off
533       # do nothing
534     when :warning
535       Puppet.warn_once(UNDEFINED_VARIABLES_KIND, _("Variable: %{name}") % { name: name },
536       _("Undefined variable '%{name}'; %{reason}") % { name: name, reason: reason } )
537     when :error
538       if Puppet.lookup(:avoid_hiera_interpolation_errors){false}
539         Puppet.warn_once(UNDEFINED_VARIABLES_KIND, _("Variable: %{name}") % { name: name },
540         _("Interpolation failed with '%{name}', but compilation continuing; %{reason}") % { name: name, reason: reason } )
541       else
542         raise ArgumentError, _("Undefined variable '%{name}'; %{reason}") % { name: name, reason: reason }
543       end
544     end
545   end
546   nil
547 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
939 def with_global_scope(&block)
940   find_global_scope.without_ephemeral_scopes(&block)
941 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
987 def with_guarded_scope
988   elevel = ephemeral_level
989   begin
990     yield
991   ensure
992     pop_ephemerals(elevel)
993   end
994 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
945 def with_local_scope(scope_variables)
946   local = LocalScope.new(@ephemeral.last)
947   scope_variables.each_pair { |k, v| local[k] = v }
948   @ephemeral.push(local)
949   begin
950     yield(self)
951   ensure
952     @ephemeral.pop
953   end
954 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
974 def with_parameter_scope(callee_name, param_names)
975   param_scope = ParameterScope.new(@ephemeral.last, callee_name, param_names)
976   with_guarded_scope do
977     @ephemeral.push(param_scope)
978     yield(param_scope)
979   end
980 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
959 def without_ephemeral_scopes
960   save_ephemeral = @ephemeral
961   begin
962     @ephemeral = [ @symtable ]
963     yield(self)
964   ensure
965     @ephemeral = save_ephemeral
966   end
967 end

Private Instance Methods

assert_class_and_title(type_name, title) click to toggle source
     # File lib/puppet/parser/scope.rb
1112 def assert_class_and_title(type_name, title)
1113   if type_name.nil? || type_name == ''
1114     #TRANSLATORS "Resource" is a class name and should not be translated
1115     raise ArgumentError, _("Cannot use an unspecific Resource[] where a Resource['class', name] is expected")
1116   end
1117   unless type_name =~ /^[Cc]lass$/
1118     #TRANSLATORS "Resource" is a class name and should not be translated
1119     raise ArgumentError, _("Cannot use a Resource[%{type_name}] where a Resource['class', name] is expected") % { type_name: type_name }
1120   end
1121   if title.nil?
1122     #TRANSLATORS "Resource" is a class name and should not be translated
1123     raise ArgumentError, _("Cannot use an unspecific Resource['class'] where a Resource['class', name] is expected")
1124   end
1125 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
828 def deep_freeze(object)
829   case object
830   when Array
831     object.each {|v| deep_freeze(v) }
832     object.freeze
833   when Hash
834     object.each {|k, v| deep_freeze(k); deep_freeze(v) }
835     object.freeze
836   when NilClass, Numeric, TrueClass, FalseClass
837     # do nothing
838   when String
839     object.freeze
840   else
841     raise Puppet::Error, _("Unsupported data type: '%{klass}'") % { klass: object.class }
842   end
843   object
844 end
extend_with_functions_module() click to toggle source
     # File lib/puppet/parser/scope.rb
1127 def extend_with_functions_module
1128   root = Puppet.lookup(:root_environment)
1129   extend Puppet::Parser::Functions.environment_module(root)
1130   extend Puppet::Parser::Functions.environment_module(environment) if environment != root
1131 end
has_enclosing_scope?() click to toggle source
    # File lib/puppet/parser/scope.rb
654 def has_enclosing_scope?
655   ! parent.nil?
656 end
qualified_scope(classname) click to toggle source
    # File lib/puppet/parser/scope.rb
659 def qualified_scope(classname)
660   klass = find_hostclass(classname)
661   raise _("class %{classname} could not be found") % { classname: classname }     unless klass
662   kscope = class_scope(klass)
663   raise _("class %{classname} has not been evaluated") % { classname: classname } unless kscope
664   kscope
665 end
transform_setting(val) click to toggle source
    # File lib/puppet/parser/scope.rb
739 def transform_setting(val)
740   if val.is_a?(String) || val.is_a?(Numeric) || true == val || false == val || nil == val
741     val
742   elsif val.is_a?(Array)
743     val.map {|entry| transform_setting(entry) }
744   elsif val.is_a?(Hash)
745     result = {}
746     val.each {|k,v| result[transform_setting(k)] = transform_setting(v) }
747     result
748   else
749     # not ideal, but required as there are settings values that are special
750     :undef == val ? nil : val.to_s
751   end
752 end