class Puppet::Pops::Evaluator::Closure

A Closure represents logic bound to a particular scope. As long as the runtime (basically the scope implementation) has the behaviour of Puppet 3x it is not safe to use this closure when the scope given to it when initialized goes “out of scope”.

Note that the implementation is backwards compatible in that the call method accepts a scope, but this scope is not used.

Note that this class is a CallableSignature, and the methods defined there should be used as the API for obtaining information in a callable implementation agnostic way.

Constants

ANY_NUMBER_RANGE
OPTIONAL_SINGLE_RANGE
REQUIRED_SINGLE_RANGE

Attributes

enclosing_scope[R]
evaluator[R]
model[R]

Public Instance Methods

block_name() click to toggle source

@api public

# File lib/puppet/pops/evaluator/closure.rb, line 118
def block_name
  # TODO: Lambda's does not support blocks yet. This is a placeholder
  'unsupported_block'
end
call(*args) click to toggle source

compatible with 3x AST::Lambda @api public

# File lib/puppet/pops/evaluator/closure.rb, line 32
def call(*args)
  variable_bindings = combine_values_with_parameters(args)

  tc = Puppet::Pops::Types::TypeCalculator
  final_args = tc.infer_set(parameters.inject([]) do |final_args, param|
    if param.captures_rest
      final_args.concat(variable_bindings[param.name])
    else
      final_args << variable_bindings[param.name]
    end
  end)

  if tc.callable?(type, final_args)
    @evaluator.evaluate_block_with_bindings(@enclosing_scope, variable_bindings, @model.body)
  else
    raise ArgumentError, "lambda called with mis-matched arguments\n#{Puppet::Pops::Evaluator::CallableMismatchDescriber.diff_string('lambda', final_args, [self])}"
  end
end
call_by_name(scope, args_hash, enforce_parameters) click to toggle source

Call closure with argument assignment by name

# File lib/puppet/pops/evaluator/closure.rb, line 52
def call_by_name(scope, args_hash, enforce_parameters)
  if enforce_parameters
    if args_hash.size > parameters.size
      raise ArgumentError, "Too many arguments: #{args_hash.size} for #{parameters.size}"
    end

    # associate values with parameters
    scope_hash = {}
    parameters.each do |p|
      name = p.name
      if (arg_value = args_hash[name]).nil?
        # only set result of default expr if it is defined (it is otherwise not possible to differentiate
        # between explicit undef and no default expression
        unless p.value.nil?
          scope_hash[name] = @evaluator.evaluate(p.value, @enclosing_scope)
        end
      else
        scope_hash[name] = arg_value
      end
    end

    missing = parameters.select { |p| !scope_hash.include?(p.name) }
    if missing.any?
      raise ArgumentError, "Too few arguments; no value given for required parameters #{missing.collect(&:name).join(" ,")}"
    end

    tc = Puppet::Pops::Types::TypeCalculator
    final_args = tc.infer_set(parameter_names.collect { |param| scope_hash[param] })
    if !tc.callable?(type, final_args)
      raise ArgumentError, "lambda called with mis-matched arguments\n#{Puppet::Pops::Evaluator::CallableMismatchDescriber.diff_string('lambda', final_args, [self])}"
    end
  else
    scope_hash = args_hash
  end

  @evaluator.evaluate_block_with_bindings(@enclosing_scope, scope_hash, @model.body)
end
last_captures_rest?() click to toggle source

@api public

# File lib/puppet/pops/evaluator/closure.rb, line 112
def last_captures_rest?
  last = @model.parameters[-1]
  last && last.captures_rest
end
parameter_count() click to toggle source

Returns the number of parameters (required and optional) @return [Integer] the total number of accepted parameters

# File lib/puppet/pops/evaluator/closure.rb, line 96
def parameter_count
  # yes, this is duplication of code, but it saves a method call
  @model.parameters.size
end
parameter_names() click to toggle source

@api public

# File lib/puppet/pops/evaluator/closure.rb, line 102
def parameter_names
  @model.parameters.collect(&:name)
end
parameters() click to toggle source
# File lib/puppet/pops/evaluator/closure.rb, line 90
def parameters
  @model.parameters
end
puppet_lambda() click to toggle source

marker method checked with respond_to :#puppet_lambda @api private @deprecated Use the type system to query if an object is of Callable type, then use its signatures method for info

# File lib/puppet/pops/evaluator/closure.rb, line 26
def puppet_lambda()
  true
end
type() click to toggle source

@api public

# File lib/puppet/pops/evaluator/closure.rb, line 107
def type
  @callable ||= create_callable_type
end

Public Class Methods

new(evaluator, model, scope) click to toggle source
# File lib/puppet/pops/evaluator/closure.rb, line 17
def initialize(evaluator, model, scope)
  @evaluator = evaluator
  @model = model
  @enclosing_scope = scope
end