Skip to content

Commit

Permalink
Add #on qualifier to numericality matcher
Browse files Browse the repository at this point in the history
This is present in all other matchers through ValidationMatcher.
However, ValidateNumericalityOfMatcher does not inherit from
ValidationMatcher. (This happens to be okay, since
ValidateNumericalityOfMatcher contains submatchers and we have to make
sure to pass the context all the way through.)

Hat tip @sj26 for most of the content of this commit, as well as
@anujbiyani for another approach to this.
  • Loading branch information
mcmire committed Apr 4, 2015
1 parent aab1aa5 commit 9748869
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 1 deletion.
4 changes: 4 additions & 0 deletions NEWS.md
Expand Up @@ -70,6 +70,8 @@

* Add `strict` qualifier to `validate_numericality_of`. ([#620])

* Add `on` qualifier to `validate_numericality_of`. (h/t [#356], [#358])

[#402]: https://github.com/thoughtbot/shoulda-matchers/pull/402
[#587]: https://github.com/thoughtbot/shoulda-matchers/pull/587
[#662]: https://github.com/thoughtbot/shoulda-matchers/pull/662
Expand All @@ -82,6 +84,8 @@
[#677]: https://github.com/thoughtbot/shoulda-matchers/pull/677
[#620]: https://github.com/thoughtbot/shoulda-matchers/pull/620
[#693]: https://github.com/thoughtbot/shoulda-matchers/pull/693
[#356]: https://github.com/thoughtbot/shoulda-matchers/pull/356
[#358]: https://github.com/thoughtbot/shoulda-matchers/pull/358

# 2.8.0

Expand Down
Expand Up @@ -22,6 +22,11 @@ def strict
self
end

def on(context)
@disallow_value_matcher.on(context)
self
end

def allowed_type
raise NotImplementedError
end
Expand Down
Expand Up @@ -384,6 +384,11 @@ def with_message(message)
self
end

def on(context)
@submatchers.each { |matcher| matcher.on(context) }
self
end

def matches?(subject)
@subject = subject
failing_submatchers.empty?
Expand Down
Expand Up @@ -197,6 +197,26 @@ def matcher_qualifier
end
end

context 'qualified with on and validating with on' do
it 'accepts' do
expect(instance_with_validations(on: :customizable)).
to matcher.on(:customizable)
end
end

context 'qualified with on but not validating with on' do
it 'accepts since the validation never considers a context' do
expect(instance_with_validations).to matcher.on(:customizable)
end
end

context 'not qualified with on but validating with on' do
it 'rejects since the validation never runs' do
expect(instance_with_validations(on: :customizable)).
not_to matcher
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' },
Expand Down
Expand Up @@ -64,6 +64,26 @@
end
end

context 'qualified with on and validating with on' do
it 'accepts' do
expect(validating_even_number(on: :customizable)).
to subject.on(:customizable)
end
end

context 'qualified with on but not validating with on' do
it 'accepts since the validation never considers a context' do
expect(validating_even_number).to subject.on(:customizable)
end
end

context 'not qualified with on but validating with on' do
it 'rejects since the validation never runs' do
expect(validating_even_number(on: :customizable)).
not_to subject
end
end

def validating_even_number(options = {})
define_model :example, attr: :string do
validates_numericality_of :attr, { even: true }.merge(options)
Expand Down
Expand Up @@ -64,6 +64,26 @@
end
end

context 'qualified with on and validating with on' do
it 'accepts' do
expect(validating_odd_number(on: :customizable)).
to subject.on(:customizable)
end
end

context 'qualified with on but not validating with on' do
it 'accepts since the validation never considers a context' do
expect(validating_odd_number).to subject.on(:customizable)
end
end

context 'not qualified with on but validating with on' do
it 'rejects since the validation never runs' do
expect(validating_odd_number(on: :customizable)).
not_to subject
end
end

def validating_odd_number(options = {})
define_model :example, attr: :string do
validates_numericality_of :attr, { odd: true }.merge(options)
Expand Down
Expand Up @@ -64,6 +64,26 @@
end
end

context 'qualified with on and validating with on' do
it 'accepts' do
expect(validating_only_integer(on: :customizable)).
to subject.on(:customizable)
end
end

context 'qualified with on but not validating with on' do
it 'accepts since the validation never considers a context' do
expect(validating_only_integer).to subject.on(:customizable)
end
end

context 'not qualified with on but validating with on' do
it 'rejects since the validation never runs' do
expect(validating_only_integer(on: :customizable)).
not_to subject
end
end

def validating_only_integer(options = {})
define_model :example, attr: :string do
validates_numericality_of :attr, { only_integer: true }.merge(options)
Expand Down
Expand Up @@ -55,6 +55,12 @@ def all_qualifiers
name: :only_integer,
validation_name: :only_integer,
validation_value: true,
},
{
name: :on,
argument: :customizable,
validation_name: :on,
validation_value: :customizable
}
]
end
Expand Down Expand Up @@ -454,6 +460,32 @@ def default_validation_values
end
end

context 'qualified with on and validating with on' do
it 'accepts' do
record = build_record_validating_numericality(on: :customizable)
expect(record).to validate_numericality.on(:customizable)
end
end

context 'qualified with on but not validating with on' do
it 'accepts since the validation never considers a context' do
record = build_record_validating_numericality
expect(record).to validate_numericality.on(:customizable)
end
end

context 'not qualified with on but validating with on' do
it 'rejects since the validation never runs' do
record = build_record_validating_numericality(on: :customizable)
assertion = lambda do
expect(record).to validate_numericality
end
expect(&assertion).to fail_with_message_including(
'Expected errors to include "is not a number"'
)
end
end

context 'with combinations of qualifiers together' do
all_qualifier_combinations.each do |combination|
if combination.size > 1
Expand Down Expand Up @@ -778,7 +810,8 @@ def apply_qualifiers!(args)
end

def define_model_validating_numericality(options = {})
attribute_name = options.fetch(:attribute_name) { self.attribute_name }
attribute_name = options.delete(:attribute_name) { self.attribute_name }

define_model 'Example', attribute_name => :string do |model|
model.validates_numericality_of(attribute_name, options)
end
Expand Down

0 comments on commit 9748869

Please sign in to comment.