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