Permalink
Browse files

Improve ValidateNumericalityOfMatcher document expression

  • Loading branch information...
1 parent 6d1da00 commit 806716c79c978267b2ed97761c4eb63cc0d649de @untidy-hair untidy-hair committed with mcmire Jan 13, 2014
Showing with 294 additions and 219 deletions.
  1. +4 −0 NEWS.md
  2. +3 −1 lib/shoulda/matchers/active_model.rb
  3. +0 −4 lib/shoulda/matchers/active_model/disallow_value_matcher.rb
  4. +4 −4 lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb
  5. +22 −0 lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb
  6. +5 −20 ...atchers/active_model/numericality_matchers/{odd_even_number_matcher.rb → numeric_type_matcher.rb}
  7. +22 −0 lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb
  8. +3 −23 lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb
  9. +16 −6 lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb
  10. +0 −4 spec/shoulda/matchers/active_model/disallow_value_matcher_spec.rb
  11. +14 −0 spec/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb
  12. +55 −0 spec/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb
  13. +0 −97 spec/shoulda/matchers/active_model/numericality_matchers/odd_even_number_matcher_spec.rb
  14. +55 −0 spec/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb
  15. +21 −24 spec/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb
  16. +60 −32 spec/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb
  17. +0 −4 spec/support/shared_examples/numerical_submatcher.rb
  18. +10 −0 spec/support/shared_examples/numerical_type_submatcher.rb
