Class: Puppet::Pops::Binder::Lookup
- Defined in:
- lib/puppet/pops/binder/lookup.rb
Overview
This class is the backing implementation of the Puppet function ‘lookup’. See puppet/parser/functions/lookup.rb for documentation.
Defined Under Namespace
Classes: PrivateNotFoundMarker
Class Method Summary collapse
- .fail(msg) ⇒ Object
- .fail_lookup(names) ⇒ Object
- .is_nil_or_undef?(x) ⇒ Boolean
-
.lookup(scope, args) ⇒ Object
This is the method called from the puppet/parser/functions/lookup.rb.
- .nil_as_undef(x) ⇒ Object
- .parse_lookup_args(args) ⇒ Object
- .search_for(scope, type, name, options) ⇒ Object
- .to_symbolic_hash(input) ⇒ Object
- .type_mismatch(type_calculator, expected, got) ⇒ Object
- .undef_as_nil(x) ⇒ Object
- .validate_options(options, type_calculator) ⇒ Object
Class Method Details
.fail(msg) ⇒ Object
54 55 56 |
# File 'lib/puppet/pops/binder/lookup.rb', line 54 def self.fail(msg) raise Puppet::ParseError, "Function lookup() " + msg end |
.fail_lookup(names) ⇒ Object
58 59 60 61 62 63 64 65 |
# File 'lib/puppet/pops/binder/lookup.rb', line 58 def self.fail_lookup(names) name_part = if names.size == 1 "the name '#{names[0]}'" else "any of the names ['" + names.join(', ') + "']" end fail("did not find a value for #{name_part}") end |
.is_nil_or_undef?(x) ⇒ Boolean
115 116 117 |
# File 'lib/puppet/pops/binder/lookup.rb', line 115 def self.is_nil_or_undef?(x) x.nil? || x == :undef end |
.lookup(scope, args) ⇒ Object
This is the method called from the puppet/parser/functions/lookup.rb
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/puppet/pops/binder/lookup.rb', line 142 def self.lookup(scope, args) type_calculator = Puppet::Pops::Types::TypeCalculator.new = parse_lookup_args(args) (, type_calculator) names = [[:name]].flatten type = [:type] result_with_name = names.reduce([]) do |memo, name| break memo if !memo[1].nil? [name, search_for(scope, type, name, )] end result = if result_with_name[1].nil? # not found, use default (which may be nil), the default is already type checked [:default] else # injector.lookup is type-safe already do no need to type check the result result_with_name[1] end # If a block is given it is called with :undef passed as 'nil' since the lookup function # is available from 3x with --binder turned on, and the evaluation is always 4x. # TODO PUPPET4: Simply pass the value # result = if pblock = [:pblock] result2 = case pblock.parameter_count when 1 pblock.call(scope, undef_as_nil(result)) when 2 pblock.call(scope, result_with_name[ 0 ], undef_as_nil(result)) else pblock.call(scope, result_with_name[ 0 ], undef_as_nil(result), undef_as_nil([ :default ])) end # if the given result was returned, there is no need to type-check it again if !result2.equal?(result) t = type_calculator.infer(undef_as_nil(result2)) if !type_calculator.assignable?(type, t) fail "the value produced by the given code block #{type_mismatch(type_calculator, type, t)}" end end result2 else result end # Finally, the result if nil must be acceptable or an error is raised if is_nil_or_undef?(result) && ![:accept_undef] fail_lookup(names) else # Since the function may be used without future parser being in effect, nil is not handled in a good # way, and should instead be turned into :undef. # TODO PUPPET4: Simply return the result # Puppet[:parser] == 'future' ? result : nil_as_undef(result) end end |
.nil_as_undef(x) ⇒ Object
107 108 109 |
# File 'lib/puppet/pops/binder/lookup.rb', line 107 def self.nil_as_undef(x) x.nil? ? :undef : x end |
.parse_lookup_args(args) ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/puppet/pops/binder/lookup.rb', line 6 def self.parse_lookup_args(args) = {} pblock = if args[-1].respond_to?(:puppet_lambda) args.pop end case args.size when 1 # name, or all options if args[ 0 ].is_a?(Hash) = to_symbolic_hash(args[ 0 ]) else [ :name ] = args[ 0 ] end when 2 # name and type, or name and options if args[ 1 ].is_a?(Hash) = to_symbolic_hash(args[ 1 ]) [:name] = args[ 0 ] # silently overwrite option with given name else [:name] = args[ 0 ] [:type] = args[ 1 ] end when 3 # name, type, default (no options) [ :name ] = args[ 0 ] [ :type ] = args[ 1 ] [ :default ] = args[ 2 ] else raise Puppet::ParseError, "The lookup function accepts 1-3 arguments, got #{args.size}" end [:pblock] = pblock end |
.search_for(scope, type, name, options) ⇒ Object
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/puppet/pops/binder/lookup.rb', line 124 def self.search_for(scope, type, name, ) # search in order, override, injector, hiera, then extra if !(result = [:override][name]).nil? result elsif !(result = scope.compiler.injector.lookup(scope, type, name)).nil? result else result = scope.function_hiera([name, PrivateNotFoundMarker]) if !result.nil? && result != PrivateNotFoundMarker result else [:extra][name] end end end |
.to_symbolic_hash(input) ⇒ Object
43 44 45 46 47 48 |
# File 'lib/puppet/pops/binder/lookup.rb', line 43 def self.to_symbolic_hash(input) names = [:name, :type, :default, :accept_undef, :extra, :override] = {} names.each {|n| [n] = undef_as_nil(input[n.to_s] || input[n]) } end |
.type_mismatch(type_calculator, expected, got) ⇒ Object
50 51 52 |
# File 'lib/puppet/pops/binder/lookup.rb', line 50 def self.type_mismatch(type_calculator, expected, got) "has wrong type, expected #{type_calculator.string(expected)}, got #{type_calculator.string(got)}" end |
.undef_as_nil(x) ⇒ Object
111 112 113 |
# File 'lib/puppet/pops/binder/lookup.rb', line 111 def self.undef_as_nil(x) is_nil_or_undef?(x) ? nil : x end |
.validate_options(options, type_calculator) ⇒ Object
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/puppet/pops/binder/lookup.rb', line 67 def self.(, type_calculator) type_parser = Puppet::Pops::Types::TypeParser.new name_type = type_parser.parse('Variant[Array[String], String]') if is_nil_or_undef?([:name]) || [:name].is_a?(Array) && [:name].empty? fail ("requires a name, or array of names. Got nothing to lookup.") end t = type_calculator.infer([:name]) if ! type_calculator.assignable?(name_type, t) fail("given 'name' argument, #{type_mismatch(type_calculator, options[:name], t)}") end # unless a type is already given (future case), parse the type (or default 'Data'), fails if invalid type is given unless [:type].is_a?(Puppet::Pops::Types::PAnyType) [:type] = type_parser.parse([:type] || 'Data') end # default value must comply with the given type if [:default] t = type_calculator.infer([:default]) if ! type_calculator.assignable?([:type], t) fail("'default' value #{type_mismatch(type_calculator, options[:type], t)}") end end if [:extra] && ![:extra].is_a?(Hash) # do not perform inference here, it is enough to know that it is not a hash fail("'extra' value must be a Hash, got #{options[:extra].class}") end [:extra] = {} unless [:extra] if [:override] && ![:override].is_a?(Hash) # do not perform inference here, it is enough to know that it is not a hash fail("'override' value must be a Hash, got #{options[:extra].class}") end [:override] = {} unless [:override] end |