<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -1,5 +1,10 @@
 *Edge*
 
+* Add :tokenizer option to validates_length_of to specify how to split up the attribute string. #507. [David Lowenfels] Example :
+
+  # Ensure essay contains at least 100 words.
+  validates_length_of :essay, :minimum =&gt; 100, :too_short =&gt; &quot;Your essay must be at least %d words.&quot;), :tokenizer =&gt; lambda {|str| str.scan(/\w+/) }
+
 * Allow conditions on multiple tables to be specified using hash. [Pratik Naik]. Example:
 
   User.all :joins =&gt; :items, :conditions =&gt; { :age =&gt; 10, :items =&gt; { :color =&gt; 'black' } }</diff>
      <filename>activerecord/CHANGELOG</filename>
    </modified>
    <modified>
      <diff>@@ -479,8 +479,9 @@ module ActiveRecord
       #     validates_length_of :fax, :in =&gt; 7..32, :allow_nil =&gt; true
       #     validates_length_of :phone, :in =&gt; 7..32, :allow_blank =&gt; true
       #     validates_length_of :user_name, :within =&gt; 6..20, :too_long =&gt; &quot;pick a shorter name&quot;, :too_short =&gt; &quot;pick a longer name&quot;
-      #     validates_length_of :fav_bra_size, :minimum=&gt;1, :too_short=&gt;&quot;please enter at least %d character&quot;
-      #     validates_length_of :smurf_leader, :is=&gt;4, :message=&gt;&quot;papa is spelled with %d characters... don't play me.&quot;
+      #     validates_length_of :fav_bra_size, :minimum =&gt; 1, :too_short =&gt; &quot;please enter at least %d character&quot;
+      #     validates_length_of :smurf_leader, :is =&gt; 4, :message =&gt; &quot;papa is spelled with %d characters... don't play me.&quot;
+      #     validates_length_of :essay, :minimum =&gt; 100, :too_short =&gt; &quot;Your essay must be at least %d words.&quot;), :tokenizer =&gt; lambda {|str| str.scan(/\w+/) }
       #   end
       #
       # Configuration options:
@@ -491,7 +492,6 @@ module ActiveRecord
       # * &lt;tt&gt;:in&lt;/tt&gt; - A synonym(or alias) for &lt;tt&gt;:within&lt;/tt&gt;.
       # * &lt;tt&gt;:allow_nil&lt;/tt&gt; - Attribute may be +nil+; skip validation.
       # * &lt;tt&gt;:allow_blank&lt;/tt&gt; - Attribute may be blank; skip validation.
-      #
       # * &lt;tt&gt;:too_long&lt;/tt&gt; - The error message if the attribute goes over the maximum (default is: &quot;is too long (maximum is %d characters)&quot;).
       # * &lt;tt&gt;:too_short&lt;/tt&gt; - The error message if the attribute goes under the minimum (default is: &quot;is too short (min is %d characters)&quot;).
       # * &lt;tt&gt;:wrong_length&lt;/tt&gt; - The error message if using the &lt;tt&gt;:is&lt;/tt&gt; method and the attribute is the wrong size (default is: &quot;is the wrong length (should be %d characters)&quot;).
@@ -503,12 +503,16 @@ module ActiveRecord
       # * &lt;tt&gt;:unless&lt;/tt&gt; - Specifies a method, proc or string to call to determine if the validation should
       #   not occur (e.g. &lt;tt&gt;:unless =&gt; :skip_validation&lt;/tt&gt;, or &lt;tt&gt;:unless =&gt; Proc.new { |user| user.signup_step &lt;= 2 }&lt;/tt&gt;).  The
       #   method, proc or string should return or evaluate to a true or false value.
+      # * &lt;tt&gt;:tokenizer&lt;/tt&gt; - Specifies how to split up the attribute string. (e.g. &lt;tt&gt;:tokenizer =&gt; lambda {|str| str.scan(/\w+/)}&lt;/tt&gt; to
+      #   count words as in above example.)
+      #   Defaults to &lt;tt&gt;lambda{ |value| value.split(//) }&lt;/tt&gt; which counts individual characters.
       def validates_length_of(*attrs)
         # Merge given options with defaults.
         options = {
           :too_long     =&gt; ActiveRecord::Errors.default_error_messages[:too_long],
           :too_short    =&gt; ActiveRecord::Errors.default_error_messages[:too_short],
-          :wrong_length =&gt; ActiveRecord::Errors.default_error_messages[:wrong_length]
+          :wrong_length =&gt; ActiveRecord::Errors.default_error_messages[:wrong_length],
+          :tokenizer    =&gt; lambda {|value| value.split(//)}
         }.merge(DEFAULT_VALIDATION_OPTIONS)
         options.update(attrs.extract_options!.symbolize_keys)
 
@@ -535,7 +539,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 = options[:tokenizer].call(value) if value.kind_of?(String)
               if value.nil? or value.size &lt; option_value.begin
                 record.errors.add(attr, too_short)
               elsif value.size &gt; option_value.end
@@ -552,7 +556,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 = options[:tokenizer].call(value) 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>
      <filename>activerecord/lib/active_record/validations.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1059,6 +1059,18 @@ class ValidationsTest &lt; ActiveRecord::TestCase
     end
   end
 
+  def test_validates_length_of_with_block
+    Topic.validates_length_of :content, :minimum =&gt; 5, :too_short=&gt;&quot;Your essay must be at least %d words.&quot;, 
+                                        :tokenizer =&gt; lambda {|str| str.scan(/\w+/) }
+    t = Topic.create!(:content =&gt; &quot;this content should be long enough&quot;)
+    assert t.valid?
+
+    t.content = &quot;not long enough&quot;
+    assert !t.valid?
+    assert t.errors.on(:content)
+    assert_equal &quot;Your essay must be at least 5 words.&quot;, t.errors[:content]
+  end
+
   def test_validates_size_of_association_utf8
     with_kcode('UTF8') do
       assert_nothing_raised { Topic.validates_size_of :replies, :minimum =&gt; 1 }</diff>
      <filename>activerecord/test/cases/validations_test.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>570f5aad663fa3113772cf56306862829babc739</id>
    </parent>
  </parents>
  <author>
    <name>David Lowenfels</name>
    <login>dfl</login>
    <email>david@internautdesign.com</email>
  </author>
  <url>http://github.com/rails/rails/commit/87fbcaa6229e9073095fb8d77c7a536c9466fbce</url>
  <id>87fbcaa6229e9073095fb8d77c7a536c9466fbce</id>
  <committed-date>2008-07-03T17:31:39-07:00</committed-date>
  <authored-date>2008-06-28T17:41:12-07:00</authored-date>
  <message>Add :tokenizer option to validates_length_of. [#507 state:resolved]

Signed-off-by: Pratik Naik &lt;pratiknaik@gmail.com&gt;</message>
  <tree>93ad434fdfc2be549da65ad4d167b5d9c4859802</tree>
  <committer>
    <name>Pratik Naik</name>
    <login>lifo</login>
    <email>pratiknaik@gmail.com</email>
  </committer>
</commit>
