class Puppet::Pops::Binder::Lookup

This class is the backing implementation of the Puppet function ‘lookup’. See puppet/parser/functions/lookup.rb for documentation.

Public Class Methods

lookup(scope, args) click to toggle source

This is the method called from the puppet/parser/functions/lookup.rb @param args [Array] array following the puppet function call conventions

# File lib/puppet/pops/binder/lookup.rb, line 159
def self.lookup(scope, args)
  type_calculator = Puppet::Pops::Types::TypeCalculator.new
  options = parse_lookup_args(args)
  validate_options(options, type_calculator)
  names = [options[:name]].flatten
  type = options[:type]

  result_with_name = names.reduce([]) do |memo, name|
    break memo if !memo[1].nil?
    [name, search_for(scope, type, name, options)]
  end

  result = if result_with_name[1].nil?
    # not found, use default (which may be nil), the default is already type checked
    options[: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 = options[:pblock]
    result2 = case pblock.parameter_count
    when 1
      pblock.call(undef_as_nil(result))
    when 2
      pblock.call(result_with_name[ 0 ], undef_as_nil(result))
    else
      pblock.call(result_with_name[ 0 ], undef_as_nil(result), undef_as_nil(options[ :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) && !options[: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.future_parser? ? result : nil_as_undef(result)
  end
end
parse_lookup_args(args) click to toggle source
# File lib/puppet/pops/binder/lookup.rb, line 6
def self.parse_lookup_args(args)
  options = {}
  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)
      options = to_symbolic_hash(args[ 0 ])
    else
      options[ :name ] = args[ 0 ]
    end

  when 2
    # name and type, or name and options
    if args[ 1 ].is_a?(Hash)
      options = to_symbolic_hash(args[ 1 ])
      options[:name] = args[ 0 ] # silently overwrite option with given name
    else
      options[:name] = args[ 0 ]
      options[:type] = args[ 1 ]
    end

  when 3
    # name, type, default (no options)
    options[ :name ] = args[ 0 ]
    options[ :type ] = args[ 1 ]
    options[ :default ] = args[ 2 ]
  else
    raise Puppet::ParseError, "The lookup function accepts 1-3 arguments, got #{args.size}"
  end
  options[:pblock] = pblock
  options
end