compat_resource 12.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,32 @@
1
+ require 'chef_compat/copied_from_chef'
2
+ module ChefCompat
3
+ module CopiedFromChef
4
+ #
5
+ # Author:: John Keiser <jkeiser@chef.io>
6
+ # Copyright:: Copyright (c) 2015 Opscode, Inc.
7
+ # License:: Apache License, Version 2.0
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+
21
+ class Chef < (defined?(::Chef) ? ::Chef : Object)
22
+ NOT_PASSED = Object.new
23
+ def NOT_PASSED.to_s
24
+ "NOT_PASSED"
25
+ end
26
+ def NOT_PASSED.inspect
27
+ to_s
28
+ end
29
+ NOT_PASSED.freeze
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,26 @@
1
+ require 'chef_compat/copied_from_chef'
2
+ module ChefCompat
3
+ module CopiedFromChef
4
+ #
5
+ # Author:: John Keiser <jkeiser@chef.io>
6
+ # Copyright:: Copyright (c) 2015 Opscode, Inc.
7
+ # License:: Apache License, Version 2.0
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+
21
+ class Chef < (defined?(::Chef) ? ::Chef : Object)
22
+ class DelayedEvaluator < (defined?(::Chef::DelayedEvaluator) ? ::Chef::DelayedEvaluator : Proc)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,8 @@
1
+ require 'chef_compat/copied_from_chef'
2
+ module ChefCompat
3
+ module CopiedFromChef
4
+ class Chef < (defined?(::Chef) ? ::Chef : Object)
5
+ end
6
+ require 'chef_compat/copied_from_chef/chef/resource'
7
+ end
8
+ end
@@ -0,0 +1,484 @@
1
+ require 'chef_compat/copied_from_chef'
2
+ module ChefCompat
3
+ module CopiedFromChef
4
+ #
5
+ # Author:: Adam Jacob (<adam@opscode.com>)
6
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
7
+ # License:: Apache License, Version 2.0
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+
21
+ require 'chef_compat/copied_from_chef/chef/constants'
22
+ require 'chef_compat/copied_from_chef/chef/property'
23
+ require 'chef_compat/copied_from_chef/chef/delayed_evaluator'
24
+
25
+ class Chef < (defined?(::Chef) ? ::Chef : Object)
26
+ module Mixin
27
+ if defined?(::Chef::Mixin)
28
+ require 'chef_compat/delegating_class'
29
+ extend DelegatingClass
30
+ @delegates_to = ::Chef::Mixin
31
+ end
32
+ module ParamsValidate
33
+ if defined?(::Chef::Mixin::ParamsValidate)
34
+ require 'chef_compat/delegating_class'
35
+ extend DelegatingClass
36
+ @delegates_to = ::Chef::Mixin::ParamsValidate
37
+ end
38
+
39
+ # Takes a hash of options, along with a map to validate them. Returns the original
40
+ # options hash, plus any changes that might have been made (through things like setting
41
+ # default values in the validation map)
42
+ #
43
+ # For example:
44
+ #
45
+ # validate({ :one => "neat" }, { :one => { :kind_of => String }})
46
+ #
47
+ # Would raise an exception if the value of :one above is not a kind_of? string. Valid
48
+ # map options are:
49
+ #
50
+ # @param opts [Hash<Symbol,Object>] Validation opts.
51
+ # @option opts [Object,Array] :is An object, or list of
52
+ # objects, that must match the value using Ruby's `===` operator
53
+ # (`opts[:is].any? { |v| v === value }`). (See #_pv_is.)
54
+ # @option opts [Object,Array] :equal_to An object, or list
55
+ # of objects, that must be equal to the value using Ruby's `==`
56
+ # operator (`opts[:is].any? { |v| v == value }`) (See #_pv_equal_to.)
57
+ # @option opts [Regexp,Array<Regexp>] :regex An object, or
58
+ # list of objects, that must match the value with `regex.match(value)`.
59
+ # (See #_pv_regex)
60
+ # @option opts [Class,Array<Class>] :kind_of A class, or
61
+ # list of classes, that the value must be an instance of. (See
62
+ # #_pv_kind_of.)
63
+ # @option opts [Hash<String,Proc>] :callbacks A hash of
64
+ # messages -> procs, all of which match the value. The proc must
65
+ # return a truthy or falsey value (true means it matches). (See
66
+ # #_pv_callbacks.)
67
+ # @option opts [Symbol,Array<Symbol>] :respond_to A method
68
+ # name, or list of method names, the value must respond to. (See
69
+ # #_pv_respond_to.)
70
+ # @option opts [Symbol,Array<Symbol>] :cannot_be A property,
71
+ # or a list of properties, that the value cannot have (such as `:nil` or
72
+ # `:empty`). The method with a questionmark at the end is called on the
73
+ # value (e.g. `value.empty?`). If the value does not have this method,
74
+ # it is considered valid (i.e. if you don't respond to `empty?` we
75
+ # assume you are not empty). (See #_pv_cannot_be.)
76
+ # @option opts [Proc] :coerce A proc which will be called to
77
+ # transform the user input to canonical form. The value is passed in,
78
+ # and the transformed value returned as output. Lazy values will *not*
79
+ # be passed to this method until after they are evaluated. Called in the
80
+ # context of the resource (meaning you can access other properties).
81
+ # (See #_pv_coerce.) (See #_pv_coerce.)
82
+ # @option opts [Boolean] :required `true` if this property
83
+ # must be present and not `nil`; `false` otherwise. This is checked
84
+ # after the resource is fully initialized. (See #_pv_required.)
85
+ # @option opts [Boolean] :name_property `true` if this
86
+ # property defaults to the same value as `name`. Equivalent to
87
+ # `default: lazy { name }`, except that #property_is_set? will
88
+ # return `true` if the property is set *or* if `name` is set. (See
89
+ # #_pv_name_property.)
90
+ # @option opts [Boolean] :name_attribute Same as `name_property`.
91
+ # @option opts [Object] :default The value this property
92
+ # will return if the user does not set one. If this is `lazy`, it will
93
+ # be run in the context of the instance (and able to access other
94
+ # properties). (See #_pv_default.)
95
+ #
96
+ def validate(opts, map)
97
+ map = map.validation_options if map.is_a?(Property)
98
+
99
+ #--
100
+ # validate works by taking the keys in the validation map, assuming it's a hash, and
101
+ # looking for _pv_:symbol as methods. Assuming it find them, it calls the right
102
+ # one.
103
+ #++
104
+ raise ArgumentError, "Options must be a hash" unless opts.kind_of?(Hash)
105
+ raise ArgumentError, "Validation Map must be a hash" unless map.kind_of?(Hash)
106
+
107
+ map.each do |key, validation|
108
+ unless key.kind_of?(Symbol) || key.kind_of?(String)
109
+ raise ArgumentError, "Validation map keys must be symbols or strings!"
110
+ end
111
+ case validation
112
+ when true
113
+ _pv_required(opts, key)
114
+ when false
115
+ true
116
+ when Hash
117
+ validation.each do |check, carg|
118
+ check_method = "_pv_#{check}"
119
+ if self.respond_to?(check_method, true)
120
+ self.send(check_method, opts, key, carg)
121
+ else
122
+ raise ArgumentError, "Validation map has unknown check: #{check}"
123
+ end
124
+ end
125
+ end
126
+ end
127
+ opts
128
+ end
129
+
130
+ def lazy(&block)
131
+ DelayedEvaluator.new(&block)
132
+ end
133
+
134
+ def set_or_return(symbol, value, validation)
135
+ property = SetOrReturnProperty.new(name: symbol, **validation)
136
+ property.call(self, value)
137
+ end
138
+
139
+ private
140
+
141
+ def explicitly_allows_nil?(key, validation)
142
+ validation.has_key?(:is) && _pv_is({ key => nil }, key, validation[:is], raise_error: false)
143
+ end
144
+
145
+ # Return the value of a parameter, or nil if it doesn't exist.
146
+ def _pv_opts_lookup(opts, key)
147
+ if opts.has_key?(key.to_s)
148
+ opts[key.to_s]
149
+ elsif opts.has_key?(key.to_sym)
150
+ opts[key.to_sym]
151
+ else
152
+ nil
153
+ end
154
+ end
155
+
156
+ # Raise an exception if the parameter is not found.
157
+ def _pv_required(opts, key, is_required=true, explicitly_allows_nil=false)
158
+ if is_required
159
+ return true if opts.has_key?(key.to_s) && (explicitly_allows_nil || !opts[key.to_s].nil?)
160
+ return true if opts.has_key?(key.to_sym) && (explicitly_allows_nil || !opts[key.to_sym].nil?)
161
+ raise Exceptions::ValidationFailed, "Required argument #{key.inspect} is missing!"
162
+ end
163
+ true
164
+ end
165
+
166
+ #
167
+ # List of things values must be equal to.
168
+ #
169
+ # Uses Ruby's `==` to evaluate (equal_to == value). At least one must
170
+ # match for the value to be valid.
171
+ #
172
+ # `nil` passes this validation automatically.
173
+ #
174
+ # @return [Array,nil] List of things values must be equal to, or nil if
175
+ # equal_to is unspecified.
176
+ #
177
+ def _pv_equal_to(opts, key, to_be)
178
+ value = _pv_opts_lookup(opts, key)
179
+ unless value.nil?
180
+ to_be = Array(to_be)
181
+ to_be.each do |tb|
182
+ return true if value == tb
183
+ end
184
+ raise Exceptions::ValidationFailed, "Option #{key} must be equal to one of: #{to_be.join(", ")}! You passed #{value.inspect}."
185
+ end
186
+ end
187
+
188
+ #
189
+ # List of things values must be instances of.
190
+ #
191
+ # Uses value.kind_of?(kind_of) to evaluate. At least one must match for
192
+ # the value to be valid.
193
+ #
194
+ # `nil` automatically passes this validation.
195
+ #
196
+ def _pv_kind_of(opts, key, to_be)
197
+ value = _pv_opts_lookup(opts, key)
198
+ unless value.nil?
199
+ to_be = Array(to_be)
200
+ to_be.each do |tb|
201
+ return true if value.kind_of?(tb)
202
+ end
203
+ raise Exceptions::ValidationFailed, "Option #{key} must be a kind of #{to_be}! You passed #{value.inspect}."
204
+ end
205
+ end
206
+
207
+ #
208
+ # List of method names values must respond to.
209
+ #
210
+ # Uses value.respond_to?(respond_to) to evaluate. At least one must match
211
+ # for the value to be valid.
212
+ #
213
+ def _pv_respond_to(opts, key, method_name_list)
214
+ value = _pv_opts_lookup(opts, key)
215
+ unless value.nil?
216
+ Array(method_name_list).each do |method_name|
217
+ unless value.respond_to?(method_name)
218
+ raise Exceptions::ValidationFailed, "Option #{key} must have a #{method_name} method!"
219
+ end
220
+ end
221
+ end
222
+ end
223
+
224
+ #
225
+ # List of things that must not be true about the value.
226
+ #
227
+ # Calls `value.<thing>?` All responses must be false for the value to be
228
+ # valid.
229
+ # Values which do not respond to <thing>? are considered valid (because if
230
+ # a value doesn't respond to `:readable?`, then it probably isn't
231
+ # readable.)
232
+ #
233
+ # @example
234
+ # ```ruby
235
+ # property :x, cannot_be: [ :nil, :empty ]
236
+ # x [ 1, 2 ] #=> valid
237
+ # x 1 #=> valid
238
+ # x [] #=> invalid
239
+ # x nil #=> invalid
240
+ # ```
241
+ #
242
+ def _pv_cannot_be(opts, key, predicate_method_base_name)
243
+ value = _pv_opts_lookup(opts, key)
244
+ if !value.nil?
245
+ Array(predicate_method_base_name).each do |method_name|
246
+ predicate_method = :"#{method_name}?"
247
+
248
+ if value.respond_to?(predicate_method)
249
+ if value.send(predicate_method)
250
+ raise Exceptions::ValidationFailed, "Option #{key} cannot be #{predicate_method_base_name}"
251
+ end
252
+ end
253
+ end
254
+ end
255
+ end
256
+
257
+ #
258
+ # The default value for a property.
259
+ #
260
+ # When the property is not assigned, this will be used.
261
+ #
262
+ # If this is a lazy value, it will either be passed the resource as a value,
263
+ # or if the lazy proc does not take parameters, it will be run in the
264
+ # context of the instance with instance_eval.
265
+ #
266
+ # @example
267
+ # ```ruby
268
+ # property :x, default: 10
269
+ # ```
270
+ #
271
+ # @example
272
+ # ```ruby
273
+ # property :x
274
+ # property :y, default: lazy { x+2 }
275
+ # ```
276
+ #
277
+ # @example
278
+ # ```ruby
279
+ # property :x
280
+ # property :y, default: lazy { |r| r.x+2 }
281
+ # ```
282
+ #
283
+ def _pv_default(opts, key, default_value)
284
+ value = _pv_opts_lookup(opts, key)
285
+ if value.nil?
286
+ default_value = default_value.freeze if !default_value.is_a?(DelayedEvaluator)
287
+ opts[key] = default_value
288
+ end
289
+ end
290
+
291
+ #
292
+ # List of regexes values that must match.
293
+ #
294
+ # Uses regex.match() to evaluate. At least one must match for the value to
295
+ # be valid.
296
+ #
297
+ # `nil` passes regex validation automatically.
298
+ #
299
+ # @example
300
+ # ```ruby
301
+ # property :x, regex: [ /abc/, /xyz/ ]
302
+ # ```
303
+ #
304
+ def _pv_regex(opts, key, regex)
305
+ value = _pv_opts_lookup(opts, key)
306
+ if !value.nil?
307
+ Array(regex).flatten.each do |r|
308
+ return true if r.match(value.to_s)
309
+ end
310
+ raise Exceptions::ValidationFailed, "Option #{key}'s value #{value} does not match regular expression #{regex.inspect}"
311
+ end
312
+ end
313
+
314
+ #
315
+ # List of procs we pass the value to.
316
+ #
317
+ # All procs must return true for the value to be valid. If any procs do
318
+ # not return true, the key will be used for the message: `"Property x's
319
+ # value :y <message>"`.
320
+ #
321
+ # @example
322
+ # ```ruby
323
+ # property :x, callbacks: { "is bigger than 10" => proc { |v| v <= 10 }, "is not awesome" => proc { |v| !v.awesome }}
324
+ # ```
325
+ #
326
+ def _pv_callbacks(opts, key, callbacks)
327
+ raise ArgumentError, "Callback list must be a hash!" unless callbacks.kind_of?(Hash)
328
+ value = _pv_opts_lookup(opts, key)
329
+ if !value.nil?
330
+ callbacks.each do |message, zeproc|
331
+ unless zeproc.call(value)
332
+ raise Exceptions::ValidationFailed, "Option #{key}'s value #{value} #{message}!"
333
+ end
334
+ end
335
+ end
336
+ end
337
+
338
+ #
339
+ # Allows a parameter to default to the value of the resource name.
340
+ #
341
+ # @example
342
+ # ```ruby
343
+ # property :x, name_property: true
344
+ # ```
345
+ #
346
+ def _pv_name_property(opts, key, is_name_property=true)
347
+ if is_name_property
348
+ if opts[key].nil?
349
+ opts[key] = self.instance_variable_get(:"@name")
350
+ end
351
+ end
352
+ end
353
+ alias :_pv_name_attribute :_pv_name_property
354
+
355
+ #
356
+ # List of valid things values can be.
357
+ #
358
+ # Uses Ruby's `===` to evaluate (is === value). At least one must match
359
+ # for the value to be valid.
360
+ #
361
+ # If a proc is passed, it is instance_eval'd in the resource, passed the
362
+ # value, and must return a truthy or falsey value.
363
+ #
364
+ # @example Class
365
+ # ```ruby
366
+ # property :x, String
367
+ # x 'valid' #=> valid
368
+ # x 1 #=> invalid
369
+ # x nil #=> invalid
370
+ #
371
+ # @example Value
372
+ # ```ruby
373
+ # property :x, [ :a, :b, :c, nil ]
374
+ # x :a #=> valid
375
+ # x nil #=> valid
376
+ # ```
377
+ #
378
+ # @example Regex
379
+ # ```ruby
380
+ # property :x, /bar/
381
+ # x 'foobar' #=> valid
382
+ # x 'foo' #=> invalid
383
+ # x nil #=> invalid
384
+ # ```
385
+ #
386
+ # @example Proc
387
+ # ```ruby
388
+ # property :x, proc { |x| x > y }
389
+ # property :y, default: 2
390
+ # x 3 #=> valid
391
+ # x 1 #=> invalid
392
+ # ```
393
+ #
394
+ # @example Property
395
+ # ```ruby
396
+ # type = Property.new(is: String)
397
+ # property :x, type
398
+ # x 'foo' #=> valid
399
+ # x 1 #=> invalid
400
+ # x nil #=> invalid
401
+ # ```
402
+ #
403
+ # @example RSpec Matcher
404
+ # ```ruby
405
+ # include RSpec::Matchers
406
+ # property :x, a_string_matching /bar/
407
+ # x 'foobar' #=> valid
408
+ # x 'foo' #=> invalid
409
+ # x nil #=> invalid
410
+ # ```
411
+ #
412
+ def _pv_is(opts, key, to_be, raise_error: true)
413
+ return true if !opts.has_key?(key.to_s) && !opts.has_key?(key.to_sym)
414
+ value = _pv_opts_lookup(opts, key)
415
+ to_be = [ to_be ].flatten(1)
416
+ to_be.each do |tb|
417
+ case tb
418
+ when Proc
419
+ return true if instance_exec(value, &tb)
420
+ when Property
421
+ validate(opts, { key => tb.validation_options })
422
+ return true
423
+ else
424
+ return true if tb === value
425
+ end
426
+ end
427
+
428
+ if raise_error
429
+ raise Exceptions::ValidationFailed, "Option #{key} must be one of: #{to_be.join(", ")}! You passed #{value.inspect}."
430
+ else
431
+ false
432
+ end
433
+ end
434
+
435
+ #
436
+ # Method to mess with a value before it is validated and stored.
437
+ #
438
+ # Allows you to transform values into a canonical form that is easy to
439
+ # work with.
440
+ #
441
+ # This is passed the value to transform, and is run in the context of the
442
+ # instance (so it has access to other resource properties). It must return
443
+ # the value that will be stored in the instance.
444
+ #
445
+ # @example
446
+ # ```ruby
447
+ # property :x, Integer, coerce: { |v| v.to_i }
448
+ # ```
449
+ #
450
+ def _pv_coerce(opts, key, coercer)
451
+ if opts.has_key?(key.to_s)
452
+ opts[key.to_s] = instance_exec(opts[key], &coercer)
453
+ elsif opts.has_key?(key.to_sym)
454
+ opts[key.to_sym] = instance_exec(opts[key], &coercer)
455
+ end
456
+ end
457
+
458
+ # Used by #set_or_return to avoid emitting a deprecation warning for
459
+ # "value nil" and to keep default stickiness working exactly the same
460
+ # @api private
461
+ class SetOrReturnProperty < (defined?(::Chef::Mixin::ParamsValidate::SetOrReturnProperty) ? ::Chef::Mixin::ParamsValidate::SetOrReturnProperty : Chef::Property)
462
+ def get(resource)
463
+ value = super
464
+ # All values are sticky, frozen or not
465
+ if !is_set?(resource)
466
+ set_value(resource, value)
467
+ end
468
+ value
469
+ end
470
+
471
+ def call(resource, value=NOT_PASSED)
472
+ # setting to nil does a get
473
+ if value.nil? && !explicitly_accepts_nil?(resource)
474
+ get(resource)
475
+ else
476
+ super
477
+ end
478
+ end
479
+ end
480
+ end
481
+ end
482
+ end
483
+ end
484
+ end