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.
@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
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 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
@api public
# File lib/puppet/pops/evaluator/closure.rb, line 112 def last_captures_rest? last = @model.parameters[-1] last && last.captures_rest end
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
@api public
# File lib/puppet/pops/evaluator/closure.rb, line 102 def parameter_names @model.parameters.collect(&:name) end
# File lib/puppet/pops/evaluator/closure.rb, line 90 def parameters @model.parameters end
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
@api public
# File lib/puppet/pops/evaluator/closure.rb, line 107 def type @callable ||= create_callable_type end
# File lib/puppet/pops/evaluator/closure.rb, line 17 def initialize(evaluator, model, scope) @evaluator = evaluator @model = model @enclosing_scope = scope end