diff --git a/lib/shoulda/matchers/active_model.rb b/lib/shoulda/matchers/active_model.rb
index 8fd6e11d..e77a633c 100644
--- a/lib/shoulda/matchers/active_model.rb
+++ b/lib/shoulda/matchers/active_model.rb
@@ -3,6 +3,7 @@ require 'shoulda/matchers/active_model/validation_matcher'
require 'shoulda/matchers/active_model/allow_value_matcher'
require 'shoulda/matchers/active_model/ensure_length_of_matcher'
require 'shoulda/matchers/active_model/ensure_inclusion_of_matcher'
+require 'shoulda/matchers/active_model/ensure_exclusion_of_matcher'
require 'shoulda/matchers/active_model/validate_presence_of_matcher'
require 'shoulda/matchers/active_model/validate_format_of_matcher'
require 'shoulda/matchers/active_model/validate_uniqueness_of_matcher'
diff --git a/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb b/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb
new file mode 100644
index 00000000..b0456014
--- /dev/null
+++ b/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb
@@ -0,0 +1,70 @@
+module Shoulda # :nodoc:
+ module Matchers
+ module ActiveModel # :nodoc:
+
+ # Ensure that the attribute's value is not in the range specified
+ #
+ # Options:
+ # * 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
+ # translation for :exclusion.
+ #
+ # Example:
+ # it { should ensure_exclusion_of(:age).in_range(30..60) }
+ #
+ def ensure_exclusion_of(attr)
+ EnsureExclusionOfMatcher.new(attr)
+ end
+
+ class EnsureExclusionOfMatcher < ValidationMatcher # :nodoc:
+
+ def in_range(range)
+ @range = range
+ @minimum = range.first
+ @maximum = range.last
+ self
+ end
+
+ def with_message(message)
+ @expected_message = message if message
+ self
+ end
+
+ def description
+ "ensure exclusion of #{@attribute} in #{@range.inspect}"
+ end
+
+ def matches?(subject)
+ super(subject)
+
+ @expected_message ||= :exclusion
+
+ allows_lower_value &&
+ disallows_minimum_value &&
+ allows_higher_value &&
+ disallows_maximum_value
+ end
+
+ private
+
+ def allows_lower_value
+ @minimum == 0 || allows_value_of(@minimum - 1, @expected_message)
+ end
+
+ def allows_higher_value
+ allows_value_of(@maximum + 1, @expected_message)
+ end
+
+ def disallows_minimum_value
+ disallows_value_of(@minimum, @expected_message)
+ end
+
+ def disallows_maximum_value
+ disallows_value_of(@maximum, @expected_message)
+ end
+ end
+
+ end
+ end
+end
diff --git a/spec/shoulda/active_model/ensure_exclusion_of_matcher_spec.rb b/spec/shoulda/active_model/ensure_exclusion_of_matcher_spec.rb
new file mode 100644
index 00000000..f3e17ac4
--- /dev/null
+++ b/spec/shoulda/active_model/ensure_exclusion_of_matcher_spec.rb
@@ -0,0 +1,57 @@
+require 'spec_helper'
+
+describe Shoulda::Matchers::ActiveModel::EnsureExclusionOfMatcher do
+
+ context "an attribute which must be excluded of a range" do
+ before do
+ @model = define_model(:example, :attr => :integer) do
+ validates_exclusion_of :attr, :in => 2..5
+ end.new
+ end
+
+ it "should accept ensuring the correct range" do
+ @model.should ensure_exclusion_of(:attr).in_range(2..5)
+ end
+
+ it "should reject ensuring excluded value" do
+ @model.should_not ensure_exclusion_of(:attr).in_range(2..6)
+ end
+
+ it "should not override the default message with a blank" do
+ @model.should ensure_exclusion_of(:attr).in_range(2..5).with_message(nil)
+ end
+ end
+
+ context "an attribute with a custom ranged value validation" do
+ before do
+ @model = define_model(:example, :attr => :string) do
+ validates_exclusion_of :attr, :in => 2..4, :message => 'not good'
+
+ end.new
+ end
+
+ it "should accept ensuring the correct range" do
+ @model.should ensure_exclusion_of(:attr).in_range(2..4).with_message(/not good/)
+ end
+ end
+
+ context "an attribute with custom range validations" do
+ before do
+ define_model :example, :attr => :integer do
+ validate :custom_validation
+ def custom_validation
+ if attr >= 2 && attr <= 5
+ errors.add(:attr, 'shoud be out of this range')
+ end
+ end
+ end
+ @model = Example.new
+ end
+
+ 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
+
+end