Class: Puppet::Pops::Evaluator::Closure
- Inherits:
-
CallableSignature
- Object
- CallableSignature
- Puppet::Pops::Evaluator::Closure
- Defined in:
- lib/puppet/pops/evaluator/closure.rb
Overview
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.
Instance Attribute Summary collapse
- #enclosing_scope ⇒ Object readonly
- #evaluator ⇒ Object readonly
- #model ⇒ Object readonly
Instance Method Summary collapse
- #block_name ⇒ Object
-
#call(*args) ⇒ Object
compatible with 3x AST::Lambda.
-
#call_by_name(scope, args_hash, enforce_parameters) ⇒ Object
Call closure with argument assignment by name.
-
#initialize(evaluator, model, scope) ⇒ Closure
constructor
A new instance of Closure.
- #last_captures_rest? ⇒ Boolean
-
#parameter_count ⇒ Integer
Returns the number of parameters (required and optional).
- #parameter_names ⇒ Object
- #parameters ⇒ Object
-
#puppet_lambda ⇒ Object
deprecated
private
Deprecated.
Use the type system to query if an object is of Callable type, then use its signatures method for info
- #type ⇒ Object
Methods inherited from CallableSignature
#args_range, #block_range, #block_type, #infinity?
Constructor Details
#initialize(evaluator, model, scope) ⇒ Closure
Returns a new instance of Closure.
17 18 19 20 21 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 17 def initialize(evaluator, model, scope) @evaluator = evaluator @model = model @enclosing_scope = scope end |
Instance Attribute Details
#enclosing_scope ⇒ Object (readonly)
15 16 17 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 15 def enclosing_scope @enclosing_scope end |
#evaluator ⇒ Object (readonly)
13 14 15 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 13 def evaluator @evaluator end |
#model ⇒ Object (readonly)
14 15 16 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 14 def model @model end |
Instance Method Details
#block_name ⇒ Object
118 119 120 121 |
# 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) ⇒ Object
compatible with 3x AST::Lambda
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# 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) ⇒ Object
Call closure with argument assignment by name
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# 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? ⇒ Boolean
112 113 114 115 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 112 def last_captures_rest? last = @model.parameters[-1] last && last.captures_rest end |
#parameter_count ⇒ Integer
Returns the number of parameters (required and optional)
96 97 98 99 |
# 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 ⇒ Object
102 103 104 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 102 def parameter_names @model.parameters.collect(&:name) end |
#parameters ⇒ Object
90 91 92 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 90 def parameters @model.parameters end |
#puppet_lambda ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Use the type system to query if an object is of Callable type, then use its signatures method for info
marker method checked with respond_to :puppet_lambda
26 27 28 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 26 def puppet_lambda() true end |
#type ⇒ Object
107 108 109 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 107 def type @callable ||= create_callable_type end |