From b32b298d79c9f0de98395e6fc1a303f992491d7c Mon Sep 17 00:00:00 2001 From: David Lowenfels Date: Sat, 14 Jun 2008 22:15:15 -0700 Subject: [PATCH] added :count=>:words to validates_length_of --- activerecord/lib/active_record/validations.rb | 24 ++++++++++++++++++++---- activerecord/test/cases/validations_test.rb | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index c4e370d..6322bfa 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -291,7 +291,8 @@ module ActiveRecord :on => :save, :allow_nil => false, :allow_blank => false, - :message => nil + :message => nil, + :count => :chars }.freeze ALL_RANGE_OPTIONS = [ :is, :within, :in, :minimum, :maximum ].freeze @@ -481,6 +482,7 @@ module ActiveRecord # validates_length_of :user_name, :within => 6..20, :too_long => "pick a shorter name", :too_short => "pick a longer name" # validates_length_of :fav_bra_size, :minimum=>1, :too_short=>"please enter at least %d character" # validates_length_of :smurf_leader, :is=>4, :message=>"papa is spelled with %d characters... don't play me." + # validates_length_of :essay, :minimum=200, :count=>:words, :too_short=>"Your essay must be at least %d words." # end # # Configuration options: @@ -489,6 +491,7 @@ module ActiveRecord # * :is - The exact size of the attribute. # * :within - A range specifying the minimum and maximum size of the attribute. # * :in - A synonym(or alias) for :within. + # * :count - Specifies whether to count :chars (default) or :words # * :allow_nil - Attribute may be +nil+; skip validation. # * :allow_blank - Attribute may be blank; skip validation. # @@ -523,10 +526,23 @@ module ActiveRecord raise ArgumentError, 'Too many range options specified. Choose only one.' end + ## check for :count_words => true, which makes length go for words instead of chars + case options[:count] + when :chars + split_token = '' + when :words + split_token = '\W' + [ :too_long, :too_short, :wrong_length ].each do |a| + options[a].gsub!('character','word') + end + else + raise ArgumentError, ":count must be either :chars or :words (:#{options[:count]} is unknown)" + end + # Get range option and value. option = range_options.first option_value = options[range_options.first] - + case option when :within, :in raise ArgumentError, ":#{option} must be a Range" unless option_value.is_a?(Range) @@ -535,7 +551,7 @@ module ActiveRecord too_long = options[:too_long] % option_value.end validates_each(attrs, options) do |record, attr, value| - value = value.split(//) if value.kind_of?(String) + value = value.split(/#{split_token}/) if value.kind_of?(String) if value.nil? or value.size < option_value.begin record.errors.add(attr, too_short) elsif value.size > option_value.end @@ -552,7 +568,7 @@ module ActiveRecord message = (options[:message] || options[message_options[option]]) % option_value validates_each(attrs, options) do |record, attr, value| - value = value.split(//) if value.kind_of?(String) + value = value.split(/#{split_token}/) if value.kind_of?(String) record.errors.add(attr, message) unless !value.nil? and value.size.method(validity_checks[option])[option_value] end end diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb index 7b71647..39928c8 100755 --- a/activerecord/test/cases/validations_test.rb +++ b/activerecord/test/cases/validations_test.rb @@ -644,6 +644,26 @@ class ValidationsTest < ActiveRecord::TestCase assert Topic.create("title" => "abcde").valid? end + def test_validates_length_of_with_word_count_is + Topic.validates_length_of( :title, :is => 5, :count => :words ) + + assert !Topic.create("title" => "this title has too many words").valid? + assert !Topic.create("title" => "too little").valid? + assert Topic.create("title" => "this title has just enough").valid? + end + + def test_validates_length_of_with_word_count_within + Topic.validates_length_of( :title, :within => 3..5, :count => :words ) + + t = Topic.new( :title => "not enough") + assert !t.valid? + assert_equal "is too short (minimum is 3 words)", t.errors.on(:title) + + t = Topic.new( :title => "this title has too many words") + assert !t.valid? + assert_equal "is too long (maximum is 5 words)", t.errors.on(:title) + end + def test_validates_inclusion_of_with_formatted_message Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :message => "option %s is not in the list" ) -- 1.5.3.6