puppet 3.7.4 → 3.7.5
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puppet might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/CONTRIBUTING.md +11 -6
- data/ext/build_defaults.yaml +2 -2
- data/ext/systemd/puppet.service +1 -0
- data/lib/hiera/puppet_function.rb +71 -0
- data/lib/puppet.rb +12 -0
- data/lib/puppet/application/device.rb +22 -5
- data/lib/puppet/daemon.rb +13 -4
- data/lib/puppet/defaults.rb +27 -4
- data/lib/puppet/environments.rb +1 -1
- data/lib/puppet/error.rb +4 -0
- data/lib/puppet/functions.rb +118 -65
- data/lib/puppet/functions/assert_type.rb +5 -5
- data/lib/puppet/functions/each.rb +12 -12
- data/lib/puppet/functions/epp.rb +3 -4
- data/lib/puppet/functions/filter.rb +12 -12
- data/lib/puppet/functions/hiera.rb +29 -0
- data/lib/puppet/functions/hiera_array.rb +34 -0
- data/lib/puppet/functions/hiera_hash.rb +36 -0
- data/lib/puppet/functions/hiera_include.rb +50 -0
- data/lib/puppet/functions/inline_epp.rb +2 -3
- data/lib/puppet/functions/map.rb +12 -12
- data/lib/puppet/functions/reduce.rb +6 -6
- data/lib/puppet/functions/scanf.rb +3 -3
- data/lib/puppet/functions/slice.rb +10 -9
- data/lib/puppet/functions/with.rb +3 -4
- data/lib/puppet/graph/simple_graph.rb +5 -5
- data/lib/puppet/metatype/manager.rb +1 -1
- data/lib/puppet/node/environment.rb +1 -1
- data/lib/puppet/parser/ast/arithmetic_operator.rb +1 -1
- data/lib/puppet/parser/ast/collexpr.rb +1 -1
- data/lib/puppet/parser/compiler.rb +3 -3
- data/lib/puppet/parser/functions/create_resources.rb +1 -9
- data/lib/puppet/parser/functions/defined.rb +1 -1
- data/lib/puppet/parser/functions/hiera.rb +20 -11
- data/lib/puppet/parser/functions/hiera_array.rb +23 -13
- data/lib/puppet/parser/functions/hiera_hash.rb +25 -15
- data/lib/puppet/parser/functions/hiera_include.rb +20 -9
- data/lib/puppet/parser/functions/lookup.rb +1 -1
- data/lib/puppet/parser/functions/realize.rb +1 -1
- data/lib/puppet/parser/functions/scanf.rb +21 -12
- data/lib/puppet/parser/parser_factory.rb +2 -2
- data/lib/puppet/parser/relationship.rb +1 -1
- data/lib/puppet/parser/scope.rb +34 -7
- data/lib/puppet/pops.rb +2 -0
- data/lib/puppet/pops/binder/lookup.rb +24 -7
- data/lib/puppet/pops/binder/producers.rb +2 -2
- data/lib/puppet/pops/evaluator/closure.rb +1 -1
- data/lib/puppet/pops/evaluator/evaluator_impl.rb +109 -17
- data/lib/puppet/pops/evaluator/puppet_proc.rb +69 -0
- data/lib/puppet/pops/evaluator/runtime3_converter.rb +175 -0
- data/lib/puppet/pops/evaluator/runtime3_support.rb +15 -128
- data/lib/puppet/pops/functions/dispatch.rb +21 -17
- data/lib/puppet/pops/functions/dispatcher.rb +3 -3
- data/lib/puppet/pops/functions/function.rb +46 -14
- data/lib/puppet/pops/issues.rb +2 -2
- data/lib/puppet/pops/model/model_label_provider.rb +1 -1
- data/lib/puppet/pops/parser/egrammar.ra +2 -0
- data/lib/puppet/pops/parser/eparser.rb +732 -724
- data/lib/puppet/pops/parser/heredoc_support.rb +1 -1
- data/lib/puppet/pops/parser/lexer2.rb +20 -22
- data/lib/puppet/pops/types/class_loader.rb +1 -1
- data/lib/puppet/pops/types/type_calculator.rb +104 -37
- data/lib/puppet/pops/types/type_factory.rb +1 -1
- data/lib/puppet/pops/types/types.rb +4 -1
- data/lib/puppet/pops/types/types_meta.rb +2 -2
- data/lib/puppet/pops/validation/checker4_0.rb +5 -3
- data/lib/puppet/provider/service/systemd.rb +1 -0
- data/lib/puppet/provider/yumrepo/inifile.rb +4 -1
- data/lib/puppet/resource.rb +3 -2
- data/lib/puppet/resource/catalog.rb +3 -2
- data/lib/puppet/resource/type.rb +1 -1
- data/lib/puppet/settings/environment_conf.rb +12 -4
- data/lib/puppet/type/package.rb +23 -13
- data/lib/puppet/util/autoload.rb +7 -7
- data/lib/puppet/util/errors.rb +4 -2
- data/lib/puppet/util/network_device/config.rb +5 -0
- data/lib/puppet/version.rb +1 -1
- data/lib/puppetx.rb +2 -2
- data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/callee.rb +8 -0
- data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/lib/puppet/parser/functions/callee_ws.rb +8 -0
- data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/usee/metadata.json +9 -0
- data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/user/lib/puppet/functions/user/caller.rb +5 -0
- data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/user/lib/puppet/functions/user/caller_ws.rb +12 -0
- data/spec/fixtures/unit/pops/loaders/loaders/mix_4x_and_3x_functions/user/metadata.json +9 -0
- data/spec/integration/parser/environment_spec.rb +47 -0
- data/spec/integration/parser/future_compiler_spec.rb +11 -6
- data/spec/unit/application/device_spec.rb +52 -14
- data/spec/unit/daemon_spec.rb +0 -2
- data/spec/unit/environments_spec.rb +2 -2
- data/spec/unit/functions/assert_type_spec.rb +4 -25
- data/spec/unit/functions/hiera_spec.rb +127 -0
- data/spec/unit/functions/with_spec.rb +9 -4
- data/spec/unit/functions4_spec.rb +98 -35
- data/spec/unit/hiera/backend/puppet_backend_spec.rb +1 -1
- data/spec/unit/parser/functions/create_resources_spec.rb +2 -2
- data/spec/unit/parser/functions/defined_spec.rb +5 -0
- data/spec/unit/parser/functions/lookup_spec.rb +5 -1
- data/spec/unit/parser/functions/scanf_spec.rb +30 -0
- data/spec/unit/parser/scope_spec.rb +5 -0
- data/spec/unit/pops/binder/injector_spec.rb +1 -1
- data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +33 -5
- data/spec/unit/pops/loaders/loaders_spec.rb +22 -1
- data/spec/unit/pops/parser/lexer2_spec.rb +28 -16
- data/spec/unit/pops/parser/parse_heredoc_spec.rb +21 -0
- data/spec/unit/pops/types/type_calculator_spec.rb +141 -19
- data/spec/unit/pops/types/type_factory_spec.rb +2 -2
- data/spec/unit/pops/validator/validator_spec.rb +25 -3
- data/spec/unit/provider/service/systemd_spec.rb +20 -4
- data/spec/unit/provider/user/hpux_spec.rb +1 -1
- data/spec/unit/provider/yumrepo/inifile_spec.rb +1 -0
- data/spec/unit/settings/environment_conf_spec.rb +12 -1
- data/spec/unit/type/package_spec.rb +0 -20
- data/spec/unit/util/network_device/config_spec.rb +6 -0
- metadata +3422 -3405
@@ -7,7 +7,7 @@ class Puppet::Parser::Relationship
|
|
7
7
|
# This if statement is needed because the 3x parser cannot load
|
8
8
|
# Puppet::Pops. This logic can be removed for 4.0 when the 3x AST
|
9
9
|
# is removed (when Pops is always used).
|
10
|
-
if !(Puppet
|
10
|
+
if !(Puppet.future_parser?)
|
11
11
|
case resources
|
12
12
|
when Puppet::Parser::Collector
|
13
13
|
resources.collected.values
|
data/lib/puppet/parser/scope.rb
CHANGED
@@ -22,6 +22,9 @@ class Puppet::Parser::Scope
|
|
22
22
|
|
23
23
|
AST = Puppet::Parser::AST
|
24
24
|
|
25
|
+
# Variables that always exist with nil value even if not set
|
26
|
+
BUILT_IN_VARS = ['module_name'.freeze, 'caller_module_name'.freeze].freeze
|
27
|
+
|
25
28
|
Puppet::Util.logmethods(self)
|
26
29
|
|
27
30
|
include Puppet::Util::Errors
|
@@ -181,9 +184,29 @@ class Puppet::Parser::Scope
|
|
181
184
|
|
182
185
|
# Returns true if the variable of the given name is set to any value (including nil)
|
183
186
|
#
|
187
|
+
# @return [Boolean] if variable exists or not
|
188
|
+
#
|
184
189
|
def exist?(name)
|
185
|
-
|
186
|
-
|
190
|
+
# Note !! ensure the answer is boolean
|
191
|
+
!! if name =~ /^(.*)::(.+)$/
|
192
|
+
class_name = $1
|
193
|
+
variable_name = $2
|
194
|
+
return true if class_name == '' && BUILT_IN_VARS.include?(variable_name)
|
195
|
+
|
196
|
+
# lookup class, but do not care if it is not evaluated since that will result
|
197
|
+
# in it not existing anyway. (Tests may run with just scopes and no evaluated classes which
|
198
|
+
# will result in class_scope for "" not returning topscope).
|
199
|
+
klass = find_hostclass(class_name)
|
200
|
+
other_scope = klass.nil? ? nil : class_scope(klass)
|
201
|
+
if other_scope.nil?
|
202
|
+
class_name == '' ? compiler.topscope.exist?(variable_name) : false
|
203
|
+
else
|
204
|
+
other_scope.exist?(variable_name)
|
205
|
+
end
|
206
|
+
else
|
207
|
+
next_scope = inherited_scope || enclosing_scope
|
208
|
+
effective_symtable(true).include?(name) || next_scope && next_scope.exist?(name) || BUILT_IN_VARS.include?(name)
|
209
|
+
end
|
187
210
|
end
|
188
211
|
|
189
212
|
# Returns true if the given name is bound in the current (most nested) scope for assignments.
|
@@ -400,8 +423,12 @@ class Puppet::Parser::Scope
|
|
400
423
|
end
|
401
424
|
|
402
425
|
def variable_not_found(name, reason=nil)
|
426
|
+
# Built in variables always exist
|
427
|
+
if BUILT_IN_VARS.include?(name)
|
428
|
+
return nil
|
429
|
+
end
|
403
430
|
if Puppet[:strict_variables]
|
404
|
-
if Puppet
|
431
|
+
if Puppet.future_parser?
|
405
432
|
throw :undefined_variable
|
406
433
|
else
|
407
434
|
reason_msg = reason.nil? ? '' : "; #{reason}"
|
@@ -534,8 +561,8 @@ class Puppet::Parser::Scope
|
|
534
561
|
#
|
535
562
|
# @see to_hash_legacy
|
536
563
|
def to_hash(recursive = true)
|
537
|
-
@
|
538
|
-
if @
|
564
|
+
@future_parser ||= Puppet.future_parser?
|
565
|
+
if @future_parser
|
539
566
|
to_hash_future(recursive)
|
540
567
|
else
|
541
568
|
to_hash_legacy(recursive)
|
@@ -847,7 +874,7 @@ class Puppet::Parser::Scope
|
|
847
874
|
# lookup in the compiler.
|
848
875
|
#
|
849
876
|
# Makes names passed in the names array absolute if they are relative
|
850
|
-
# Names are now made absolute if Puppet
|
877
|
+
# Names are now made absolute if Puppet.future_parser? is true, this will
|
851
878
|
# be the default behavior in Puppet 4.0
|
852
879
|
#
|
853
880
|
# Transforms Class[] and Resource[] type referenes to class name
|
@@ -860,7 +887,7 @@ class Puppet::Parser::Scope
|
|
860
887
|
# @return [Array<String>] names after transformation
|
861
888
|
#
|
862
889
|
def transform_and_assert_classnames(names)
|
863
|
-
if Puppet
|
890
|
+
if Puppet.future_parser?
|
864
891
|
names.map do |name|
|
865
892
|
case name
|
866
893
|
when String
|
data/lib/puppet/pops.rb
CHANGED
@@ -96,11 +96,13 @@ module Puppet
|
|
96
96
|
|
97
97
|
module Evaluator
|
98
98
|
require 'puppet/pops/evaluator/callable_signature'
|
99
|
+
require 'puppet/pops/evaluator/runtime3_converter'
|
99
100
|
require 'puppet/pops/evaluator/runtime3_support'
|
100
101
|
require 'puppet/pops/evaluator/evaluator_impl'
|
101
102
|
require 'puppet/pops/evaluator/epp_evaluator'
|
102
103
|
require 'puppet/pops/evaluator/callable_mismatch_describer'
|
103
104
|
require 'puppet/pops/evaluator/collector_transformer'
|
105
|
+
require 'puppet/pops/evaluator/puppet_proc'
|
104
106
|
module Collectors
|
105
107
|
require 'puppet/pops/evaluator/collectors/abstract_collector'
|
106
108
|
require 'puppet/pops/evaluator/collectors/fixed_set_collector'
|
@@ -46,14 +46,17 @@ class Puppet::Pops::Binder::Lookup
|
|
46
46
|
names.each {|n| options[n] = undef_as_nil(input[n.to_s] || input[n]) }
|
47
47
|
options
|
48
48
|
end
|
49
|
+
private_class_method :to_symbolic_hash
|
49
50
|
|
50
51
|
def self.type_mismatch(type_calculator, expected, got)
|
51
52
|
"has wrong type, expected #{type_calculator.string(expected)}, got #{type_calculator.string(got)}"
|
52
53
|
end
|
54
|
+
private_class_method :type_mismatch
|
53
55
|
|
54
56
|
def self.fail(msg)
|
55
57
|
raise Puppet::ParseError, "Function lookup() " + msg
|
56
58
|
end
|
59
|
+
private_class_method :fail
|
57
60
|
|
58
61
|
def self.fail_lookup(names)
|
59
62
|
name_part = if names.size == 1
|
@@ -63,6 +66,7 @@ class Puppet::Pops::Binder::Lookup
|
|
63
66
|
end
|
64
67
|
fail("did not find a value for #{name_part}")
|
65
68
|
end
|
69
|
+
private_class_method :fail_lookup
|
66
70
|
|
67
71
|
def self.validate_options(options, type_calculator)
|
68
72
|
type_parser = Puppet::Pops::Types::TypeParser.new
|
@@ -74,7 +78,7 @@ class Puppet::Pops::Binder::Lookup
|
|
74
78
|
|
75
79
|
t = type_calculator.infer(options[:name])
|
76
80
|
if ! type_calculator.assignable?(name_type, t)
|
77
|
-
fail("given 'name' argument, #{type_mismatch(type_calculator,
|
81
|
+
fail("given 'name' argument, #{type_mismatch(type_calculator, name_type, t)}")
|
78
82
|
end
|
79
83
|
|
80
84
|
# unless a type is already given (future case), parse the type (or default 'Data'), fails if invalid type is given
|
@@ -103,18 +107,22 @@ class Puppet::Pops::Binder::Lookup
|
|
103
107
|
options[:override] = {} unless options[:override]
|
104
108
|
|
105
109
|
end
|
110
|
+
private_class_method :validate_options
|
106
111
|
|
107
112
|
def self.nil_as_undef(x)
|
108
113
|
x.nil? ? :undef : x
|
109
114
|
end
|
115
|
+
private_class_method :nil_as_undef
|
110
116
|
|
111
117
|
def self.undef_as_nil(x)
|
112
118
|
is_nil_or_undef?(x) ? nil : x
|
113
119
|
end
|
120
|
+
private_class_method :undef_as_nil
|
114
121
|
|
115
122
|
def self.is_nil_or_undef?(x)
|
116
123
|
x.nil? || x == :undef
|
117
124
|
end
|
125
|
+
private_class_method :is_nil_or_undef?
|
118
126
|
|
119
127
|
# This is used as a marker - a value that cannot (at least not easily) by mistake be found in
|
120
128
|
# hiera data.
|
@@ -128,7 +136,7 @@ class Puppet::Pops::Binder::Lookup
|
|
128
136
|
elsif !(result = scope.compiler.injector.lookup(scope, type, name)).nil?
|
129
137
|
result
|
130
138
|
else
|
131
|
-
result = scope
|
139
|
+
result = call_hiera_function(scope, name, PrivateNotFoundMarker)
|
132
140
|
if !result.nil? && result != PrivateNotFoundMarker
|
133
141
|
result
|
134
142
|
else
|
@@ -136,8 +144,17 @@ class Puppet::Pops::Binder::Lookup
|
|
136
144
|
end
|
137
145
|
end
|
138
146
|
end
|
147
|
+
private_class_method :search_for
|
139
148
|
|
140
|
-
|
149
|
+
def self.call_hiera_function(scope, name, dflt)
|
150
|
+
loader = scope.compiler.loaders.private_environment_loader
|
151
|
+
func = loader.load(:function, :hiera) unless loader.nil?
|
152
|
+
raise Error, 'Function not found: hiera' if func.nil?
|
153
|
+
func.call(scope, name, dflt)
|
154
|
+
end
|
155
|
+
private_class_method :call_hiera_function
|
156
|
+
|
157
|
+
# This is the method called from the puppet/parser/functions/lookup.rb
|
141
158
|
# @param args [Array] array following the puppet function call conventions
|
142
159
|
def self.lookup(scope, args)
|
143
160
|
type_calculator = Puppet::Pops::Types::TypeCalculator.new
|
@@ -166,11 +183,11 @@ class Puppet::Pops::Binder::Lookup
|
|
166
183
|
result = if pblock = options[:pblock]
|
167
184
|
result2 = case pblock.parameter_count
|
168
185
|
when 1
|
169
|
-
pblock.call(
|
186
|
+
pblock.call(undef_as_nil(result))
|
170
187
|
when 2
|
171
|
-
pblock.call(
|
188
|
+
pblock.call(result_with_name[ 0 ], undef_as_nil(result))
|
172
189
|
else
|
173
|
-
pblock.call(
|
190
|
+
pblock.call(result_with_name[ 0 ], undef_as_nil(result), undef_as_nil(options[ :default ]))
|
174
191
|
end
|
175
192
|
|
176
193
|
# if the given result was returned, there is no need to type-check it again
|
@@ -193,7 +210,7 @@ class Puppet::Pops::Binder::Lookup
|
|
193
210
|
# way, and should instead be turned into :undef.
|
194
211
|
# TODO PUPPET4: Simply return the result
|
195
212
|
#
|
196
|
-
Puppet
|
213
|
+
Puppet.future_parser? ? result : nil_as_undef(result)
|
197
214
|
end
|
198
215
|
end
|
199
216
|
end
|
@@ -57,7 +57,7 @@ module Puppet::Pops::Binder::Producers
|
|
57
57
|
def initialize(injector, binding, scope, options)
|
58
58
|
if transformer_lambda = options[:transformer]
|
59
59
|
if transformer_lambda.is_a?(Proc)
|
60
|
-
raise ArgumentError, "Transformer Proc must take
|
60
|
+
raise ArgumentError, "Transformer Proc must take one argument; value." unless transformer_lambda.arity == 1
|
61
61
|
@transformer = transformer_lambda
|
62
62
|
else
|
63
63
|
raise ArgumentError, "Transformer must be a LambdaExpression" unless transformer_lambda.is_a?(Puppet::Pops::Model::LambdaExpression)
|
@@ -110,7 +110,7 @@ module Puppet::Pops::Binder::Producers
|
|
110
110
|
#
|
111
111
|
def do_transformation(scope, produced_value)
|
112
112
|
return produced_value unless transformer
|
113
|
-
transformer.call(
|
113
|
+
transformer.call(produced_value)
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
@@ -29,7 +29,7 @@ class Puppet::Pops::Evaluator::Closure < Puppet::Pops::Evaluator::CallableSignat
|
|
29
29
|
|
30
30
|
# compatible with 3x AST::Lambda
|
31
31
|
# @api public
|
32
|
-
def call(
|
32
|
+
def call(*args)
|
33
33
|
variable_bindings = combine_values_with_parameters(args)
|
34
34
|
|
35
35
|
tc = Puppet::Pops::Types::TypeCalculator
|
@@ -53,9 +53,6 @@ class Puppet::Pops::Evaluator::EvaluatorImpl
|
|
53
53
|
|
54
54
|
@@compare_operator ||= Puppet::Pops::Evaluator::CompareOperator.new()
|
55
55
|
@@relationship_operator ||= Puppet::Pops::Evaluator::RelationshipOperator.new()
|
56
|
-
|
57
|
-
# Initialize the runtime module
|
58
|
-
Puppet::Pops::Evaluator::Runtime3Support.instance_method(:initialize).bind(self).call()
|
59
56
|
end
|
60
57
|
|
61
58
|
# @api private
|
@@ -77,14 +74,43 @@ class Puppet::Pops::Evaluator::EvaluatorImpl
|
|
77
74
|
@@eval_visitor.visit_this_1(self, target, scope)
|
78
75
|
|
79
76
|
rescue Puppet::Pops::SemanticError => e
|
80
|
-
#
|
77
|
+
# A raised issue may not know the semantic target, use errors call stack, but fill in the
|
78
|
+
# rest from a supplied semantic object, or the target instruction if there is not semantic
|
79
|
+
# object.
|
80
|
+
#
|
81
81
|
fail(e.issue, e.semantic || target, e.options, e)
|
82
82
|
|
83
|
-
rescue
|
84
|
-
|
85
|
-
|
83
|
+
rescue Puppet::PreformattedError => e
|
84
|
+
# Already formatted with location information, and with the wanted call stack.
|
85
|
+
# Note this is currently a specialized ParseError, so rescue-order is important
|
86
|
+
#
|
87
|
+
raise e
|
88
|
+
|
89
|
+
rescue Puppet::ParseError => e
|
90
|
+
# ParseError may be raised in ruby code without knowing the location
|
91
|
+
# in puppet code.
|
92
|
+
# Accept a ParseError that has file or line information available
|
93
|
+
# as an error that should be used verbatim. (Tests typically run without
|
94
|
+
# setting a file name).
|
95
|
+
# ParseError can supply an original - it is impossible to determine which
|
96
|
+
# call stack that should be propagated, using the ParseError's backtrace.
|
97
|
+
#
|
98
|
+
if e.file || e.line
|
86
99
|
raise e
|
100
|
+
else
|
101
|
+
# Since it had no location information, treat it as user intended a general purpose
|
102
|
+
# error. Pass on its call stack.
|
103
|
+
fail(Issues::RUNTIME_ERROR, target, {:detail => e.message}, e)
|
87
104
|
end
|
105
|
+
|
106
|
+
|
107
|
+
rescue Puppet::Error => e
|
108
|
+
# PuppetError has the ability to wrap an exception, if so, use the wrapped exception's
|
109
|
+
# call stack instead
|
110
|
+
fail(Issues::RUNTIME_ERROR, target, {:detail => e.message}, e.original || e)
|
111
|
+
|
112
|
+
rescue StandardError => e
|
113
|
+
# All other errors, use its message and call stack
|
88
114
|
fail(Issues::RUNTIME_ERROR, target, {:detail => e.message}, e)
|
89
115
|
end
|
90
116
|
end
|
@@ -238,6 +264,8 @@ class Puppet::Pops::Evaluator::EvaluatorImpl
|
|
238
264
|
def eval_UnfoldExpression(o, scope)
|
239
265
|
candidate = evaluate(o.expr, scope)
|
240
266
|
case candidate
|
267
|
+
when nil
|
268
|
+
[]
|
241
269
|
when Array
|
242
270
|
candidate
|
243
271
|
when Hash
|
@@ -763,12 +791,7 @@ class Puppet::Pops::Evaluator::EvaluatorImpl
|
|
763
791
|
fail(Issues::ILLEGAL_EXPRESSION, o.functor_expr, {:feature=>'function name', :container => o})
|
764
792
|
end
|
765
793
|
name = o.functor_expr.value
|
766
|
-
|
767
|
-
evaluated_arguments = unfold([], o.arguments, scope)
|
768
|
-
|
769
|
-
# wrap lambda in a callable block if it is present
|
770
|
-
evaluated_arguments << Puppet::Pops::Evaluator::Closure.new(self, o.lambda, scope) if o.lambda
|
771
|
-
call_function(name, evaluated_arguments, o, scope)
|
794
|
+
call_function_with_block(name, unfold([], o.arguments, scope), o, scope)
|
772
795
|
end
|
773
796
|
|
774
797
|
# Evaluation of CallMethodExpression handles a NamedAccessExpression functor (receiver.function_name)
|
@@ -783,13 +806,82 @@ class Puppet::Pops::Evaluator::EvaluatorImpl
|
|
783
806
|
fail(Issues::ILLEGAL_EXPRESSION, o.functor_expr, {:feature=>'function name', :container => o})
|
784
807
|
end
|
785
808
|
name = name.value # the string function name
|
809
|
+
call_function_with_block(name, unfold([receiver], o.arguments || [], scope), o, scope)
|
810
|
+
end
|
786
811
|
|
787
|
-
|
812
|
+
def call_function_with_block(name, evaluated_arguments, o, scope)
|
813
|
+
if o.lambda.nil?
|
814
|
+
call_function(name, evaluated_arguments, o, scope)
|
815
|
+
else
|
816
|
+
closure = Puppet::Pops::Evaluator::Closure.new(self, o.lambda, scope)
|
817
|
+
call_function(name, evaluated_arguments, o, scope, &proc_from_closure(closure))
|
818
|
+
end
|
819
|
+
end
|
820
|
+
private :call_function_with_block
|
788
821
|
|
789
|
-
|
790
|
-
|
791
|
-
|
822
|
+
# Creates a Proc with an arity count that matches the parameters of the given closure. The arity will
|
823
|
+
# be correct up to 10 parameters and then default to varargs (-1)
|
824
|
+
#
|
825
|
+
def proc_from_closure(closure)
|
826
|
+
return Puppet::Pops::Evaluator::PuppetProc.new(closure) { |*args| closure.call(*args) } unless RUBY_VERSION[0,3] == '1.8'
|
827
|
+
|
828
|
+
# This code is required since a Proc isn't propagated by reference in Ruby 1.8.x. It produces a standard
|
829
|
+
# Proc that has correct arity as a replacement for the otherwise used PuppetProc
|
830
|
+
# TODO: Remove when Ruby 1.8.x support is dropped
|
831
|
+
arity = closure.parameters.reduce(0) do |memo, param|
|
832
|
+
count = memo + 1
|
833
|
+
break -count if param.captures_rest || !param.value.nil?
|
834
|
+
count
|
835
|
+
end
|
836
|
+
|
837
|
+
case arity
|
838
|
+
when 0
|
839
|
+
proc { || closure.call }
|
840
|
+
when 1
|
841
|
+
proc { |a| closure.call(a) }
|
842
|
+
when 2
|
843
|
+
proc { |a, b| closure.call(a, b) }
|
844
|
+
when 3
|
845
|
+
proc { |a, b, c| closure.call(a, b, c) }
|
846
|
+
when 4
|
847
|
+
proc { |a, b, c, d| closure.call(a, b, c, d) }
|
848
|
+
when 5
|
849
|
+
proc { |a, b, c, d, e| closure.call(a, b, c, d, e) }
|
850
|
+
when 6
|
851
|
+
proc { |a, b, c, d, e, f| closure.call(a, b, c, d, e, f) }
|
852
|
+
when 7
|
853
|
+
proc { |a, b, c, d, e, f, g| closure.call(a, b, c, d, e, f, g) }
|
854
|
+
when 8
|
855
|
+
proc { |a, b, c, d, e, f, g, h| closure.call(a, b, c, d, e, f, g, h) }
|
856
|
+
when 9
|
857
|
+
proc { |a, b, c, d, e, f, g, h, i| closure.call(a, b, c, d, e, f, g, h, i) }
|
858
|
+
when 10
|
859
|
+
proc { |a, b, c, d, e, f, g, h, i, j| closure.call(a, b, c, d, e, f, g, h, i, j) }
|
860
|
+
when -1
|
861
|
+
proc { |*v| closure.call(*v) }
|
862
|
+
when -2
|
863
|
+
proc { |a, *v| closure.call(a, *v) }
|
864
|
+
when -3
|
865
|
+
proc { |a, b, *v| closure.call(a, b, *v) }
|
866
|
+
when -4
|
867
|
+
proc { |a, b, c, *v| closure.call(a, b, c, *v) }
|
868
|
+
when -5
|
869
|
+
proc { |a, b, c, d, *v| closure.call(a, b, c, d, *v) }
|
870
|
+
when -6
|
871
|
+
proc { |a, b, c, d, e, *v| closure.call(a, b, c, d, e, *v) }
|
872
|
+
when -7
|
873
|
+
proc { |a, b, c, d, e, f, *v| closure.call(a, b, c, d, e, f, *v) }
|
874
|
+
when -8
|
875
|
+
proc { |a, b, c, d, e, f, g, *v| closure.call(a, b, c, d, e, f, g, *v) }
|
876
|
+
when -9
|
877
|
+
proc { |a, b, c, d, e, f, g, h, *v| closure.call(a, b, c, d, e, f,g, h, *v) }
|
878
|
+
when -10
|
879
|
+
proc { |a, b, c, d, e, f, g, h, i, *v| closure.call(a, b, c, d, e, f,g, h, i, *v) }
|
880
|
+
else
|
881
|
+
proc { |*a| closure.call(*a) }
|
882
|
+
end
|
792
883
|
end
|
884
|
+
private :proc_from_closure
|
793
885
|
|
794
886
|
# @example
|
795
887
|
# $x ? { 10 => true, 20 => false, default => 0 }
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# Complies with Proc API by mapping a Puppet::Pops::Evaluator::Closure to a ruby Proc.
|
2
|
+
# Creating and passing an instance of this class instead of just a plain block makes
|
3
|
+
# it possible to inherit the parameter info and arity from the closure. Advanced users
|
4
|
+
# may also access the closure itself. The Puppet::Pops::Functions::Dispatcher uses this
|
5
|
+
# when it needs to get the Callable type of the closure.
|
6
|
+
#
|
7
|
+
# The class is part of the Puppet Function API for Ruby and thus public API but a user
|
8
|
+
# should never create an instance of this class.
|
9
|
+
#
|
10
|
+
# @api public
|
11
|
+
class Puppet::Pops::Evaluator::PuppetProc < Proc
|
12
|
+
# Creates a new instance from a closure and a block that will dispatch
|
13
|
+
# all parameters to the closure. The block must be similar to:
|
14
|
+
#
|
15
|
+
# { |*args| closure.call(*args) }
|
16
|
+
#
|
17
|
+
# @param closure [Puppet::Pops::Evaluator::Closure] The closure to map
|
18
|
+
# @param &block [Block] The varargs block that invokes the closure.call method
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
def self.new(closure, &block)
|
22
|
+
proc = super(&block)
|
23
|
+
proc.instance_variable_set(:@closure, closure)
|
24
|
+
proc
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [Puppet::Pops::Evaluator::Closure] the mapped closure
|
28
|
+
# @api public
|
29
|
+
attr_reader :closure
|
30
|
+
|
31
|
+
# @overrides Block.lambda?
|
32
|
+
# @return [Boolean] always false since this proc doesn't do the Ruby lambda magic
|
33
|
+
# @api public
|
34
|
+
def lambda?
|
35
|
+
false
|
36
|
+
end
|
37
|
+
|
38
|
+
# Maps the closure parameters to standard Block parameter info where each
|
39
|
+
# parameter is represented as a two element Array where the first
|
40
|
+
# element is :req, :opt, or :rest and the second element is the name
|
41
|
+
# of the parameter.
|
42
|
+
#
|
43
|
+
# @return [Array<Array<Symbol>>] array of parameter info pairs
|
44
|
+
# @overrides Block.parameters
|
45
|
+
# @api public
|
46
|
+
def parameters
|
47
|
+
@closure.parameters.map do |param|
|
48
|
+
sym = param.name.to_sym
|
49
|
+
if param.captures_rest
|
50
|
+
[ :rest, sym ]
|
51
|
+
elsif param.value
|
52
|
+
[ :opt, sym ]
|
53
|
+
else
|
54
|
+
[ :req, sym ]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# @return [Fixnum] the arity of the block
|
60
|
+
# @overrides Block.arity
|
61
|
+
# @api public
|
62
|
+
def arity
|
63
|
+
parameters.reduce(0) do |memo, param|
|
64
|
+
count = memo + 1
|
65
|
+
break -count unless param[0] == :req
|
66
|
+
count
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|