module Puppet::Pops::Lookup::Interpolation
Adds support for interpolation expressions. The expressions may contain keys that uses dot-notation to further navigate into hashes and arrays
@api public
Constants
- EMPTY_INTERPOLATIONS
- QUOTED_KEY
Matches a key that is quoted using a matching pair of either single or double quotes.
Public Instance Methods
interpolate(value, context, allow_methods)
click to toggle source
@param value [Object] The value to interpolate @param context [Context] The current lookup context @param allow_methods [Boolean] `true` if interpolation expression that contains lookup methods are allowed @return [Object] the result of resolving all interpolations in the given value @api public
# File lib/puppet/pops/lookup/interpolation.rb 18 def interpolate(value, context, allow_methods) 19 case value 20 when String 21 value.index('%{').nil? ? value : interpolate_string(value, context, allow_methods) 22 when Array 23 value.map { |element| interpolate(element, context, allow_methods) } 24 when Hash 25 result = {} 26 value.each_pair { |k, v| result[interpolate(k, context, allow_methods)] = interpolate(v, context, allow_methods) } 27 result 28 else 29 value 30 end 31 end
Private Instance Methods
fail(issue, args = EMPTY_HASH)
click to toggle source
# File lib/puppet/pops/lookup/interpolation.rb 155 def fail(issue, args = EMPTY_HASH) 156 raise Puppet::DataBinding::LookupError.new( 157 issue.format(args), nil, nil, nil, nil, issue.issue_code) 158 end
get_method_and_data(data, allow_methods)
click to toggle source
# File lib/puppet/pops/lookup/interpolation.rb 143 def get_method_and_data(data, allow_methods) 144 match = data.match(/^(\w+)\((?:["]([^"]+)["]|[']([^']+)['])\)$/) 145 if match 146 fail(Issues::HIERA_INTERPOLATION_METHOD_SYNTAX_NOT_ALLOWED) unless allow_methods 147 key = match[1].to_sym 148 data = match[2] || match[3] # double or single qouted 149 else 150 key = :scope 151 end 152 [key, data] 153 end
interpolate_method(method_key)
click to toggle source
# File lib/puppet/pops/lookup/interpolation.rb 73 def interpolate_method(method_key) 74 @@interpolate_methods ||= begin 75 global_lookup = lambda do |key, lookup_invocation, _| 76 scope = lookup_invocation.scope 77 if scope.is_a?(Hiera::Scope) && !lookup_invocation.global_only? 78 # "unwrap" the Hiera::Scope 79 scope = scope.real 80 end 81 lookup_invocation.with_scope(scope) do |sub_invocation| 82 sub_invocation.lookup(key) { Lookup.lookup(key, nil, '', true, nil, sub_invocation) } 83 end 84 end 85 scope_lookup = lambda do |key, lookup_invocation, subject| 86 segments = split_key(key) { |problem| Puppet::DataBinding::LookupError.new("#{problem} in string: #{subject}") } 87 root_key = segments.shift 88 value = lookup_invocation.with(:scope, 'Global Scope') do 89 ovr = lookup_invocation.override_values 90 if ovr.include?(root_key) 91 lookup_invocation.report_found_in_overrides(root_key, ovr[root_key]) 92 else 93 scope = lookup_invocation.scope 94 val = nil 95 if (default_key_exists = lookup_invocation.default_values.include?(root_key) ) 96 catch(:undefined_variable) { val = scope[root_key] } 97 else 98 val = scope[root_key] 99 end 100 if val.nil? && !nil_in_scope?(scope, root_key) 101 if default_key_exists 102 lookup_invocation.report_found_in_defaults(root_key, 103 lookup_invocation.default_values[root_key]) 104 else 105 nil 106 end 107 else 108 lookup_invocation.report_found(root_key, val) 109 end 110 end 111 end 112 unless value.nil? || segments.empty? 113 found = nil; 114 catch(:no_such_key) { found = sub_lookup(key, lookup_invocation, segments, value) } 115 value = found; 116 end 117 lookup_invocation.remember_scope_lookup(key, root_key, segments, value) 118 value 119 end 120 121 { 122 :lookup => global_lookup, 123 :hiera => global_lookup, # this is just an alias for 'lookup' 124 :alias => global_lookup, # same as 'lookup' but expression must be entire string and result is not subject to string substitution 125 :scope => scope_lookup, 126 :literal => lambda { |key, _, _| key } 127 }.freeze 128 end 129 interpolate_method = @@interpolate_methods[method_key] 130 fail(Issues::HIERA_INTERPOLATION_UNKNOWN_INTERPOLATION_METHOD, :name => method_key) unless interpolate_method 131 interpolate_method 132 end
interpolate_string(subject, context, allow_methods)
click to toggle source
# File lib/puppet/pops/lookup/interpolation.rb 47 def interpolate_string(subject, context, allow_methods) 48 lookup_invocation = context.is_a?(Invocation) ? context : context.invocation 49 lookup_invocation.with(:interpolate, subject) do 50 subject.gsub(/%\{([^\}]*)\}/) do |match| 51 expr = $1 52 # Leading and trailing spaces inside an interpolation expression are insignificant 53 expr.strip! 54 value = nil 55 unless EMPTY_INTERPOLATIONS[expr] 56 method_key, key = get_method_and_data(expr, allow_methods) 57 is_alias = method_key == :alias 58 59 # Alias is only permitted if the entire string is equal to the interpolate expression 60 fail(Issues::HIERA_INTERPOLATION_ALIAS_NOT_ENTIRE_STRING) if is_alias && subject != match 61 value = interpolate_method(method_key).call(key, lookup_invocation, subject) 62 63 # break gsub and return value immediately if this was an alias substitution. The value might be something other than a String 64 return value if is_alias 65 66 value = lookup_invocation.check(method_key == :scope ? "scope:#{key}" : key) { interpolate(value, lookup_invocation, allow_methods) } 67 end 68 value.nil? ? '' : value 69 end 70 end 71 end
nil_in_scope?(scope, key)
click to toggle source
Because the semantics of Puppet::Parser::Scope#include? differs from Hash#include?
# File lib/puppet/pops/lookup/interpolation.rb 135 def nil_in_scope?(scope, key) 136 if scope.is_a?(Hash) 137 scope.include?(key) 138 else 139 scope.exist?(key) 140 end 141 end