Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Numerical matchers #244

Closed
1 change: 1 addition & 0 deletions lib/shoulda/matchers/active_model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
require 'shoulda/matchers/active_model/allow_value_matcher'
require 'shoulda/matchers/active_model/disallow_value_matcher'
require 'shoulda/matchers/active_model/only_integer_matcher'
require 'shoulda/matchers/active_model/comparison_matcher'
require 'shoulda/matchers/active_model/odd_even_number_matcher'
require 'shoulda/matchers/active_model/ensure_length_of_matcher'
require 'shoulda/matchers/active_model/ensure_inclusion_of_matcher'
Expand Down
52 changes: 52 additions & 0 deletions lib/shoulda/matchers/active_model/comparison_matcher.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
module Shoulda # :nodoc:
module Matchers
module ActiveModel # :nodoc:
# Examples:
# it { should validate_numericality_of(:attr).
# is_greater_than(6).
# less_than(20)...(and so on) }
class ComparisonMatcher < ValidationMatcher
def initialize(value, operator)
@value = value
@operator = operator
end

def for(attribute)
@attribute = attribute
self
end

def matches?(subject)
@subject = subject
disallows_value_of(value_to_compare)
end

def allowed_types
'integer'
end

private

def value_to_compare
case @operator
when :> then [@value, @value - 1].sample
when :>= then @value - 1
when :== then @value
when :< then [@value, @value + 1].sample
when :<= then @value + 1
end
end

def expectation
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
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,32 @@ def initialize(attribute)
end

def only_integer
only_integer_matcher = OnlyIntegerMatcher.new(@attribute)
add_submatcher(only_integer_matcher)
add_submatcher(OnlyIntegerMatcher.new(@attribute))
self
end

def is_greater_than(value)
add_submatcher(ComparisonMatcher.new(value, :>).for(@attribute))
self
end

def is_greater_than_or_equal_to(value)
add_submatcher(ComparisonMatcher.new(value, :>=).for(@attribute))
self
end

def is_equal_to(value)
add_submatcher(ComparisonMatcher.new(value, :==).for(@attribute))
self
end

def is_less_than(value)
add_submatcher(ComparisonMatcher.new(value, :<).for(@attribute))
self
end

def is_less_than_or_equal_to(value)
add_submatcher(ComparisonMatcher.new(value, :<=).for(@attribute))
self
end

Expand Down Expand Up @@ -98,7 +122,7 @@ def submatcher_failure_messages_for_should_not
end

def failing_submatchers
@failing_submatchers ||= @submatchers.select { |matcher| !matcher.matches?(@subject) }
@failing_submatchers ||= @submatchers.select { |matcher| !matcher.matches?(@subject.dup) }
end

def allowed_types
Expand Down
40 changes: 40 additions & 0 deletions spec/shoulda/matchers/active_model/comparison_matcher_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
require 'spec_helper'

describe Shoulda::Matchers::ActiveModel::ComparisonMatcher do
context 'is_greater_than' do
it { instance_with_validations(:greater_than => 2).should matcher.is_greater_than(2) }
it { instance_without_validations.should_not matcher.is_greater_than(2) }
end

context 'greater_than_or_equal_to' do
it { instance_with_validations(:greater_than_or_equal_to => 2).should matcher.is_greater_than_or_equal_to(2) }
it { instance_without_validations.should_not matcher.is_greater_than_or_equal_to(2) }
end

context 'less_than' do
it { instance_with_validations(:less_than => 2).should matcher.is_less_than(2) }
it { instance_without_validations.should_not matcher.is_less_than(2) }
end

context 'less_than_or_equal_to' do
it { instance_with_validations(:less_than_or_equal_to => 2).should matcher.is_less_than_or_equal_to(2) }
it { instance_without_validations.should_not matcher.is_less_than_or_equal_to(2) }
end

def instance_with_validations(options = {})
define_model :example, :attr => :string do
validates_numericality_of :attr, options
attr_accessible :attr
end.new
end

def instance_without_validations
define_model :example, :attr => :string do
attr_accessible :attr
end.new
end

def matcher
validate_numericality_of(:attr)
end
end