puppet 3.7.3 → 3.7.4
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.
- data/Gemfile +4 -0
- data/ext/build_defaults.yaml +2 -2
- data/ext/project_data.yaml +2 -2
- data/lib/puppet.rb +1 -1
- data/lib/puppet/configurer.rb +7 -4
- data/lib/puppet/environments.rb +68 -51
- data/lib/puppet/functions/scanf.rb +46 -0
- data/lib/puppet/network/http/webrick/rest.rb +3 -0
- data/lib/puppet/parser/ast/pops_bridge.rb +2 -1
- data/lib/puppet/parser/compiler.rb +11 -3
- data/lib/puppet/parser/functions/realize.rb +7 -2
- data/lib/puppet/parser/functions/scanf.rb +35 -0
- data/lib/puppet/parser/relationship.rb +21 -6
- data/lib/puppet/parser/resource.rb +11 -4
- data/lib/puppet/pops.rb +7 -0
- data/lib/puppet/pops/evaluator/access_operator.rb +1 -6
- data/lib/puppet/pops/evaluator/collector_transformer.rb +219 -0
- data/lib/puppet/pops/evaluator/collectors/abstract_collector.rb +86 -0
- data/lib/puppet/pops/evaluator/collectors/catalog_collector.rb +25 -0
- data/lib/puppet/pops/evaluator/collectors/exported_collector.rb +66 -0
- data/lib/puppet/pops/evaluator/collectors/fixed_set_collector.rb +37 -0
- data/lib/puppet/pops/evaluator/compare_operator.rb +8 -28
- data/lib/puppet/pops/evaluator/evaluator_impl.rb +4 -18
- data/lib/puppet/pops/evaluator/relationship_operator.rb +4 -0
- data/lib/puppet/pops/evaluator/runtime3_support.rb +2 -2
- data/lib/puppet/pops/parser/egrammar.ra +3 -3
- data/lib/puppet/pops/parser/eparser.rb +3 -3
- data/lib/puppet/pops/parser/evaluating_parser.rb +4 -0
- data/lib/puppet/pops/types/type_calculator.rb +19 -8
- data/lib/puppet/pops/types/type_parser.rb +1 -4
- data/lib/puppet/provider/service/redhat.rb +6 -3
- data/lib/puppet/resource/catalog.rb +12 -1
- data/lib/puppet/settings/environment_conf.rb +7 -8
- data/lib/puppet/type/cron.rb +5 -1
- data/lib/puppet/type/file/content.rb +1 -1
- data/lib/puppet/util/tagging.rb +21 -2
- data/lib/puppet/version.rb +1 -1
- data/spec/integration/indirector/catalog/compiler_spec.rb +11 -0
- data/spec/integration/parser/collector_spec.rb +41 -0
- data/spec/integration/parser/compiler_spec.rb +16 -0
- data/spec/integration/parser/future_compiler_spec.rb +1 -1
- data/spec/unit/environments_spec.rb +238 -118
- data/spec/unit/functions/scanf_spec.rb +36 -0
- data/spec/unit/network/http/rack/rest_spec.rb +11 -8
- data/spec/unit/network/http/webrick/rest_spec.rb +19 -0
- data/spec/unit/parser/compiler_spec.rb +0 -27
- data/spec/unit/pops/evaluator/access_ops_spec.rb +9 -9
- data/spec/unit/pops/evaluator/comparison_ops_spec.rb +14 -8
- data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +20 -8
- data/spec/unit/pops/parser/parse_basic_expressions_spec.rb +10 -0
- data/spec/unit/pops/parser/parse_heredoc_spec.rb +30 -0
- data/spec/unit/pops/types/type_calculator_spec.rb +18 -0
- data/spec/unit/pops/types/type_parser_spec.rb +2 -2
- data/spec/unit/provider/service/redhat_spec.rb +2 -1
- data/spec/unit/type/cron_spec.rb +24 -24
- data/spec/unit/util/tagging_spec.rb +7 -0
- metadata +11 -2
data/Gemfile
CHANGED
@@ -60,6 +60,10 @@ end
|
|
60
60
|
group(:extra) do
|
61
61
|
gem "rack", "~> 1.4", :require => false
|
62
62
|
gem "activerecord", '~> 3.2', :require => false
|
63
|
+
# this pin for i18n should *not* be in the puppet-4+ branches
|
64
|
+
# it's solely here because activerecord pulls in i18n and i18n
|
65
|
+
# was recently updated to require 1.9.3 which breaks 1.8.7 specs
|
66
|
+
gem "i18n", '~> 0.6.11', :require => false
|
63
67
|
gem "couchrest", '~> 1.0', :require => false
|
64
68
|
gem "net-ssh", '~> 2.1', :require => false
|
65
69
|
gem "puppetlabs_spec_helper", :require => false
|
data/ext/build_defaults.yaml
CHANGED
@@ -26,8 +26,8 @@ build_msi:
|
|
26
26
|
repo: 'git://github.com/puppetlabs/hiera.git'
|
27
27
|
sys:
|
28
28
|
ref:
|
29
|
-
x86: '
|
30
|
-
x64: '
|
29
|
+
x86: '57068e7b7c87288c51ff39d96c80cfb509a42091'
|
30
|
+
x64: '531319f5c121e98990772e018eb9781bf7dc6316'
|
31
31
|
repo: 'git://github.com/puppetlabs/puppet-win32-ruby.git'
|
32
32
|
apt_host: 'apt.puppetlabs.com'
|
33
33
|
apt_repo_url: 'http://apt.puppetlabs.com'
|
data/ext/project_data.yaml
CHANGED
@@ -28,7 +28,7 @@ gem_platform_dependencies:
|
|
28
28
|
x86-mingw32:
|
29
29
|
gem_runtime_dependencies:
|
30
30
|
# Pinning versions that require native extensions
|
31
|
-
ffi: '1.9.
|
31
|
+
ffi: '~> 1.9.5'
|
32
32
|
win32-dir: '~> 0.4.9'
|
33
33
|
win32-eventlog: '~> 0.6.1'
|
34
34
|
win32-process: '~> 0.7.4'
|
@@ -38,7 +38,7 @@ gem_platform_dependencies:
|
|
38
38
|
minitar: '~> 0.5.4'
|
39
39
|
x64-mingw32:
|
40
40
|
gem_runtime_dependencies:
|
41
|
-
ffi: '1.9.
|
41
|
+
ffi: '~> 1.9.5'
|
42
42
|
win32-dir: '~> 0.4.9'
|
43
43
|
win32-eventlog: '~> 0.6.1'
|
44
44
|
win32-process: '~> 0.7.4'
|
data/lib/puppet.rb
CHANGED
@@ -197,7 +197,7 @@ module Puppet
|
|
197
197
|
end
|
198
198
|
|
199
199
|
{
|
200
|
-
:environments => Puppet::Environments::Cached.new(*loaders),
|
200
|
+
:environments => Puppet::Environments::Cached.new(Puppet::Environments::Combined.new(*loaders)),
|
201
201
|
:http_pool => proc {
|
202
202
|
require 'puppet/network/http'
|
203
203
|
Puppet::Network::HTTP::NoCachePool.new
|
data/lib/puppet/configurer.rb
CHANGED
@@ -87,14 +87,16 @@ class Puppet::Configurer
|
|
87
87
|
download_plugins(remote_environment_for_plugins)
|
88
88
|
end
|
89
89
|
|
90
|
+
facts_hash = {}
|
90
91
|
if Puppet::Resource::Catalog.indirection.terminus_class == :rest
|
91
92
|
# This is a bit complicated. We need the serialized and escaped facts,
|
92
93
|
# and we need to know which format they're encoded in. Thus, we
|
93
94
|
# get a hash with both of these pieces of information.
|
94
95
|
#
|
95
96
|
# facts_for_uploading may set Puppet[:node_name_value] as a side effect
|
96
|
-
|
97
|
+
facts_hash = facts_for_uploading
|
97
98
|
end
|
99
|
+
facts_hash
|
98
100
|
end
|
99
101
|
|
100
102
|
def prepare_and_retrieve_catalog(options, query_options)
|
@@ -195,9 +197,6 @@ class Puppet::Configurer
|
|
195
197
|
Puppet.push_context({:current_environment => local_node_environment}, "Local node environment for configurer transaction")
|
196
198
|
|
197
199
|
query_options = get_facts(options) unless query_options
|
198
|
-
|
199
|
-
# get_facts returns nil during puppet apply
|
200
|
-
query_options ||= {}
|
201
200
|
query_options[:transaction_uuid] = @transaction_uuid
|
202
201
|
|
203
202
|
unless catalog = prepare_and_retrieve_catalog(options, query_options)
|
@@ -216,6 +215,10 @@ class Puppet::Configurer
|
|
216
215
|
Puppet.warning "Local environment: \"#{@environment}\" doesn't match server specified environment \"#{catalog.environment}\", restarting agent run with environment \"#{catalog.environment}\""
|
217
216
|
@environment = catalog.environment
|
218
217
|
report.environment = @environment
|
218
|
+
|
219
|
+
query_options = get_facts(options)
|
220
|
+
query_options[:transaction_uuid] = @transaction_uuid
|
221
|
+
|
219
222
|
return nil unless catalog = prepare_and_retrieve_catalog(options, query_options)
|
220
223
|
tries += 1
|
221
224
|
end
|
data/lib/puppet/environments.rb
CHANGED
@@ -25,6 +25,21 @@ module Puppet::Environments
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
+
# Provide any common methods that loaders should have. It requires that any
|
29
|
+
# classes that include this module implement get
|
30
|
+
# @api private
|
31
|
+
module EnvironmentLoader
|
32
|
+
# @!macro loader_get_or_fail
|
33
|
+
def get!(name)
|
34
|
+
environment = get(name)
|
35
|
+
if environment
|
36
|
+
environment
|
37
|
+
else
|
38
|
+
raise EnvironmentNotFound, name
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
28
43
|
# @!macro [new] loader_search_paths
|
29
44
|
# A list of indicators of where the loader is getting its environments from.
|
30
45
|
# @return [Array<String>] The URIs of the load locations
|
@@ -62,6 +77,7 @@ module Puppet::Environments
|
|
62
77
|
# @api private
|
63
78
|
class Static
|
64
79
|
include EnvironmentCreator
|
80
|
+
include EnvironmentLoader
|
65
81
|
|
66
82
|
def initialize(*environments)
|
67
83
|
@environments = environments
|
@@ -84,14 +100,6 @@ module Puppet::Environments
|
|
84
100
|
end
|
85
101
|
end
|
86
102
|
|
87
|
-
# @!macro loader_get_or_fail
|
88
|
-
def get!(name)
|
89
|
-
if !environment = get(name)
|
90
|
-
raise EnvironmentNotFound, name
|
91
|
-
end
|
92
|
-
environment
|
93
|
-
end
|
94
|
-
|
95
103
|
# Returns a basic environment configuration object tied to the environment's
|
96
104
|
# implementation values. Will not interpolate.
|
97
105
|
#
|
@@ -186,6 +194,8 @@ module Puppet::Environments
|
|
186
194
|
#
|
187
195
|
# @api private
|
188
196
|
class Directories
|
197
|
+
include EnvironmentLoader
|
198
|
+
|
189
199
|
def initialize(environment_dir, global_module_path)
|
190
200
|
@environment_dir = environment_dir
|
191
201
|
@global_module_path = global_module_path
|
@@ -212,51 +222,49 @@ module Puppet::Environments
|
|
212
222
|
def list
|
213
223
|
valid_directories.collect do |envdir|
|
214
224
|
name = Puppet::FileSystem.basename_string(envdir).intern
|
215
|
-
|
216
|
-
setting_values = Puppet.settings.values(name, Puppet.settings.preferred_run_mode)
|
217
|
-
env = Puppet::Node::Environment.create(
|
218
|
-
name,
|
219
|
-
Puppet::Node::Environment.split_path(setting_values.interpolate(:modulepath)),
|
220
|
-
setting_values.interpolate(:manifest),
|
221
|
-
setting_values.interpolate(:config_version)
|
222
|
-
)
|
223
|
-
env.watching = false
|
224
|
-
env
|
225
|
+
create_environment(name)
|
225
226
|
end
|
226
227
|
end
|
227
228
|
|
228
229
|
# @!macro loader_get
|
229
230
|
def get(name)
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
# @!macro loader_get_or_fail
|
234
|
-
def get!(name)
|
235
|
-
if !environment = get(name)
|
236
|
-
raise EnvironmentNotFound, name
|
231
|
+
if valid_directory?(File.join(@environment_dir, name.to_s))
|
232
|
+
create_environment(name)
|
237
233
|
end
|
238
|
-
environment
|
239
234
|
end
|
240
235
|
|
241
236
|
# @!macro loader_get_conf
|
242
237
|
def get_conf(name)
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
return Puppet::Settings::EnvironmentConf.load_from(envdir, @global_module_path)
|
247
|
-
end
|
238
|
+
envdir = File.join(@environment_dir, name.to_s)
|
239
|
+
if valid_directory?(envdir)
|
240
|
+
return Puppet::Settings::EnvironmentConf.load_from(envdir, @global_module_path)
|
248
241
|
end
|
249
242
|
nil
|
250
243
|
end
|
251
244
|
|
252
245
|
private
|
253
246
|
|
247
|
+
def create_environment(name, setting_values = nil)
|
248
|
+
env_symbol = name.intern
|
249
|
+
setting_values = Puppet.settings.values(env_symbol, Puppet.settings.preferred_run_mode)
|
250
|
+
Puppet::Node::Environment.create(
|
251
|
+
env_symbol,
|
252
|
+
Puppet::Node::Environment.split_path(setting_values.interpolate(:modulepath)),
|
253
|
+
setting_values.interpolate(:manifest),
|
254
|
+
setting_values.interpolate(:config_version)
|
255
|
+
)
|
256
|
+
end
|
257
|
+
|
258
|
+
def valid_directory?(envdir)
|
259
|
+
name = Puppet::FileSystem.basename_string(envdir)
|
260
|
+
Puppet::FileSystem.directory?(envdir) &&
|
261
|
+
Puppet::Node::Environment.valid_name?(name)
|
262
|
+
end
|
263
|
+
|
254
264
|
def valid_directories
|
255
265
|
if Puppet::FileSystem.directory?(@environment_dir)
|
256
266
|
Puppet::FileSystem.children(@environment_dir).select do |child|
|
257
|
-
|
258
|
-
Puppet::FileSystem.directory?(child) &&
|
259
|
-
Puppet::Node::Environment.valid_name?(name)
|
267
|
+
valid_directory?(child)
|
260
268
|
end
|
261
269
|
else
|
262
270
|
[]
|
@@ -267,6 +275,8 @@ module Puppet::Environments
|
|
267
275
|
# Combine together multiple loaders to act as one.
|
268
276
|
# @api private
|
269
277
|
class Combined
|
278
|
+
include EnvironmentLoader
|
279
|
+
|
270
280
|
def initialize(*loaders)
|
271
281
|
@loaders = loaders
|
272
282
|
end
|
@@ -291,16 +301,6 @@ module Puppet::Environments
|
|
291
301
|
nil
|
292
302
|
end
|
293
303
|
|
294
|
-
# @!macro loader_get_or_fail
|
295
|
-
def get!(name)
|
296
|
-
@loaders.each do |loader|
|
297
|
-
if env = loader.get(name)
|
298
|
-
return env
|
299
|
-
end
|
300
|
-
end
|
301
|
-
raise EnvironmentNotFound, name
|
302
|
-
end
|
303
|
-
|
304
304
|
# @!macro loader_get_conf
|
305
305
|
def get_conf(name)
|
306
306
|
@loaders.each do |loader|
|
@@ -313,7 +313,9 @@ module Puppet::Environments
|
|
313
313
|
|
314
314
|
end
|
315
315
|
|
316
|
-
class Cached
|
316
|
+
class Cached
|
317
|
+
include EnvironmentLoader
|
318
|
+
|
317
319
|
INFINITY = 1.0 / 0.0
|
318
320
|
|
319
321
|
class DefaultCacheExpirationService
|
@@ -336,17 +338,28 @@ module Puppet::Environments
|
|
336
338
|
@cache_expiration_service || DefaultCacheExpirationService.new
|
337
339
|
end
|
338
340
|
|
339
|
-
def initialize(
|
340
|
-
|
341
|
+
def initialize(loader)
|
342
|
+
@loader = loader
|
341
343
|
@cache = {}
|
342
344
|
@cache_expiration_service = Puppet::Environments::Cached.cache_expiration_service
|
343
345
|
end
|
344
346
|
|
347
|
+
# @!macro loader_list
|
348
|
+
def list
|
349
|
+
@loader.list
|
350
|
+
end
|
351
|
+
|
352
|
+
# @!macro loader_search_paths
|
353
|
+
def search_paths
|
354
|
+
@loader.search_paths
|
355
|
+
end
|
356
|
+
|
357
|
+
# @!macro loader_get
|
345
358
|
def get(name)
|
346
359
|
evict_if_expired(name)
|
347
360
|
if result = @cache[name]
|
348
361
|
return result.value
|
349
|
-
elsif (result =
|
362
|
+
elsif (result = @loader.get(name))
|
350
363
|
@cache[name] = entry(result)
|
351
364
|
result
|
352
365
|
end
|
@@ -364,13 +377,17 @@ module Puppet::Environments
|
|
364
377
|
@cache = {}
|
365
378
|
end
|
366
379
|
|
367
|
-
# This implementation evicts the cache, and always gets the current
|
368
|
-
#
|
380
|
+
# This implementation evicts the cache, and always gets the current
|
381
|
+
# configuration of the environment
|
382
|
+
#
|
383
|
+
# TODO: While this is wasteful since it
|
384
|
+
# needs to go on a search for the conf, it is too disruptive to optimize
|
369
385
|
# this.
|
370
386
|
#
|
387
|
+
# @!macro loader_get_conf
|
371
388
|
def get_conf(name)
|
372
389
|
evict_if_expired(name)
|
373
|
-
|
390
|
+
@loader.get_conf(name)
|
374
391
|
end
|
375
392
|
|
376
393
|
# Creates a suitable cache entry given the time to live for one environment
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# Scans a string and returns an array of one or more converted values as directed by a given format string.args
|
2
|
+
# See the documenation of Ruby's String::scanf method for details about the supported formats (which
|
3
|
+
# are similar but not identical to the formats used in Puppet's `sprintf` function.
|
4
|
+
#
|
5
|
+
# This function takes two mandatory arguments: the first is the String to convert, and the second
|
6
|
+
# the format String. A parameterized block may optionally be given, which is called with the result
|
7
|
+
# that is produced by scanf if no block is present, the result of the block is then returned by
|
8
|
+
# the function.
|
9
|
+
#
|
10
|
+
# The result of the scan is an Array, with each sucessfully scanned and transformed value.args The scanning
|
11
|
+
# stops if a scan is unsuccesful and the scanned result up to that point is returned. If there was no
|
12
|
+
# succesful scan at all, the result is an empty Array. The optional code block is typically used to
|
13
|
+
# assert that the scan was succesful, and either produce the same input, or perform unwrapping of
|
14
|
+
# the result
|
15
|
+
#
|
16
|
+
# @example scanning an integer in string form (result is an array with
|
17
|
+
# integer, or empty if unsuccessful)
|
18
|
+
# "42".scanf("%i")
|
19
|
+
#
|
20
|
+
# @example scanning and processing resulting array to assert result and unwrap
|
21
|
+
#
|
22
|
+
# "42".scanf("%i") |$x| {
|
23
|
+
# unless $x[0] =~ Integer {
|
24
|
+
# fail "Expected a well formed integer value, got '$x[0]'"
|
25
|
+
# }
|
26
|
+
# $x[0]
|
27
|
+
# }
|
28
|
+
#
|
29
|
+
# @since 3.7.4
|
30
|
+
Puppet::Functions.create_function(:scanf) do
|
31
|
+
require 'scanf'
|
32
|
+
|
33
|
+
dispatch :scanf do
|
34
|
+
param 'String', 'data'
|
35
|
+
param 'String', 'format'
|
36
|
+
optional_block_param
|
37
|
+
end
|
38
|
+
|
39
|
+
def scanf(data, format, block=nil)
|
40
|
+
result = data.scanf(format)
|
41
|
+
if !block.nil?
|
42
|
+
result = block.call({}, result)
|
43
|
+
end
|
44
|
+
result
|
45
|
+
end
|
46
|
+
end
|
@@ -79,6 +79,9 @@ class Puppet::Network::HTTP::WEBrickREST < WEBrick::HTTPServlet::AbstractServlet
|
|
79
79
|
response.body = result
|
80
80
|
response["content-length"] = result.stat.size if result.is_a?(File)
|
81
81
|
end
|
82
|
+
if RUBY_VERSION[0,3] == "1.8"
|
83
|
+
response["connection"] = 'close'
|
84
|
+
end
|
82
85
|
end
|
83
86
|
|
84
87
|
# Retrieve node/cert/ip information from the request object.
|
@@ -24,7 +24,8 @@ class Puppet::Parser::AST::PopsBridge
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def evaluate(scope)
|
27
|
-
@@evaluator.evaluate(scope, @value)
|
27
|
+
object = @@evaluator.evaluate(scope, @value)
|
28
|
+
@@evaluator.convert_to_3x(object, scope)
|
28
29
|
end
|
29
30
|
|
30
31
|
# Adapts to 3x where top level constructs needs to have each to iterate over children. Short circuit this
|
@@ -31,7 +31,7 @@ class Puppet::Parser::Compiler
|
|
31
31
|
raise(Puppet::Error, errmsg.join(' '))
|
32
32
|
end
|
33
33
|
|
34
|
-
new(node).compile.to_resource
|
34
|
+
new(node).compile {|resulting_catalog| resulting_catalog.to_resource }
|
35
35
|
rescue => detail
|
36
36
|
message = "#{detail} on node #{node.name}"
|
37
37
|
Puppet.log_exception(detail, message)
|
@@ -140,7 +140,11 @@ class Puppet::Parser::Compiler
|
|
140
140
|
|
141
141
|
fail_on_unevaluated
|
142
142
|
|
143
|
-
|
143
|
+
if block_given?
|
144
|
+
yield @catalog
|
145
|
+
else
|
146
|
+
@catalog
|
147
|
+
end
|
144
148
|
end
|
145
149
|
end
|
146
150
|
|
@@ -443,7 +447,11 @@ class Puppet::Parser::Compiler
|
|
443
447
|
# look for resources, because we want to consider those to be
|
444
448
|
# parse errors.
|
445
449
|
def fail_on_unevaluated_resource_collections
|
446
|
-
|
450
|
+
if Puppet[:parser] == 'future'
|
451
|
+
remaining = @collections.collect(&:unresolved_resources).flatten.compact
|
452
|
+
else
|
453
|
+
remaining = @collections.collect(&:resources).flatten.compact
|
454
|
+
end
|
447
455
|
|
448
456
|
if !remaining.empty?
|
449
457
|
raise Puppet::ParseError, "Failed to realize virtual resources #{remaining.join(', ')}"
|
@@ -6,9 +6,14 @@ Puppet::Parser::Functions::newfunction(:realize, :arity => -2, :doc => "Make a v
|
|
6
6
|
bother with a full collection. It is slightly faster than a collection,
|
7
7
|
and, of course, is a bit shorter. You must pass the object using a
|
8
8
|
reference; e.g.: `realize User[luke]`." ) do |vals|
|
9
|
-
|
9
|
+
|
10
10
|
vals = [vals] unless vals.is_a?(Array)
|
11
|
-
|
11
|
+
if Puppet[:parser] == 'future'
|
12
|
+
coll = Puppet::Pops::Evaluator::Collectors::FixedSetCollector.new(self, vals.flatten)
|
13
|
+
else
|
14
|
+
coll = Puppet::Parser::Collector.new(self, :nomatter, nil, nil, :virtual)
|
15
|
+
coll.resources = vals.flatten
|
16
|
+
end
|
12
17
|
|
13
18
|
compiler.add_collection(coll)
|
14
19
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
Puppet::Parser::Functions::newfunction(
|
2
|
+
:scanf,
|
3
|
+
:type => :rvalue,
|
4
|
+
:arity => 2,
|
5
|
+
:doc => <<-DOC
|
6
|
+
Scans a string and returns an array of one or more converted values as directed by a given format string.args
|
7
|
+
See the documenation of Ruby's String::scanf method for details about the supported formats (which
|
8
|
+
are similar but not identical to the formats used in Puppet's `sprintf` function.
|
9
|
+
|
10
|
+
This function takes two mandatory arguments: the first is the String to convert, and the second
|
11
|
+
the format String. A parameterized block may optionally be given, which is called with the result
|
12
|
+
that is produced by scanf if no block is present, the result of the block is then returned by
|
13
|
+
the function.
|
14
|
+
|
15
|
+
The result of the scan is an Array, with each sucessfully scanned and transformed value.args The scanning
|
16
|
+
stops if a scan is unsuccesful and the scanned result up to that point is returned. If there was no
|
17
|
+
succesful scan at all, the result is an empty Array. The optional code block is typically used to
|
18
|
+
assert that the scan was succesful, and either produce the same input, or perform unwrapping of
|
19
|
+
the result
|
20
|
+
|
21
|
+
|
22
|
+
"42".scanf("%i")
|
23
|
+
"42".scanf("%i") |$x| {
|
24
|
+
unless $x[0] =~ Integer {
|
25
|
+
fail "Expected a well formed integer value, got '$x[0]'"
|
26
|
+
}
|
27
|
+
$x[0]
|
28
|
+
}
|
29
|
+
|
30
|
+
- since 3.7.4
|
31
|
+
- note requires `parser = future`
|
32
|
+
DOC
|
33
|
+
) do |args|
|
34
|
+
function_fail(["scanf() is only available when parser/evaluator future is in effect"])
|
35
|
+
end
|