diff options
author | John Keiser <john@johnkeiser.com> | 2015-06-03 14:32:43 -0700 |
---|---|---|
committer | John Keiser <john@johnkeiser.com> | 2015-06-23 15:23:01 -0700 |
commit | 4e34d816167af65b36c7a57ad33dca3b1f39c1e4 (patch) | |
tree | 0572f1f83c28db05fb5225837b13ab97c36fe3e2 | |
parent | c4257f9d016871c6b4243079542d803d5e7fa383 (diff) | |
download | chef-4e34d816167af65b36c7a57ad33dca3b1f39c1e4.tar.gz |
Add "is" to property
-rw-r--r-- | lib/chef/mixin/params_validate.rb | 212 | ||||
-rw-r--r-- | lib/chef/resource.rb | 3 | ||||
-rw-r--r-- | spec/unit/property/validation_spec.rb | 110 | ||||
-rw-r--r-- | spec/unit/property_spec.rb | 6 |
4 files changed, 175 insertions, 156 deletions
diff --git a/lib/chef/mixin/params_validate.rb b/lib/chef/mixin/params_validate.rb index ccc313db32..6fe5036570 100644 --- a/lib/chef/mixin/params_validate.rb +++ b/lib/chef/mixin/params_validate.rb @@ -109,137 +109,155 @@ class Chef private - # Return the value of a parameter, or nil if it doesn't exist. - def _pv_opts_lookup(opts, key) - if opts.has_key?(key.to_s) - opts[key.to_s] - elsif opts.has_key?(key.to_sym) - opts[key.to_sym] + # Return the value of a parameter, or nil if it doesn't exist. + def _pv_opts_lookup(opts, key) + if opts.has_key?(key.to_s) + opts[key.to_s] + elsif opts.has_key?(key.to_sym) + opts[key.to_sym] + else + nil + end + end + + # Raise an exception if the parameter is not found. + def _pv_required(opts, key, is_required=true) + if is_required + if (opts.has_key?(key.to_s) && !opts[key.to_s].nil?) || + (opts.has_key?(key.to_sym) && !opts[key.to_sym].nil?) + true else - nil + raise Exceptions::ValidationFailed, "Required argument #{key} is missing!" end end + end - # Raise an exception if the parameter is not found. - def _pv_required(opts, key, is_required=true) - if is_required - if (opts.has_key?(key.to_s) && !opts[key.to_s].nil?) || - (opts.has_key?(key.to_sym) && !opts[key.to_sym].nil?) - true - else - raise Exceptions::ValidationFailed, "Required argument #{key} is missing!" - end + def _pv_equal_to(opts, key, to_be) + value = _pv_opts_lookup(opts, key) + unless value.nil? + passes = false + to_be = Array(to_be) + to_be.each do |tb| + passes = true if value == tb + end + unless passes + raise Exceptions::ValidationFailed, "Option #{key} must be equal to one of: #{to_be.join(", ")}! You passed #{value.inspect}." end end + end - def _pv_equal_to(opts, key, to_be) - value = _pv_opts_lookup(opts, key) - unless value.nil? - passes = false - to_be = Array(to_be) - to_be.each do |tb| - passes = true if value == tb - end - unless passes - raise Exceptions::ValidationFailed, "Option #{key} must be equal to one of: #{to_be.join(", ")}! You passed #{value.inspect}." - end + # Raise an exception if the parameter is not a kind_of?(to_be) + def _pv_kind_of(opts, key, to_be) + value = _pv_opts_lookup(opts, key) + unless value.nil? + passes = false + to_be = Array(to_be) + to_be.each do |tb| + passes = true if value.kind_of?(tb) + end + unless passes + raise Exceptions::ValidationFailed, "Option #{key} must be a kind of #{to_be}! You passed #{value.inspect}." end end + end - # Raise an exception if the parameter is not a kind_of?(to_be) - def _pv_kind_of(opts, key, to_be) - value = _pv_opts_lookup(opts, key) - unless value.nil? - passes = false - to_be = Array(to_be) - to_be.each do |tb| - passes = true if value.kind_of?(tb) - end - unless passes - raise Exceptions::ValidationFailed, "Option #{key} must be a kind of #{to_be}! You passed #{value.inspect}." + # Raise an exception if the parameter does not respond to a given set of methods. + 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, "Option #{key} must have a #{method_name} method!" end end end + end - # Raise an exception if the parameter does not respond to a given set of methods. - 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, "Option #{key} must have a #{method_name} method!" - end + # Assert that parameter returns false when passed a predicate method. + # For example, :cannot_be => :blank will raise a Exceptions::ValidationFailed + # error value.blank? returns a 'truthy' (not nil or false) value. + # + # Note, this will *PASS* if the object doesn't respond to the method. + # So, to make sure a value is not nil and not blank, you need to do + # both :cannot_be => [ :blank, :nil ] + def _pv_cannot_be(opts, key, predicate_method_base_name) + value = _pv_opts_lookup(opts, key) + 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, "Option #{key} cannot be #{predicate_method_base_name}" end end end + end + + # Assign a default value to a parameter. + def _pv_default(opts, key, default_value) + value = _pv_opts_lookup(opts, key) + if value == nil + opts[key] = default_value + end + end - # Assert that parameter returns false when passed a predicate method. - # For example, :cannot_be => :blank will raise a Exceptions::ValidationFailed - # error value.blank? returns a 'truthy' (not nil or false) value. - # - # Note, this will *PASS* if the object doesn't respond to the method. - # So, to make sure a value is not nil and not blank, you need to do - # both :cannot_be => [ :blank, :nil ] - def _pv_cannot_be(opts, key, predicate_method_base_name) - value = _pv_opts_lookup(opts, key) - 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, "Option #{key} cannot be #{predicate_method_base_name}" + # Check a parameter against a regular expression. + def _pv_regex(opts, key, regex) + value = _pv_opts_lookup(opts, key) + if value != nil + passes = false + Array(regex).each do |r| + if value != nil + if r.match(value.to_s) + passes = true end end end - end - - # Assign a default value to a parameter. - def _pv_default(opts, key, default_value) - value = _pv_opts_lookup(opts, key) - if value == nil - opts[key] = default_value + unless passes + raise Exceptions::ValidationFailed, "Option #{key}'s value #{value} does not match regular expression #{regex.inspect}" end end + end - # Check a parameter against a regular expression. - def _pv_regex(opts, key, regex) - value = _pv_opts_lookup(opts, key) - if value != nil - passes = false - Array(regex).each do |r| - if value != nil - if r.match(value.to_s) - passes = true - end - end - end - unless passes - raise Exceptions::ValidationFailed, "Option #{key}'s value #{value} does not match regular expression #{regex.inspect}" + # Check a parameter against a hash of proc's. + def _pv_callbacks(opts, key, callbacks) + raise ArgumentError, "Callback list must be a hash!" unless callbacks.kind_of?(Hash) + value = _pv_opts_lookup(opts, key) + if value != nil + callbacks.each do |message, zeproc| + if zeproc.call(value) != true + raise Exceptions::ValidationFailed, "Option #{key}'s value #{value} #{message}!" end end end + end - # Check a parameter against a hash of proc's. - def _pv_callbacks(opts, key, callbacks) - raise ArgumentError, "Callback list must be a hash!" unless callbacks.kind_of?(Hash) - value = _pv_opts_lookup(opts, key) - if value != nil - callbacks.each do |message, zeproc| - if zeproc.call(value) != true - raise Exceptions::ValidationFailed, "Option #{key}'s value #{value} #{message}!" - end - end + # Allow a parameter to default to @name + def _pv_name_attribute(opts, key, is_name_attribute=true) + if is_name_attribute + if opts[key] == nil + opts[key] = self.instance_variable_get("@name") end end + end - # Allow a parameter to default to @name - def _pv_name_attribute(opts, key, is_name_attribute=true) - if is_name_attribute - if opts[key] == nil - opts[key] = self.instance_variable_get("@name") + # Compare the way "case" would (i.e. `===`) + def _pv_is(opts, key, to_be) + value = _pv_opts_lookup(opts, key) + unless value.nil? + passes = false + to_be = Array(to_be) + to_be.each do |tb| + if tb.is_a?(Proc) + return if instance_exec(value, &tb) + else + return if tb === value end end + + raise Exceptions::ValidationFailed, "Option #{key} must be one of: #{to_be.join(", ")}! You passed #{value.inspect}." end + end end end end diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb index 40a6e911a6..712b7b36cb 100644 --- a/lib/chef/resource.rb +++ b/lib/chef/resource.rb @@ -720,6 +720,9 @@ class Chef # # @param name [Symbol] The name of the property. # @param options [Hash<Symbol,Object>] Validation options. + # @option options [Object,Array] :is An object, or list of + # objects, that must match the value using Ruby's `===` operator + # (`options[:is].any? { |v| v === value }`). # @option options [Object,Array] :equal_to An object, or list # of objects, that must be equal to the value using Ruby's `==` # operator (`options[:is].any? { |v| v == value }`) diff --git a/spec/unit/property/validation_spec.rb b/spec/unit/property/validation_spec.rb index a88ebfd0cf..4aa8a5474e 100644 --- a/spec/unit/property/validation_spec.rb +++ b/spec/unit/property/validation_spec.rb @@ -136,61 +136,61 @@ describe "Chef::Resource.property validation" do # end # is - # context "is" do - # # Class - # validation_test 'is: String', - # [ 'a', '' ], - # [ nil, :a, 1 ] - # - # # Value - # validation_test 'is: :a', - # [ :a ], - # [ :b, nil ] - # - # validation_test 'is: [ :a, :b ]', - # [ :a, :b ], - # [ [ :a, :b ], nil ] - # - # validation_test 'is: [ [ :a, :b ] ]', - # [ [ :a, :b ] ], - # [ :a, :b, nil ] - # - # # Regex - # validation_test 'is: /abc/', - # [ 'abc', 'wowabcwow' ], - # [ '', 'abac', nil ] - # - # # PropertyType - # validation_test 'is: PropertyType.new(is: :a)', - # [ :a ], - # [ :b, nil ] - # - # # RSpec Matcher - # class Globalses - # extend RSpec::Matchers - # end - # - # validation_test "is: Globalses.eq(10)", - # [ 10 ], - # [ 1, nil ] - # - # # Proc - # validation_test 'is: proc { |x| x }', - # [ true, 1 ], - # [ false, nil ] - # - # validation_test 'is: proc { |x| x > blah }', - # [ 10 ], - # [ -1 ] - # - # validation_test 'is: nil', - # [ nil ], - # [ 'a' ] - # - # validation_test 'is: [ String, nil ]', - # [ 'a', nil ], - # [ :b ] - # end + context "is" do + # Class + validation_test 'is: String', + [ 'a', '' ], + [ nil, :a, 1 ] + + # Value + validation_test 'is: :a', + [ :a ], + [ :b, nil ] + + validation_test 'is: [ :a, :b ]', + [ :a, :b ], + [ [ :a, :b ], nil ] + + validation_test 'is: [ [ :a, :b ] ]', + [ [ :a, :b ] ], + [ :a, :b, nil ] + + # Regex + validation_test 'is: /abc/', + [ 'abc', 'wowabcwow' ], + [ '', 'abac', nil ] + + # PropertyType + # validation_test 'is: PropertyType.new(is: :a)', + # [ :a ], + # [ :b, nil ] + + # RSpec Matcher + class Globalses + extend RSpec::Matchers + end + + validation_test "is: Globalses.eq(10)", + [ 10 ], + [ 1, nil ] + + # Proc + validation_test 'is: proc { |x| x }', + [ true, 1 ], + [ false, nil ] + + validation_test 'is: proc { |x| x > blah }', + [ 10 ], + [ -1 ] + + validation_test 'is: nil', + [ nil ], + [ 'a' ] + + validation_test 'is: [ String, nil ]', + [ 'a', nil ], + [ :b ] + end # Combination context "combination" do diff --git a/spec/unit/property_spec.rb b/spec/unit/property_spec.rb index b9c0d27da8..d948ad20e0 100644 --- a/spec/unit/property_spec.rb +++ b/spec/unit/property_spec.rb @@ -652,8 +652,7 @@ describe "Chef::Resource.property" do end end - # with_property ':x, is: proc { |v| Namer.next_index; true }' do - with_property ':x, callbacks: { "a" => proc { |v| Namer.next_index; true } }' do + with_property ':x, is: proc { |v| Namer.next_index; true }' do it "lazy values are validated on each access" do resource.x lazy { Namer.next_index } expect(resource.x).to eq 1 @@ -730,8 +729,7 @@ describe "Chef::Resource.property" do # end context "Chef::Resource::PropertyType validation" do - # with_property ':x, is: proc { |v| Namer.next_index; v.is_a?(Integer) }' do - with_property ':x, callbacks: { "a" => proc { |v| Namer.next_index; v.is_a?(Integer) } }' do + with_property ':x, is: proc { |v| Namer.next_index; v.is_a?(Integer) }' do it "validation runs on set" do expect(resource.x 10).to eq 10 expect(Namer.current_index).to eq 1 |