diff --git a/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb b/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb index aaa2bcc2..c972977b 100644 --- a/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb +++ b/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb @@ -5,6 +5,7 @@ module Shoulda # :nodoc: # Ensure that the attribute's value is not in the range specified # # Options: + # * in_array - the array of not allowed values for this attribute # * in_range - the range of not allowed values for this attribute # * with_message - value the test expects to find in # errors.on(:attribute). Regexp or string. Defaults to the @@ -18,6 +19,10 @@ module Shoulda # :nodoc: end class EnsureExclusionOfMatcher < ValidationMatcher # :nodoc: + def in_array(array) + @array = array + self + end def in_range(range) @range = range @@ -32,20 +37,30 @@ module Shoulda # :nodoc: end def description - "ensure exclusion of #{@attribute} in #{@range.inspect}" + "ensure exclusion of #{@attribute} in #{inspect_message}" end def matches?(subject) super(subject) - allows_lower_value && - disallows_minimum_value && - allows_higher_value && - disallows_maximum_value + if @range + allows_lower_value && + disallows_minimum_value && + allows_higher_value && + disallows_maximum_value + elsif @array + disallows_all_values_in_array? + end end private + def disallows_all_values_in_array? + @array.all? do |value| + disallows_value_of(value, expected_message) + end + end + def allows_lower_value @minimum == 0 || allows_value_of(@minimum - 1, expected_message) end @@ -65,8 +80,15 @@ module Shoulda # :nodoc: def expected_message @expected_message || :exclusion end - end + def inspect_message + if @range + @range.inspect + else + @array.inspect + end + end + end end end end diff --git a/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb b/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb index f4151b52..cc0d2712 100644 --- a/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +++ b/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb @@ -5,7 +5,7 @@ module Shoulda # :nodoc: # Ensure that the attribute's value is in the range specified # # Options: - # * in_array - the range of allowed values for this attribute + # * in_array - the array of allowed values for this attribute # * in_range - the range of allowed values for this attribute # * with_low_message - value the test expects to find in # errors.on(:attribute). Regexp or string. Defaults to the diff --git a/spec/shoulda/active_model/ensure_exclusion_of_matcher_spec.rb b/spec/shoulda/active_model/ensure_exclusion_of_matcher_spec.rb index f3e17ac4..4c450fdb 100644 --- a/spec/shoulda/active_model/ensure_exclusion_of_matcher_spec.rb +++ b/spec/shoulda/active_model/ensure_exclusion_of_matcher_spec.rb @@ -51,7 +51,29 @@ describe Shoulda::Matchers::ActiveModel::EnsureExclusionOfMatcher do it "should accept ensuring the correct range and messages" do @model.should ensure_exclusion_of(:attr).in_range(2..5).with_message(/shoud be out of this range/) end - end + context "an attribute which must be excluded in an array" do + before do + @model = define_model(:example, :attr => :string) do + validates_exclusion_of :attr, :in => %w(one two) + end.new + end + + it "accepts with correct array" do + @model.should ensure_exclusion_of(:attr).in_array(%w(one two)) + end + + it "rejects when only part of array matches" do + @model.should_not ensure_exclusion_of(:attr).in_array(%w(one wrong_value)) + end + + it "rejects when array doesn't match at all" do + @model.should_not ensure_exclusion_of(:attr).in_array(%w(cat dog)) + end + + it "has correct description" do + ensure_exclusion_of(:attr).in_array([true, 'dog']).description.should == 'ensure exclusion of attr in [true, "dog"]' + end + end end