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 behavior of Puppet 3x it is not safe to return and later use this closure.
The 3x scope is essentially a named scope with an additional internal local/ephemeral nested scope state. In 3x there is no way to directly refer to the nested scopes, instead, the named scope must be in a particular state. Specifically, closures that require a local/ephemeral scope to exist at a later point will fail. It is safe to call a closure (even with 3x scope) from the very same place it was defined, but not returning it and expecting the closure to reference the scope’s state at the point it was created.
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.
Defined Under Namespace
Constant Summary collapse
- CLOSURE_NAME =
'lambda'.freeze
Instance Attribute Summary collapse
- #enclosing_scope ⇒ Object readonly
- #evaluator ⇒ Object readonly
- #model ⇒ Object readonly
Instance Method Summary collapse
- #block_name ⇒ Object
-
#call(*args) ⇒ Object
Evaluates a closure in its enclosing scope after having matched given arguments with parameters (from left to right).
-
#call_by_name(args_hash, enforce_parameters) ⇒ Object
Call closure with argument assignment by name.
- #closure_name ⇒ Object
-
#initialize(evaluator, model) ⇒ Closure
constructor
A new instance of Closure.
-
#invoke(instance, calling_scope, args, &block) ⇒ Object
private
This method makes a Closure compatible with a Dispatch.
- #last_captures_rest? ⇒ Boolean
-
#parameter_count ⇒ Integer
Returns the number of parameters (required and optional).
- #parameter_names ⇒ Object
- #parameters ⇒ Object
- #params_struct ⇒ Object
- #return_type ⇒ Object
- #type ⇒ Object
Methods inherited from CallableSignature
#args_range, #block_range, #block_type, #infinity?
Constructor Details
#initialize(evaluator, model) ⇒ Closure
Returns a new instance of Closure.
60 61 62 63 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 60 def initialize(evaluator, model) @evaluator = evaluator @model = model end |
Instance Attribute Details
#enclosing_scope ⇒ Object (readonly)
58 59 60 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 58 def enclosing_scope @enclosing_scope end |
#evaluator ⇒ Object (readonly)
56 57 58 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 56 def evaluator @evaluator end |
#model ⇒ Object (readonly)
57 58 59 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 57 def model @model end |
Instance Method Details
#block_name ⇒ Object
153 154 155 156 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 153 def block_name # TODO: Lambda's does not support blocks yet. This is a placeholder 'unsupported_block' end |
#call(*args) ⇒ Object
Evaluates a closure in its enclosing scope after having matched given arguments with parameters (from left to right)
67 68 69 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 67 def call(*args) call_with_scope(enclosing_scope, args) end |
#call_by_name(args_hash, enforce_parameters) ⇒ Object
Call closure with argument assignment by name
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 82 def call_by_name(args_hash, enforce_parameters) closure_scope = enclosing_scope if enforce_parameters # Push a temporary parameter scope used while resolving the parameter defaults closure_scope.with_parameter_scope(closure_name, parameter_names) do |param_scope| # Assign all non-nil values, even those that represent non-existent paramaters. args_hash.each { |k, v| param_scope[k] = v unless v.nil? } parameters.each do |p| name = p.name arg = args_hash[name] if arg.nil? # Arg either wasn't given, or it was undef if p.value.nil? # No default. Assign nil if the args_hash included it param_scope[name] = nil if args_hash.include?(name) else param_scope[name] = param_scope.evaluate(name, p.value, closure_scope, @evaluator) end end end args_hash = param_scope.to_hash end Types::TypeMismatchDescriber.validate_parameters(closure_name, params_struct, args_hash) result = catch(:next) do @evaluator.evaluate_block_with_bindings(closure_scope, args_hash, @model.body) end Types::TypeAsserter.assert_instance_of(nil, return_type, result) do "value returned from #{closure_name}" end else @evaluator.evaluate_block_with_bindings(closure_scope, args_hash, @model.body) end end |
#closure_name ⇒ Object
161 162 163 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 161 def closure_name() CLOSURE_NAME end |
#invoke(instance, calling_scope, args, &block) ⇒ 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.
This method makes a Closure compatible with a Dispatch. This is used when the closure is wrapped in a Function and the function is called. (Saves an extra Dispatch that just delegates to a Closure and avoids having two checks of the argument type/arity validity).
75 76 77 78 79 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 75 def invoke(instance, calling_scope, args, &block) enclosing_scope.with_global_scope do |global_scope| call_with_scope(global_scope, args, &block) end end |
#last_captures_rest? ⇒ Boolean
147 148 149 150 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 147 def last_captures_rest? last = @model.parameters[-1] last && last.captures_rest end |
#parameter_count ⇒ Integer
Returns the number of parameters (required and optional)
122 123 124 125 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 122 def parameter_count # yes, this is duplication of code, but it saves a method call @model.parameters.size end |
#parameter_names ⇒ Object
128 129 130 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 128 def parameter_names @model.parameters.collect(&:name) end |
#parameters ⇒ Object
116 117 118 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 116 def parameters @model.parameters end |
#params_struct ⇒ Object
142 143 144 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 142 def params_struct @params_struct ||= create_params_struct end |
#return_type ⇒ Object
132 133 134 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 132 def return_type @return_type ||= create_return_type end |
#type ⇒ Object
137 138 139 |
# File 'lib/puppet/pops/evaluator/closure.rb', line 137 def type @callable ||= create_callable_type end |