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
Hash of hashes of default values per type name
Public Class Methods
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
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
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
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
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
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
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
Alias for `compiler.catalog`
# File lib/puppet/parser/scope.rb 38 def catalog 39 @compiler.catalog 40 end
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
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
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
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
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
Alias for `compiler.environment`
# File lib/puppet/parser/scope.rb 33 def environment 34 @compiler.environment 35 end
# 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
# File lib/puppet/parser/scope.rb 920 def ephemeral_level 921 @ephemeral.size 922 end
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
@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
@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
# File lib/puppet/parser/scope.rb 349 def find_definition(name) 350 environment.known_resource_types.find_definition(name) 351 end
# 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
# File lib/puppet/parser/scope.rb 345 def find_hostclass(name) 346 environment.known_resource_types.find_hostclass(name) 347 end
@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
# File lib/puppet/parser/scope.rb 369 def findresource(type, title = nil) 370 @compiler.catalog.resource(type, title) 371 end
@api private
# File lib/puppet/parser/scope.rb 636 def get_local_variable(name) 637 @ephemeral.last[name] 638 end
# 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
@api private
# File lib/puppet/parser/scope.rb 631 def has_local_variable?(name) 632 @ephemeral.last.include?(name) 633 end
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
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
# File lib/puppet/parser/scope.rb 591 def is_classscope? 592 resource && resource.type == TYPENAME_CLASS 593 end
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
# File lib/puppet/parser/scope.rb 595 def is_nodescope? 596 resource && resource.type == TYPENAME_NODE 597 end
# File lib/puppet/parser/scope.rb 599 def is_topscope? 600 equal?(@compiler.topscope) 601 end
@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
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
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
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 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
# 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
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
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
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
# 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 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 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
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
# File lib/puppet/parser/scope.rb 816 def set_facts(hash) 817 setvar('facts', deep_freeze(hash), :privileged => true) 818 end
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
# File lib/puppet/parser/scope.rb 820 def set_server_facts(hash) 821 setvar('server_facts', deep_freeze(hash), :privileged => true) 822 end
# File lib/puppet/parser/scope.rb 812 def set_trusted(hash) 813 setvar('trusted', deep_freeze(hash), :privileged => true) 814 end
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
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
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
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
# 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
# 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
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
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
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
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
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
# 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
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
# 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
# File lib/puppet/parser/scope.rb 654 def has_enclosing_scope? 655 ! parent.nil? 656 end
# 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
# 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