2014-01-23 18:07:36 +00:00
|
|
|
module Shoulda
|
2013-11-01 21:57:42 +00:00
|
|
|
module Matchers
|
2014-01-23 18:07:36 +00:00
|
|
|
module ActiveModel
|
2013-11-01 21:57:42 +00:00
|
|
|
module NumericalityMatchers
|
2014-01-23 18:07:36 +00:00
|
|
|
# @private
|
2013-11-01 21:57:42 +00:00
|
|
|
class ComparisonMatcher < ValidationMatcher
|
2014-04-26 15:17:25 +00:00
|
|
|
ERROR_MESSAGES = {
|
|
|
|
:> => :greater_than,
|
|
|
|
:>= => :greater_than_or_equal_to,
|
|
|
|
:< => :less_than,
|
|
|
|
:<= => :less_than_or_equal_to,
|
|
|
|
:== => :equal_to
|
|
|
|
}
|
2014-04-15 21:16:01 +00:00
|
|
|
|
2014-02-27 03:26:37 +00:00
|
|
|
def initialize(numericality_matcher, value, operator)
|
2015-12-13 23:45:24 +00:00
|
|
|
super(nil)
|
2014-02-27 03:26:37 +00:00
|
|
|
unless numericality_matcher.respond_to? :diff_to_compare
|
|
|
|
raise ArgumentError, 'numericality_matcher is invalid'
|
|
|
|
end
|
|
|
|
@numericality_matcher = numericality_matcher
|
2013-11-01 21:57:42 +00:00
|
|
|
@value = value
|
|
|
|
@operator = operator
|
2014-04-26 15:17:25 +00:00
|
|
|
@message = ERROR_MESSAGES[operator]
|
2013-11-01 21:57:42 +00:00
|
|
|
end
|
|
|
|
|
2015-12-13 23:45:24 +00:00
|
|
|
def simple_description
|
|
|
|
description = ''
|
2015-09-24 22:49:58 +00:00
|
|
|
|
2015-12-13 23:45:24 +00:00
|
|
|
if expects_strict?
|
|
|
|
description << ' strictly'
|
2015-09-24 22:49:58 +00:00
|
|
|
end
|
|
|
|
|
2015-12-13 23:45:24 +00:00
|
|
|
description +
|
|
|
|
"disallow :#{attribute} from being a number that is not " +
|
|
|
|
"#{comparison_expectation} #{@value}"
|
2015-09-24 22:49:58 +00:00
|
|
|
end
|
|
|
|
|
2013-11-01 21:57:42 +00:00
|
|
|
def for(attribute)
|
|
|
|
@attribute = attribute
|
|
|
|
self
|
|
|
|
end
|
|
|
|
|
|
|
|
def with_message(message)
|
2015-12-13 23:45:24 +00:00
|
|
|
@expects_custom_validation_message = true
|
2013-11-01 21:57:42 +00:00
|
|
|
@message = message
|
2015-09-24 22:49:58 +00:00
|
|
|
self
|
2013-11-01 21:57:42 +00:00
|
|
|
end
|
|
|
|
|
2015-12-13 23:45:24 +00:00
|
|
|
def expects_custom_validation_message?
|
|
|
|
@expects_custom_validation_message
|
|
|
|
end
|
|
|
|
|
2015-09-24 22:49:58 +00:00
|
|
|
def matches?(subject)
|
|
|
|
@subject = subject
|
|
|
|
all_bounds_correct?
|
2014-01-13 01:43:36 +00:00
|
|
|
end
|
|
|
|
|
2015-01-23 01:47:43 +00:00
|
|
|
def failure_message
|
|
|
|
last_failing_submatcher.failure_message
|
|
|
|
end
|
|
|
|
|
|
|
|
def failure_message_when_negated
|
|
|
|
last_failing_submatcher.failure_message_when_negated
|
|
|
|
end
|
|
|
|
|
2015-09-24 22:49:58 +00:00
|
|
|
def comparison_description
|
|
|
|
"#{comparison_expectation} #{@value}"
|
|
|
|
end
|
|
|
|
|
2013-11-01 21:57:42 +00:00
|
|
|
private
|
|
|
|
|
2015-01-23 01:47:43 +00:00
|
|
|
def all_bounds_correct?
|
|
|
|
failing_submatchers.empty?
|
|
|
|
end
|
|
|
|
|
|
|
|
def failing_submatchers
|
|
|
|
submatchers_and_results.
|
|
|
|
select { |x| !x[:matched] }.
|
|
|
|
map { |x| x[:matcher] }
|
|
|
|
end
|
|
|
|
|
|
|
|
def last_failing_submatcher
|
|
|
|
failing_submatchers.last
|
|
|
|
end
|
|
|
|
|
|
|
|
def submatchers
|
|
|
|
@_submatchers ||=
|
|
|
|
comparison_combos.map do |diff, submatcher_method_name|
|
2015-10-07 05:12:30 +00:00
|
|
|
matcher = __send__(submatcher_method_name, diff, nil)
|
2015-01-23 01:47:43 +00:00
|
|
|
matcher.with_message(@message, values: { count: @value })
|
|
|
|
matcher
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def submatchers_and_results
|
|
|
|
@_submatchers_and_results ||=
|
|
|
|
submatchers.map do |matcher|
|
|
|
|
{ matcher: matcher, matched: matcher.matches?(@subject) }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-02-27 03:26:37 +00:00
|
|
|
def comparison_combos
|
2015-01-23 01:47:43 +00:00
|
|
|
diffs_to_compare.zip(submatcher_method_names)
|
|
|
|
end
|
|
|
|
|
|
|
|
def submatcher_method_names
|
|
|
|
assertions.map do |value|
|
|
|
|
if value
|
|
|
|
:allow_value_matcher
|
|
|
|
else
|
|
|
|
:disallow_value_matcher
|
2014-02-27 03:26:37 +00:00
|
|
|
end
|
2015-01-23 01:47:43 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def assertions
|
|
|
|
case @operator
|
2015-01-21 22:46:26 +00:00
|
|
|
when :>
|
|
|
|
[false, false, true]
|
|
|
|
when :>=
|
|
|
|
[false, true, true]
|
|
|
|
when :==
|
|
|
|
[false, true, false]
|
|
|
|
when :<
|
|
|
|
[true, false, false]
|
|
|
|
when :<=
|
|
|
|
[true, true, false]
|
2015-01-23 01:47:43 +00:00
|
|
|
end
|
2014-02-27 03:26:37 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def diffs_to_compare
|
2015-10-07 05:12:30 +00:00
|
|
|
diff_to_compare = @numericality_matcher.diff_to_compare
|
|
|
|
values = [-1, 0, 1].map { |sign| @value + (diff_to_compare * sign) }
|
|
|
|
|
|
|
|
if @numericality_matcher.given_numeric_column?
|
|
|
|
values
|
|
|
|
else
|
|
|
|
values.map(&:to_s)
|
|
|
|
end
|
2013-11-01 21:57:42 +00:00
|
|
|
end
|
|
|
|
|
2015-09-24 22:49:58 +00:00
|
|
|
def comparison_expectation
|
2013-11-01 21:57:42 +00:00
|
|
|
case @operator
|
|
|
|
when :> then "greater than"
|
|
|
|
when :>= then "greater than or equal to"
|
|
|
|
when :== then "equal to"
|
|
|
|
when :< then "less than"
|
|
|
|
when :<= then "less than or equal to"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|