module Remarkable
module MongoMapper
module Matchers
class ValidateLengthOfMatcher < Remarkable::MongoMapper::Base #:nodoc:
arguments :collection => :attributes, :as => :attribute
optional :within, :minimum, :maximum, :is
optional :allow_nil, :allow_blank, :default => true
optional :message
default_options :message => "is invalid"
collection_assertions :less_than_min_length?, :exactly_min_length?,
:more_than_max_length?, :exactly_max_length?,
:allow_nil?, :allow_blank?
before_assert do
if @options[:is]
@min_value, @max_value = @options[:is], @options[:is]
elsif @options[:within]
@min_value, @max_value = @options[:within].first, @options[:within].last
elsif @options[:maximum]
@min_value, @max_value = nil, @options[:maximum]
elsif @options[:minimum]
@min_value, @max_value = @options[:minimum], nil
end
end
protected
def allow_nil?
super(default_message_for(:too_short))
end
def allow_blank?
super(default_message_for(:too_short))
end
def less_than_min_length?
@min_value.nil? || @min_value <= 1 || bad?(@min_value - 1, default_message_for(:too_short))
end
def exactly_min_length?
@min_value.nil? || @min_value <= 0 || good?(@min_value, default_message_for(:too_short))
end
def more_than_max_length?
@max_value.nil? || bad?(@max_value + 1, default_message_for(:too_long))
end
def exactly_max_length?
@max_value.nil? || @min_value == @max_value || good?(@max_value, default_message_for(:too_long))
end
def interpolation_options
{ :minimum => @min_value, :maximum => @max_value }
end
# Returns the default message for the validation type.
# If user supplied :message, it will return it. Otherwise it will return
# wrong_length on :is validation and :too_short or :too_long in the other
# types.
#
def default_message_for(validation_type)
return :message if @options[:message]
end
end
# Validates the length of the given attributes. You have also to supply
# one of the following options: minimum, maximum, is or within.
#
# Note: this method is also aliased as validate_size_of.
#
# == Options
#
# * :minimum - The minimum size of the attribute.
# * :maximum - The maximum size of the attribute.
# * :is - The exact size of the attribute.
# * :within - A range specifying the minimum and maximum size of the attribute.
# * :allow_nil - when supplied, validates if it allows nil or not.
# * :allow_blank - when supplied, validates if it allows blank or not.
# * :message - value the test expects to find in errors.on(:attribute).
# Regexp, string or symbol. Default = "is invalid"
#
# == Examples
#
# it { should validate_length_of(:password).within(6..20) }
# it { should validate_length_of(:password).maximum(20) }
# it { should validate_length_of(:password).minimum(6) }
# it { should validate_length_of(:age).is(18) }
#
# should_validate_length_of :password, :within => 6..20
# should_validate_length_of :password, :maximum => 20
# should_validate_length_of :password, :minimum => 6
# should_validate_length_of :age, :is => 18
#
# should_validate_length_of :password do |m|
# m.minimum 6
# m.maximum 20
# end
#
def validate_length_of(*attributes, &block)
ValidateLengthOfMatcher.new(*attributes, &block).spec(self)
end
end
end
end