View
@@ -9,6 +9,10 @@
non-password attribute which is in a model that `has_secure_password`. Doing
so previously would result in a "Password digest missing on new record" error.
+* Fix description for `validate_numericality_of` so that if the matcher fails,
+ the error message reported does not say the matcher accepts integer values if
+ you didn't specify that.
+
# v 2.5.0
* Fix Rails/Test::Unit integration to ensure that the test case classes we are
@@ -13,8 +13,10 @@
require 'shoulda/matchers/active_model/validate_acceptance_of_matcher'
require 'shoulda/matchers/active_model/validate_confirmation_of_matcher'
require 'shoulda/matchers/active_model/validate_numericality_of_matcher'
+require 'shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher'
require 'shoulda/matchers/active_model/numericality_matchers/comparison_matcher'
-require 'shoulda/matchers/active_model/numericality_matchers/odd_even_number_matcher'
+require 'shoulda/matchers/active_model/numericality_matchers/odd_number_matcher'
+require 'shoulda/matchers/active_model/numericality_matchers/even_number_matcher'
require 'shoulda/matchers/active_model/numericality_matchers/only_integer_matcher'
require 'shoulda/matchers/active_model/allow_mass_assignment_of_matcher'
require 'shoulda/matchers/active_model/errors'
@@ -35,10 +35,6 @@ def failure_message_when_negated
end
alias failure_message_for_should_not failure_message_when_negated
- def allowed_types
- ''
- end
-
def strict
@allow_matcher.strict
self
@@ -23,14 +23,14 @@ def matches?(subject)
disallows_value_of(value_to_compare, @message)
end
- def allowed_types
- 'integer'
- end
-
def with_message(message)
@message = message
end
+ def comparison_description
+ "#{expectation} #{@value}"
+ end
+
private
def value_to_compare
@@ -0,0 +1,22 @@
+module Shoulda # :nodoc:
+ module Matchers
+ module ActiveModel # :nodoc:
+ module NumericalityMatchers
+ class EvenNumberMatcher < NumericTypeMatcher # :nodoc:
+ NON_EVEN_NUMBER_VALUE = 1
+
+ def initialize(attribute, options = {})
+ @attribute = attribute
+ @disallow_value_matcher = DisallowValueMatcher.new(NON_EVEN_NUMBER_VALUE).
+ for(@attribute).
+ with_message(:even)
+ end
+
+ def allowed_type
+ 'even numbers'
+ end
+ end
+ end
+ end
+ end
+end
@@ -2,24 +2,9 @@ module Shoulda # :nodoc:
module Matchers
module ActiveModel # :nodoc:
module NumericalityMatchers
- class OddEvenNumberMatcher # :nodoc:
- NON_EVEN_NUMBER_VALUE = 1
- NON_ODD_NUMBER_VALUE = 2
-
- def initialize(attribute, options = {})
- @attribute = attribute
- options[:odd] ||= true
- options[:even] ||= false
-
- if options[:odd] && !options[:even]
- @disallow_value_matcher = DisallowValueMatcher.new(NON_ODD_NUMBER_VALUE).
- for(@attribute).
- with_message(:odd)
- else
- @disallow_value_matcher = DisallowValueMatcher.new(NON_EVEN_NUMBER_VALUE).
- for(@attribute).
- with_message(:even)
- end
+ class NumericTypeMatcher
+ def initialize
+ raise NotImplementedError
end
def matches?(subject)
@@ -31,8 +16,8 @@ def with_message(message)
self
end
- def allowed_types
- 'integer'
+ def allowed_type
+ raise NotImplementedError
end
def failure_message
@@ -0,0 +1,22 @@
+module Shoulda # :nodoc:
+ module Matchers
+ module ActiveModel # :nodoc:
+ module NumericalityMatchers
+ class OddNumberMatcher < NumericTypeMatcher # :nodoc:
+ NON_ODD_NUMBER_VALUE = 2
+
+ def initialize(attribute, options = {})
+ @attribute = attribute
+ @disallow_value_matcher = DisallowValueMatcher.new(NON_ODD_NUMBER_VALUE).
+ for(@attribute).
+ with_message(:odd)
+ end
+
+ def allowed_type
+ 'odd numbers'
+ end
+ end
+ end
+ end
+ end
+end
@@ -2,38 +2,18 @@ module Shoulda # :nodoc:
module Matchers
module ActiveModel # :nodoc:
module NumericalityMatchers
- class OnlyIntegerMatcher # :nodoc:
+ class OnlyIntegerMatcher < NumericTypeMatcher # :nodoc:
NON_INTEGER_VALUE = 0.1
-
def initialize(attribute)
@attribute = attribute
@disallow_value_matcher = DisallowValueMatcher.new(NON_INTEGER_VALUE).
for(attribute).
with_message(:not_an_integer)
end
- def matches?(subject)
- @disallow_value_matcher.matches?(subject)
- end
-
- def with_message(message)
- @disallow_value_matcher.with_message(message)
- self
- end
-
- def allowed_types
- 'integer'
- end
-
- def failure_message
- @disallow_value_matcher.failure_message
- end
- alias failure_message_for_should failure_message
-
- def failure_message_when_negated
- @disallow_value_matcher.failure_message_when_negated
+ def allowed_type
+ 'integers'
end
- alias failure_message_for_should_not failure_message_when_negated
end
end
end
@@ -22,6 +22,7 @@ def validate_numericality_of(attr)
end
class ValidateNumericalityOfMatcher
+ NUMERIC_NAME = 'numbers'
NON_NUMERIC_VALUE = 'abcd'
def initialize(attribute)
@@ -62,13 +63,13 @@ def is_less_than_or_equal_to(value)
end
def odd
- odd_number_matcher = NumericalityMatchers::OddEvenNumberMatcher.new(@attribute, odd: true)
+ odd_number_matcher = NumericalityMatchers::OddNumberMatcher.new(@attribute)
add_submatcher(odd_number_matcher)
self
end
def even
- even_number_matcher = NumericalityMatchers::OddEvenNumberMatcher.new(@attribute, even: true)
+ even_number_matcher = NumericalityMatchers::EvenNumberMatcher.new(@attribute)
add_submatcher(even_number_matcher)
self
end
@@ -84,7 +85,7 @@ def matches?(subject)
end
def description
- "only allow #{allowed_types} values for #{@attribute}"
+ "only allow #{allowed_types} for #{@attribute}#{comparison_descriptions}"
end
def failure_message
@@ -128,12 +129,21 @@ def failing_submatchers
end
def allowed_types
- allowed = ['numeric'] + submatcher_allowed_types
- allowed.join(', ')
+ allowed_array = submatcher_allowed_types
+ allowed_array.empty? ? NUMERIC_NAME : allowed_array.join(', ')
end
def submatcher_allowed_types
- @submatchers.map(&:allowed_types).reject(&:empty?)
+ @submatchers.inject([]){|m, s| m << s.allowed_type if s.respond_to?(:allowed_type); m }
+ end
+
+ def comparison_descriptions
+ description_array = submatcher_comparison_descriptions
+ description_array.empty? ? '' : ' which are ' + submatcher_comparison_descriptions.join(' and ')
+ end
+
+ def submatcher_comparison_descriptions
+ @submatchers.inject([]){|m, s| m << s.comparison_description if s.respond_to?(:comparison_description); m }
end
end
end
@@ -1,10 +1,6 @@
require 'spec_helper'
describe Shoulda::Matchers::ActiveModel::DisallowValueMatcher do
- it 'does not allow any types' do
- expect(matcher('abcde').allowed_types).to eq ''
- end
-
context 'an attribute with a format validation' do
it 'does not match if the value is allowed' do
expect(validating_format(with: /abc/)).not_to matcher('abcde').for(:attr)
@@ -37,6 +37,20 @@
end
end
+ describe '#comparison_description' do
+ [{ operator: :>, value: 0, expectation: 'greater than 0' },
+ { operator: :>=, value: -1.0, expectation: 'greater than or equal to -1.0' },
+ { operator: :==, value: 2.2, expectation: 'equal to 2.2' },
+ { operator: :<, value: -3, expectation: 'less than -3' },
+ { operator: :<=, value: 4, expectation: 'less than or equal to 4' },
+ ].each do |h|
+ context "with :#{h[:operator]} as operator and #{h[:value]} as value" do
+ subject { described_class.new(h[:value], h[:operator]).comparison_description }
+ it { should eq h[:expectation] }
+ end
+ end
+ end
+
def instance_with_validations(options = {})
define_model :example, attr: :string do
validates_numericality_of :attr, options
@@ -0,0 +1,55 @@
+require 'spec_helper'
+
+describe Shoulda::Matchers::ActiveModel::NumericalityMatchers::EvenNumberMatcher do
+ subject { described_class.new(:attr) }
+
+ it_behaves_like 'a numerical submatcher'
+ it_behaves_like 'a numerical type submatcher'
+
+ it 'allows even number' do
+ expect(subject.allowed_type).to eq 'even numbers'
+ end
+
+ context 'when the model has an even validation' do
+ it 'matches' do
+ match = subject
+ expect(validating_even_number).to match
+ end
+ end
+
+ context 'when the model does not have an even validation' do
+ it 'does not match' do
+ match = subject
+ expect(not_validating_even_number).not_to match
+ end
+
+ it 'fails with the ActiveRecord :even message' do
+ match = subject
+ expect {
+ expect(not_validating_even_number).to match
+ }.to fail_with_message_including('Expected errors to include "must be even"')
+ end
+ end
+
+ context 'with custom validation message' do
+ it 'only accepts even number values for that attribute with that message' do
+ expect(validating_even_number(message: 'custom')).to subject.with_message(/custom/)
+ end
+
+ it 'fails even number values for that attribute with another message' do
+ expect(validating_even_number(message: 'custom')).not_to subject.with_message(/wrong/)
+ end
+ end
+
+
+ def validating_even_number(options = {})
+ define_model :example, attr: :string do
+ validates_numericality_of :attr, { even: true }.merge(options)
+ end.new
+ end
+
+ def not_validating_even_number
+ define_model(:example, attr: :string).new
+ end
+
+end
Oops, something went wrong.

0 comments on commit 806716c

Please sign in to comment.