module Chef::Mixin::ParamsValidate
Public Instance Methods
Source
# File lib/chef/mixin/params_validate.rb, line 123 def lazy(&block) DelayedEvaluator.new(&block) end
Source
# File lib/chef/mixin/params_validate.rb, line 127 def set_or_return(symbol, value, validation) property = SetOrReturnProperty.new(name: symbol, **validation) property.call(self, value) end
Source
# File lib/chef/mixin/params_validate.rb, line 85 def validate(opts, map) map = map.validation_options if map.is_a?(Property) #-- # validate works by taking the keys in the validation map, assuming it's a hash, and # looking for _pv_:symbol as methods. Assuming it find them, it calls the right # one. #++ raise ArgumentError, "Options must be a hash" unless opts.is_a?(Hash) raise ArgumentError, "Validation Map must be a hash" unless map.is_a?(Hash) @validation_message ||= {} map.each do |key, validation| unless key.is_a?(Symbol) || key.is_a?(String) raise ArgumentError, "Validation map keys must be symbols or strings!" end case validation when true _pv_required(opts, key) when false true when Hash @validation_message[key] = validation.delete(:validation_message) if validation.key?(:validation_message) validation.each do |check, carg| check_method = "_pv_#{check}" if respond_to?(check_method, true) send(check_method, opts, key, carg) else raise ArgumentError, "Validation map has unknown check: #{check}" end end end end opts end
Takes a hash of options, along with a map to validate them. Returns the original options hash, plus any changes that might have been made (through things like setting default values in the validation map)
For example:
validate({ :one => "neat" }, { :one => { :kind_of => String }})
Would raise an exception if the value of :one above is not a kind_of? string. Valid map options are:
@param opts [Hash<Symbol,Object>] Validation opts.
@option opts [String] :validation_message A custom message to return should validation fail. @option opts [Object,Array] :is An object, or list of objects, that must match the value using Ruby's `===` operator (`opts[:is].any? { |v| v === value }`). (See #_pv_is.) @option opts [Object,Array] :equal_to An object, or list of objects, that must be equal to the value using Ruby's `==` operator (`opts[:equal_to].any? { |v| v == value }`) (See #_pv_equal_to.) @option opts [Regexp,Array<Regexp>] :regex An object, or list of objects, that must match the value with `regex.match(value)`. (See #_pv_regex) @option opts [Class,Array<Class>] :kind_of A class, or list of classes, that the value must be an instance of. (See #_pv_kind_of.) @option opts [Hash<String,Proc>] :callbacks A hash of messages -> procs, all of which match the value. The proc must return a truthy or falsey value (true means it matches). (See #_pv_callbacks.) @option opts [Symbol,Array<Symbol>] :respond_to A method name, or list of method names, the value must respond to. (See #_pv_respond_to.) @option opts [Symbol,Array<Symbol>] :cannot_be A property, or a list of properties, that the value cannot have (such as `:nil` or `:empty`). The method with a questionmark at the end is called on the value (e.g. `value.empty?`). If the value does not have this method, it is considered valid (i.e. if you don't respond to `empty?` we assume you are not empty). (See #_pv_cannot_be.) @option opts [Proc] :coerce A proc which will be called to transform the user input to canonical form. The value is passed in, and the transformed value returned as output. Lazy values will *not* be passed to this method until after they are evaluated. Called in the context of the resource (meaning you can access other properties). (See #_pv_coerce.) (See #_pv_coerce.) @option opts [Boolean] :required `true` if this property must be present and not `nil`; `false` otherwise. This is checked after the resource is fully initialized. (See #_pv_required.) @option opts [Boolean] :name_property `true` if this property defaults to the same value as `name`. Equivalent to `default: lazy { name }`, except that #property_is_set? will return `true` if the property is set *or* if `name` is set. (See #_pv_name_property.) @option opts [Boolean] :name_attribute Same as `name_property`. @option opts [Object] :default The value this property will return if the user does not set one. If this is `lazy`, it will be run in the context of the instance (and able to access other properties). (See #_pv_default.)
Private Instance Methods
Source
# File lib/chef/mixin/params_validate.rb, line 322 def _pv_callbacks(opts, key, callbacks) raise ArgumentError, "Callback list must be a hash!" unless callbacks.is_a?(Hash) value = _pv_opts_lookup(opts, key) unless value.nil? callbacks.each do |message, zeproc| unless zeproc.call(value) raise Exceptions::ValidationFailed, _validation_message(key, "Option #{key}'s value #{value} #{message}!") end end end end
List of procs we pass the value to.
All procs must return true for the value to be valid. If any procs do not return true, the key will be used for the message: ‘“Property x’s value :y <message>”‘.
@example
```ruby property :x, callbacks: { "is bigger than 10" => proc { |v| v <= 10 }, "is not awesome" => proc { |v| !v.awesome }} ```
Source
# File lib/chef/mixin/params_validate.rb, line 238 def _pv_cannot_be(opts, key, predicate_method_base_name) value = _pv_opts_lookup(opts, key) unless value.nil? Array(predicate_method_base_name).each do |method_name| predicate_method = :"#{method_name}?" if value.respond_to?(predicate_method) if value.send(predicate_method) raise Exceptions::ValidationFailed, _validation_message(key, "Option #{key} cannot be #{predicate_method_base_name}") end end end end end
List of things that must not be true about the value.
Calls ‘value.<thing>?` All responses must be false for the value to be valid. Values which do not respond to <thing>? are considered valid (because if a value doesn’t respond to ‘:readable?`, then it probably isn’t readable.)
@example
```ruby property :x, cannot_be: [ :nil, :empty ] x [ 1, 2 ] #=> valid x 1 #=> valid x [] #=> invalid x nil #=> invalid ```
Source
# File lib/chef/mixin/params_validate.rb, line 464 def _pv_coerce(opts, key, coercer) if opts.key?(key.to_s) raise Exceptions::CannotValidateStaticallyError, "coerce must be evaluated for each resource." if self == Chef::Mixin::ParamsValidate opts[key.to_s] = instance_exec(opts[key], &coercer) elsif opts.key?(key.to_sym) raise Exceptions::CannotValidateStaticallyError, "coerce must be evaluated for each resource." if self == Chef::Mixin::ParamsValidate opts[key.to_sym] = instance_exec(opts[key], &coercer) end end
Method to mess with a value before it is validated and stored.
Allows you to transform values into a canonical form that is easy to work with.
This is passed the value to transform, and is run in the context of the instance (so it has access to other resource properties). It must return the value that will be stored in the instance.
@example
```ruby property :x, Integer, coerce: { |v| v.to_i } ```
Source
# File lib/chef/mixin/params_validate.rb, line 279 def _pv_default(opts, key, default_value) value = _pv_opts_lookup(opts, key) if value.nil? default_value = default_value.freeze unless default_value.is_a?(DelayedEvaluator) opts[key] = default_value end end
The default value for a property.
When the property is not assigned, this will be used.
If this is a lazy value, it will either be passed the resource as a value, or if the lazy proc does not take parameters, it will be run in the context of the instance with instance_eval.
@example
```ruby property :x, default: 10 ```
@example
```ruby property :x property :y, default: lazy { x+2 } ```
@example
```ruby property :x property :y, default: lazy { |r| r.x+2 } ```
Source
# File lib/chef/mixin/params_validate.rb, line 171 def _pv_equal_to(opts, key, to_be) value = _pv_opts_lookup(opts, key) unless value.nil? to_be = Array(to_be) to_be.each do |tb| return true if value == tb end # Ruby will print :something as something, which confuses users so make sure to print them as symbols # by inspecting the value instead of just printing it raise Exceptions::ValidationFailed, _validation_message(key, "Option #{key} must be equal to one of: #{to_be.map(&:inspect).join(", ")}! You passed #{value.inspect}.") end end
List of things values must be equal to.
Uses Ruby’s ‘==` to evaluate (equal_to == value). At least one must match for the value to be valid.
‘nil` passes this validation automatically.
@return [Array,nil] List of things values must be equal to, or nil if
equal_to is unspecified.
Source
# File lib/chef/mixin/params_validate.rb, line 411 def _pv_is(opts, key, to_be) return true if !opts.key?(key.to_s) && !opts.key?(key.to_sym) value = _pv_opts_lookup(opts, key) to_be = [ to_be ].flatten(1) errors = [] passed = to_be.any? do |tb| case tb when Proc raise Exceptions::CannotValidateStaticallyError, "is: proc { } must be evaluated once for each resource" if self == Chef::Mixin::ParamsValidate instance_exec(value, &tb) when Property begin validate(opts, { key => tb.validation_options }) true rescue Exceptions::ValidationFailed # re-raise immediately if there is only one "is" so we get a better stack raise if to_be.size == 1 errors << $! false end else tb === value end end if passed true else message = "Property #{key} must be one of: #{to_be.map(&:inspect).join(", ")}! You passed #{value.inspect}." unless errors.empty? message << " Errors:\n#{errors.map { |m| "- #{m}" }.join("\n")}" end raise Exceptions::ValidationFailed, _validation_message(key, message) end end
List of valid things values can be.
Uses Ruby’s ‘===` to evaluate (is === value). At least one must match for the value to be valid.
If a proc is passed, it is instance_eval’d in the resource, passed the value, and must return a truthy or falsey value.
@example Class
```ruby property :x, String x 'valid' #=> valid x 1 #=> invalid x nil #=> invalid
@example Value
```ruby property :x, [ :a, :b, :c, nil ] x :a #=> valid x nil #=> valid ```
@example Regex
```ruby property :x, /bar/ x 'foobar' #=> valid x 'foo' #=> invalid x nil #=> invalid ```
@example Proc
```ruby property :x, proc { |x| x > y } property :y, default: 2 x 3 #=> valid x 1 #=> invalid ```
@example Property
```ruby type = Property.new(is: String) property :x, type x 'foo' #=> valid x 1 #=> invalid x nil #=> invalid ```
@example RSpec Matcher
```ruby include RSpec::Matchers property :x, a_string_matching /bar/ x 'foobar' #=> valid x 'foo' #=> invalid x nil #=> invalid ```
Source
# File lib/chef/mixin/params_validate.rb, line 192 def _pv_kind_of(opts, key, to_be) value = _pv_opts_lookup(opts, key) unless value.nil? to_be = Array(to_be) to_be.each do |tb| return true if value.is_a?(tb) end raise Exceptions::ValidationFailed, _validation_message(key, "Option #{key} must be a kind of #{to_be}! You passed #{value.inspect}.") end end
List of things values must be instances of.
Uses value.kind_of?(kind_of) to evaluate. At least one must match for the value to be valid.
‘nil` automatically passes this validation.
Source
# File lib/chef/mixin/params_validate.rb, line 343 def _pv_name_property(opts, key, is_name_property = true) if is_name_property if opts[key].nil? raise Exceptions::CannotValidateStaticallyError, "name_property cannot be evaluated without a resource." if self == Chef::Mixin::ParamsValidate opts[key] = instance_variable_get(:"@name") end end end
Allows a parameter to default to the value of the resource name.
@example
```ruby property :x, name_property: true ```
Source
# File lib/chef/mixin/params_validate.rb, line 139 def _pv_opts_lookup(opts, key) if opts.key?(key.to_s) opts[key.to_s] elsif opts.key?(key.to_sym) opts[key.to_sym] else nil end end
Return the value of a parameter, or nil if it doesn’t exist.
Source
# File lib/chef/mixin/params_validate.rb, line 300 def _pv_regex(opts, key, regex) value = _pv_opts_lookup(opts, key) unless value.nil? Array(regex).flatten.each do |r| return true if r.match(value.to_s) end raise Exceptions::ValidationFailed, _validation_message(key, "Property #{key}'s value #{value} does not match regular expression #{regex.inspect}") end end
List of regexes values that must match.
Uses regex.match() to evaluate. At least one must match for the value to be valid.
‘nil` passes regex validation automatically.
@example
```ruby property :x, regex: [ /abc/, /xyz/ ] ```
Source
# File lib/chef/mixin/params_validate.rb, line 150 def _pv_required(opts, key, is_required = true, explicitly_allows_nil = false) if is_required return true if opts.key?(key.to_s) && (explicitly_allows_nil || !opts[key.to_s].nil?) return true if opts.key?(key.to_sym) && (explicitly_allows_nil || !opts[key.to_sym].nil?) raise Exceptions::ValidationFailed, _validation_message(key, "Required argument #{key.inspect} is missing!") end true end
Raise an exception if the parameter is not found.
Source
# File lib/chef/mixin/params_validate.rb, line 209 def _pv_respond_to(opts, key, method_name_list) value = _pv_opts_lookup(opts, key) unless value.nil? Array(method_name_list).each do |method_name| unless value.respond_to?(method_name) raise Exceptions::ValidationFailed, _validation_message(key, "Option #{key} must have a #{method_name} method!") end end end end
List of method names values must respond to.
Uses value.respond_to?(respond_to) to evaluate. At least one must match for the value to be valid.
Source
# File lib/chef/mixin/params_validate.rb, line 134 def _validation_message(key, default) @validation_message.key?(key) ? @validation_message[key] : default end