durran-validatable 1.7.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +118 -0
 - data/Rakefile +55 -0
 - data/VERSION.yml +4 -0
 - data/lib/child_validation.rb +15 -0
 - data/lib/errors.rb +90 -0
 - data/lib/included_validation.rb +9 -0
 - data/lib/macros.rb +306 -0
 - data/lib/object_extension.rb +21 -0
 - data/lib/requireable.rb +26 -0
 - data/lib/understandable.rb +31 -0
 - data/lib/validatable.rb +25 -0
 - data/lib/validatable_class_methods.rb +85 -0
 - data/lib/validatable_instance_methods.rb +116 -0
 - data/lib/validations/validates_acceptance_of.rb +14 -0
 - data/lib/validations/validates_associated.rb +13 -0
 - data/lib/validations/validates_confirmation_of.rb +23 -0
 - data/lib/validations/validates_each.rb +14 -0
 - data/lib/validations/validates_format_of.rb +16 -0
 - data/lib/validations/validates_length_of.rb +30 -0
 - data/lib/validations/validates_numericality_of.rb +27 -0
 - data/lib/validations/validates_presence_of.rb +17 -0
 - data/lib/validations/validates_true_for.rb +13 -0
 - data/lib/validations/validation_base.rb +91 -0
 - data/test/all_tests.rb +1 -0
 - data/test/functional/test_validatable.rb +589 -0
 - data/test/functional/test_validates_acceptance_of.rb +16 -0
 - data/test/functional/test_validates_associated.rb +41 -0
 - data/test/functional/test_validates_confirmation_of.rb +56 -0
 - data/test/functional/test_validates_each.rb +14 -0
 - data/test/functional/test_validates_format_of.rb +34 -0
 - data/test/functional/test_validates_length_of.rb +64 -0
 - data/test/functional/test_validates_numericality_of.rb +57 -0
 - data/test/functional/test_validates_presence_of.rb +16 -0
 - data/test/functional/test_validates_true_for.rb +27 -0
 - data/test/test_helper.rb +33 -0
 - data/test/unit/test_errors.rb +70 -0
 - data/test/unit/test_understandable.rb +19 -0
 - data/test/unit/test_validatable.rb +38 -0
 - data/test/unit/test_validates_acceptance_of.rb +45 -0
 - data/test/unit/test_validates_associated.rb +29 -0
 - data/test/unit/test_validates_confirmation_of.rb +76 -0
 - data/test/unit/test_validates_format_of.rb +44 -0
 - data/test/unit/test_validates_length_of.rb +80 -0
 - data/test/unit/test_validates_numericality_of.rb +76 -0
 - data/test/unit/test_validates_presence_of.rb +35 -0
 - data/test/unit/test_validates_true_for.rb +29 -0
 - data/test/unit/test_validation_base.rb +52 -0
 - metadata +126 -0
 
| 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Object #:nodoc:
         
     | 
| 
      
 2 
     | 
    
         
            +
              module InstanceExecHelper #:nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
              end
         
     | 
| 
      
 4 
     | 
    
         
            +
              include InstanceExecHelper
         
     | 
| 
      
 5 
     | 
    
         
            +
              def instance_eval_with_params(*args, &block)
         
     | 
| 
      
 6 
     | 
    
         
            +
                begin
         
     | 
| 
      
 7 
     | 
    
         
            +
                  old_critical, Thread.critical = Thread.critical, true
         
     | 
| 
      
 8 
     | 
    
         
            +
                  n = 0
         
     | 
| 
      
 9 
     | 
    
         
            +
                  n += 1 while respond_to?(mname="__instance_exec#{n}")
         
     | 
| 
      
 10 
     | 
    
         
            +
                  InstanceExecHelper.module_eval{ define_method(mname, &block) }
         
     | 
| 
      
 11 
     | 
    
         
            +
                ensure
         
     | 
| 
      
 12 
     | 
    
         
            +
                  Thread.critical = old_critical
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
                begin
         
     | 
| 
      
 15 
     | 
    
         
            +
                  ret = send(mname, *args)
         
     | 
| 
      
 16 
     | 
    
         
            +
                ensure
         
     | 
| 
      
 17 
     | 
    
         
            +
                  InstanceExecHelper.module_eval{ remove_method(mname) } rescue nil
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
                ret
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/requireable.rb
    ADDED
    
    | 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Validatable
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Requireable #:nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
                module ClassMethods #:nodoc:
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def requires(*args)
         
     | 
| 
      
 5 
     | 
    
         
            +
                    required_options.concat args        
         
     | 
| 
      
 6 
     | 
    
         
            +
                  end
         
     | 
| 
      
 7 
     | 
    
         
            +
                  
         
     | 
| 
      
 8 
     | 
    
         
            +
                  def required_options
         
     | 
| 
      
 9 
     | 
    
         
            +
                    @required_options ||= []
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
                
         
     | 
| 
      
 13 
     | 
    
         
            +
                def self.included(klass)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  klass.extend ClassMethods
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
                
         
     | 
| 
      
 17 
     | 
    
         
            +
                def requires(options)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  required_options = self.class.required_options.inject([]) do |errors, attribute|
         
     | 
| 
      
 19 
     | 
    
         
            +
                    errors << attribute.to_s unless options.has_key?(attribute)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    errors
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
                  raise ArgumentError.new("#{self.class} requires options: #{required_options.join(', ')}") if required_options.any?
         
     | 
| 
      
 23 
     | 
    
         
            +
                  true
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Validatable
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Understandable #:nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
                module ClassMethods #:nodoc:
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def understands(*args)
         
     | 
| 
      
 5 
     | 
    
         
            +
                    understandings.concat args
         
     | 
| 
      
 6 
     | 
    
         
            +
                  end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def understandings
         
     | 
| 
      
 9 
     | 
    
         
            +
                    @understandings ||= []
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  def all_understandings
         
     | 
| 
      
 13 
     | 
    
         
            +
                    return understandings + self.superclass.all_understandings if self.superclass.respond_to? :all_understandings
         
     | 
| 
      
 14 
     | 
    
         
            +
                    understandings
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                def self.included(klass)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  klass.extend ClassMethods
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def must_understand(hash)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  invalid_options = hash.inject([]) do |errors, (key, value)|
         
     | 
| 
      
 24 
     | 
    
         
            +
                    errors << key.to_s unless self.class.all_understandings.include?(key)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    errors
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
                  raise ArgumentError.new("invalid options: #{invalid_options.join(', ')}") if invalid_options.any?
         
     | 
| 
      
 28 
     | 
    
         
            +
                  true
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/validatable.rb
    ADDED
    
    | 
         @@ -0,0 +1,25 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'forwardable'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'activesupport'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            dir = File.expand_path(File.dirname(__FILE__))
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            require File.join(dir, 'object_extension')
         
     | 
| 
      
 8 
     | 
    
         
            +
            require File.join(dir, 'errors')
         
     | 
| 
      
 9 
     | 
    
         
            +
            require File.join(dir, 'validatable_class_methods')
         
     | 
| 
      
 10 
     | 
    
         
            +
            require File.join(dir, 'macros')
         
     | 
| 
      
 11 
     | 
    
         
            +
            require File.join(dir, 'validatable_instance_methods')
         
     | 
| 
      
 12 
     | 
    
         
            +
            require File.join(dir, 'included_validation')
         
     | 
| 
      
 13 
     | 
    
         
            +
            require File.join(dir, 'child_validation')
         
     | 
| 
      
 14 
     | 
    
         
            +
            require File.join(dir, 'understandable')
         
     | 
| 
      
 15 
     | 
    
         
            +
            require File.join(dir, 'requireable')
         
     | 
| 
      
 16 
     | 
    
         
            +
            require File.join(dir, 'validations/validation_base')
         
     | 
| 
      
 17 
     | 
    
         
            +
            require File.join(dir, 'validations/validates_format_of')
         
     | 
| 
      
 18 
     | 
    
         
            +
            require File.join(dir, 'validations/validates_presence_of')
         
     | 
| 
      
 19 
     | 
    
         
            +
            require File.join(dir, 'validations/validates_acceptance_of')
         
     | 
| 
      
 20 
     | 
    
         
            +
            require File.join(dir, 'validations/validates_confirmation_of')
         
     | 
| 
      
 21 
     | 
    
         
            +
            require File.join(dir, 'validations/validates_length_of')
         
     | 
| 
      
 22 
     | 
    
         
            +
            require File.join(dir, 'validations/validates_true_for')
         
     | 
| 
      
 23 
     | 
    
         
            +
            require File.join(dir, 'validations/validates_numericality_of')
         
     | 
| 
      
 24 
     | 
    
         
            +
            require File.join(dir, 'validations/validates_each')
         
     | 
| 
      
 25 
     | 
    
         
            +
            require File.join(dir, 'validations/validates_associated')
         
     | 
| 
         @@ -0,0 +1,85 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Validatable
         
     | 
| 
      
 2 
     | 
    
         
            +
              module ClassMethods #:nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
                
         
     | 
| 
      
 4 
     | 
    
         
            +
                def validate_children(instance, group)
         
     | 
| 
      
 5 
     | 
    
         
            +
                  self.children_to_validate.each do |child_validation|
         
     | 
| 
      
 6 
     | 
    
         
            +
                    next unless child_validation.should_validate?(instance)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    child = instance.send child_validation.attribute
         
     | 
| 
      
 8 
     | 
    
         
            +
                    if (child.respond_to?(:valid_for_group?))
         
     | 
| 
      
 9 
     | 
    
         
            +
                      child.valid_for_group?(group)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    else
         
     | 
| 
      
 11 
     | 
    
         
            +
                      child.valid?
         
     | 
| 
      
 12 
     | 
    
         
            +
                    end
         
     | 
| 
      
 13 
     | 
    
         
            +
                    child.errors.each do |attribute, messages|
         
     | 
| 
      
 14 
     | 
    
         
            +
                      if messages.is_a?(String)
         
     | 
| 
      
 15 
     | 
    
         
            +
                        add_error(instance, child_validation.map[attribute.to_sym] || attribute, messages)
         
     | 
| 
      
 16 
     | 
    
         
            +
                      else
         
     | 
| 
      
 17 
     | 
    
         
            +
                        messages.each do |message|
         
     | 
| 
      
 18 
     | 
    
         
            +
                          add_error(instance, child_validation.map[attribute.to_sym] || attribute, message)
         
     | 
| 
      
 19 
     | 
    
         
            +
                        end
         
     | 
| 
      
 20 
     | 
    
         
            +
                      end
         
     | 
| 
      
 21 
     | 
    
         
            +
                    end
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
                
         
     | 
| 
      
 25 
     | 
    
         
            +
                def all_before_validations
         
     | 
| 
      
 26 
     | 
    
         
            +
                  if self.superclass.respond_to? :all_before_validations
         
     | 
| 
      
 27 
     | 
    
         
            +
                    return before_validations + self.superclass.all_before_validations 
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
                  before_validations
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
                
         
     | 
| 
      
 32 
     | 
    
         
            +
                def before_validations
         
     | 
| 
      
 33 
     | 
    
         
            +
                  @before_validations ||= []
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                def all_validations
         
     | 
| 
      
 37 
     | 
    
         
            +
                  if self.respond_to?(:superclass) && self.superclass.respond_to?(:all_validations)
         
     | 
| 
      
 38 
     | 
    
         
            +
                    return validations + self.superclass.all_validations 
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
                  validations
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                def validations
         
     | 
| 
      
 44 
     | 
    
         
            +
                  @validations ||= []
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
                
         
     | 
| 
      
 47 
     | 
    
         
            +
                def add_error(instance, attribute, msg)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  instance.errors.add(attribute, msg)
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
                
         
     | 
| 
      
 51 
     | 
    
         
            +
                def validation_keys_include?(key)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  validations.map { |validation| validation.key }.include?(key)
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
                
         
     | 
| 
      
 55 
     | 
    
         
            +
                def validations_to_include
         
     | 
| 
      
 56 
     | 
    
         
            +
                  @validations_to_include ||= []
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
                
         
     | 
| 
      
 59 
     | 
    
         
            +
                protected
         
     | 
| 
      
 60 
     | 
    
         
            +
                
         
     | 
| 
      
 61 
     | 
    
         
            +
                def add_validations(args, klass)
         
     | 
| 
      
 62 
     | 
    
         
            +
                  options = args.last.is_a?(Hash) ? args.pop : {}
         
     | 
| 
      
 63 
     | 
    
         
            +
                  args.each do |attribute|
         
     | 
| 
      
 64 
     | 
    
         
            +
                    new_validation = klass.new self, attribute, options
         
     | 
| 
      
 65 
     | 
    
         
            +
                    self.validations << new_validation
         
     | 
| 
      
 66 
     | 
    
         
            +
                    self.create_valid_method_for_groups new_validation.groups
         
     | 
| 
      
 67 
     | 
    
         
            +
                  end
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
                
         
     | 
| 
      
 70 
     | 
    
         
            +
                def create_valid_method_for_groups(groups)
         
     | 
| 
      
 71 
     | 
    
         
            +
                  groups.each do |group|
         
     | 
| 
      
 72 
     | 
    
         
            +
                    self.class_eval do
         
     | 
| 
      
 73 
     | 
    
         
            +
                      define_method "valid_for_#{group}?".to_sym do
         
     | 
| 
      
 74 
     | 
    
         
            +
                        valid_for_group?(group)
         
     | 
| 
      
 75 
     | 
    
         
            +
                      end
         
     | 
| 
      
 76 
     | 
    
         
            +
                    end
         
     | 
| 
      
 77 
     | 
    
         
            +
                  end
         
     | 
| 
      
 78 
     | 
    
         
            +
                end
         
     | 
| 
      
 79 
     | 
    
         
            +
                
         
     | 
| 
      
 80 
     | 
    
         
            +
                def children_to_validate
         
     | 
| 
      
 81 
     | 
    
         
            +
                  @children_to_validate ||= []
         
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
                
         
     | 
| 
      
 84 
     | 
    
         
            +
              end
         
     | 
| 
      
 85 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,116 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Validatable
         
     | 
| 
      
 2 
     | 
    
         
            +
              def self.included(klass) #:nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
                klass.extend Validatable::ClassMethods
         
     | 
| 
      
 4 
     | 
    
         
            +
                klass.extend Validatable::Macros
         
     | 
| 
      
 5 
     | 
    
         
            +
                klass.class_eval do
         
     | 
| 
      
 6 
     | 
    
         
            +
                  include ActiveSupport::Callbacks
         
     | 
| 
      
 7 
     | 
    
         
            +
                  define_callbacks :validate, :validate_on_create, :validate_on_update
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
              
         
     | 
| 
      
 11 
     | 
    
         
            +
              # call-seq: valid?
         
     | 
| 
      
 12 
     | 
    
         
            +
              #
         
     | 
| 
      
 13 
     | 
    
         
            +
              # Returns true if no errors were added otherwise false. Only executes validations that have no :groups option specified
         
     | 
| 
      
 14 
     | 
    
         
            +
              def valid?
         
     | 
| 
      
 15 
     | 
    
         
            +
                valid_for_group?(nil)
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
              
         
     | 
| 
      
 18 
     | 
    
         
            +
              # call-seq: errors
         
     | 
| 
      
 19 
     | 
    
         
            +
              #
         
     | 
| 
      
 20 
     | 
    
         
            +
              # Returns the Errors object that holds all information about attribute error messages.
         
     | 
| 
      
 21 
     | 
    
         
            +
              def errors
         
     | 
| 
      
 22 
     | 
    
         
            +
                @errors ||= Validatable::Errors.new
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
              
         
     | 
| 
      
 25 
     | 
    
         
            +
              def valid_for_group?(group) #:nodoc:
         
     | 
| 
      
 26 
     | 
    
         
            +
                run_before_validations
         
     | 
| 
      
 27 
     | 
    
         
            +
                errors.clear
         
     | 
| 
      
 28 
     | 
    
         
            +
                run_callbacks(:validate)
         
     | 
| 
      
 29 
     | 
    
         
            +
                
         
     | 
| 
      
 30 
     | 
    
         
            +
                if respond_to?(:new?)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  new? ? run_callbacks(:validate_on_create) : run_callbacks(:validate_on_update)
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
                
         
     | 
| 
      
 34 
     | 
    
         
            +
                self.class.validate_children(self, group)
         
     | 
| 
      
 35 
     | 
    
         
            +
                self.validate_group(group)
         
     | 
| 
      
 36 
     | 
    
         
            +
                errors.empty?
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
              
         
     | 
| 
      
 39 
     | 
    
         
            +
              def times_validated(key) #:nodoc:
         
     | 
| 
      
 40 
     | 
    
         
            +
                times_validated_hash[key] || 0
         
     | 
| 
      
 41 
     | 
    
         
            +
              end
         
     | 
| 
      
 42 
     | 
    
         
            +
              
         
     | 
| 
      
 43 
     | 
    
         
            +
              def increment_times_validated_for(validation) #:nodoc:
         
     | 
| 
      
 44 
     | 
    
         
            +
                if validation.key != nil
         
     | 
| 
      
 45 
     | 
    
         
            +
                  if times_validated_hash[validation.key].nil?
         
     | 
| 
      
 46 
     | 
    
         
            +
                    times_validated_hash[validation.key] = 1
         
     | 
| 
      
 47 
     | 
    
         
            +
                  else
         
     | 
| 
      
 48 
     | 
    
         
            +
                    times_validated_hash[validation.key] += 1
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
              end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
              # call-seq: validate_only(key)
         
     | 
| 
      
 54 
     | 
    
         
            +
              #
         
     | 
| 
      
 55 
     | 
    
         
            +
              # Only executes a specified validation. The argument should follow a pattern based on the key of the validation.
         
     | 
| 
      
 56 
     | 
    
         
            +
              #   Examples:
         
     | 
| 
      
 57 
     | 
    
         
            +
              #     * validates_presence_of :name can be run with obj.validate_only("presence_of/name")
         
     | 
| 
      
 58 
     | 
    
         
            +
              #     * validates_presence_of :birthday, :key => "a key" can be run with obj.validate_only("presence_of/a key")
         
     | 
| 
      
 59 
     | 
    
         
            +
              def validate_only(key)
         
     | 
| 
      
 60 
     | 
    
         
            +
                validation_name, attribute_name = key.split("/")
         
     | 
| 
      
 61 
     | 
    
         
            +
                validation_name = validation_name.split("_").collect{|word| word.capitalize}.join
         
     | 
| 
      
 62 
     | 
    
         
            +
                validation_key = "#{self.class.name}/Validatable::Validates#{validation_name}/#{attribute_name}"
         
     | 
| 
      
 63 
     | 
    
         
            +
                validation = self.class.all_validations.find { |validation| validation.key == validation_key }
         
     | 
| 
      
 64 
     | 
    
         
            +
                raise ArgumentError.new("validation with key #{validation_key} could not be found") if validation.nil?
         
     | 
| 
      
 65 
     | 
    
         
            +
                errors.clear
         
     | 
| 
      
 66 
     | 
    
         
            +
                run_validation(validation)
         
     | 
| 
      
 67 
     | 
    
         
            +
              end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
              protected
         
     | 
| 
      
 70 
     | 
    
         
            +
              def times_validated_hash #:nodoc:
         
     | 
| 
      
 71 
     | 
    
         
            +
                @times_validated_hash ||= {}
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
              def validate_group(group) #:nodoc:
         
     | 
| 
      
 75 
     | 
    
         
            +
                validation_levels.each do |level|
         
     | 
| 
      
 76 
     | 
    
         
            +
                  validations_for_level_and_group(level, group).each do |validation|
         
     | 
| 
      
 77 
     | 
    
         
            +
                    run_validation(validation) if validation.should_validate?(self)
         
     | 
| 
      
 78 
     | 
    
         
            +
                  end
         
     | 
| 
      
 79 
     | 
    
         
            +
                  return unless self.errors.empty?
         
     | 
| 
      
 80 
     | 
    
         
            +
                end
         
     | 
| 
      
 81 
     | 
    
         
            +
              end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
              def run_validation(validation) #:nodoc:
         
     | 
| 
      
 84 
     | 
    
         
            +
                validation_result = validation.valid?(self)
         
     | 
| 
      
 85 
     | 
    
         
            +
                add_error(validation.attribute, validation.message(self)) unless validation_result
         
     | 
| 
      
 86 
     | 
    
         
            +
                increment_times_validated_for(validation)
         
     | 
| 
      
 87 
     | 
    
         
            +
                validation.run_after_validate(validation_result, self, validation.attribute)
         
     | 
| 
      
 88 
     | 
    
         
            +
              end
         
     | 
| 
      
 89 
     | 
    
         
            +
              
         
     | 
| 
      
 90 
     | 
    
         
            +
              def run_before_validations #:nodoc:
         
     | 
| 
      
 91 
     | 
    
         
            +
                self.class.all_before_validations.each do |block|
         
     | 
| 
      
 92 
     | 
    
         
            +
                  instance_eval &block
         
     | 
| 
      
 93 
     | 
    
         
            +
                end
         
     | 
| 
      
 94 
     | 
    
         
            +
              end
         
     | 
| 
      
 95 
     | 
    
         
            +
              
         
     | 
| 
      
 96 
     | 
    
         
            +
              def add_error(attribute, message) #:nodoc:
         
     | 
| 
      
 97 
     | 
    
         
            +
                self.class.add_error(self, attribute, message)
         
     | 
| 
      
 98 
     | 
    
         
            +
              end
         
     | 
| 
      
 99 
     | 
    
         
            +
              
         
     | 
| 
      
 100 
     | 
    
         
            +
              def validations_for_level_and_group(level, group) #:nodoc:
         
     | 
| 
      
 101 
     | 
    
         
            +
                validations_for_level = self.all_validations.select { |validation| validation.level == level }
         
     | 
| 
      
 102 
     | 
    
         
            +
                return validations_for_level.select { |validation| validation.groups.empty? } if group.nil?
         
     | 
| 
      
 103 
     | 
    
         
            +
                validations_for_level.select { |validation| validation.groups.include?(group) }
         
     | 
| 
      
 104 
     | 
    
         
            +
              end
         
     | 
| 
      
 105 
     | 
    
         
            +
              
         
     | 
| 
      
 106 
     | 
    
         
            +
              def all_validations #:nodoc:
         
     | 
| 
      
 107 
     | 
    
         
            +
                res = self.class.validations_to_include.inject(self.class.all_validations) do |result, included_validation_class|
         
     | 
| 
      
 108 
     | 
    
         
            +
                  result += self.send(included_validation_class.attribute).all_validations
         
     | 
| 
      
 109 
     | 
    
         
            +
                  result
         
     | 
| 
      
 110 
     | 
    
         
            +
                end
         
     | 
| 
      
 111 
     | 
    
         
            +
              end
         
     | 
| 
      
 112 
     | 
    
         
            +
              
         
     | 
| 
      
 113 
     | 
    
         
            +
              def validation_levels #:nodoc:
         
     | 
| 
      
 114 
     | 
    
         
            +
                self.class.all_validations.inject([1]) { |result, validation| result << validation.level }.uniq.sort
         
     | 
| 
      
 115 
     | 
    
         
            +
              end
         
     | 
| 
      
 116 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,14 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Validatable
         
     | 
| 
      
 2 
     | 
    
         
            +
              class ValidatesAcceptanceOf < ValidationBase #:nodoc:    
         
     | 
| 
      
 3 
     | 
    
         
            +
                def valid?(instance)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  value = instance.send(self.attribute)
         
     | 
| 
      
 5 
     | 
    
         
            +
                  return true if allow_nil && value.nil?
         
     | 
| 
      
 6 
     | 
    
         
            +
                  return true if allow_blank && value.blank?
         
     | 
| 
      
 7 
     | 
    
         
            +
                  %w(1 true t).include?(value)
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
                
         
     | 
| 
      
 10 
     | 
    
         
            +
                def message(instance)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  super || "must be accepted"
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Validatable
         
     | 
| 
      
 2 
     | 
    
         
            +
              class ValidatesAssociated < ValidationBase #:nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
                def valid?(instance)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  Array(instance.send(attribute)).compact.map do |child|
         
     | 
| 
      
 5 
     | 
    
         
            +
                    child.valid?
         
     | 
| 
      
 6 
     | 
    
         
            +
                  end.all?
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def message(instance)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  super || "is invalid"
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Validatable
         
     | 
| 
      
 2 
     | 
    
         
            +
              class ValidatesConfirmationOf < ValidationBase #:nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
                option :case_sensitive
         
     | 
| 
      
 4 
     | 
    
         
            +
                default :case_sensitive => true
         
     | 
| 
      
 5 
     | 
    
         
            +
                
         
     | 
| 
      
 6 
     | 
    
         
            +
                def initialize(klass, attribute, options={})
         
     | 
| 
      
 7 
     | 
    
         
            +
                  klass.class_eval { attr_accessor "#{attribute}_confirmation" }
         
     | 
| 
      
 8 
     | 
    
         
            +
                  super
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
                
         
     | 
| 
      
 11 
     | 
    
         
            +
                def valid?(instance)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  confirmation_value = instance.send("#{self.attribute}_confirmation")
         
     | 
| 
      
 13 
     | 
    
         
            +
                  return true if allow_nil && confirmation_value.nil?
         
     | 
| 
      
 14 
     | 
    
         
            +
                  return true if allow_blank && confirmation_value.blank?
         
     | 
| 
      
 15 
     | 
    
         
            +
                  return instance.send(self.attribute) == instance.send("#{self.attribute}_confirmation".to_sym) if case_sensitive
         
     | 
| 
      
 16 
     | 
    
         
            +
                  instance.send(self.attribute).to_s.casecmp(instance.send("#{self.attribute}_confirmation".to_sym).to_s) == 0
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
                
         
     | 
| 
      
 19 
     | 
    
         
            +
                def message(instance)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  super || "doesn't match confirmation"
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,14 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Validatable
         
     | 
| 
      
 2 
     | 
    
         
            +
              class ValidatesEach < ValidationBase #:nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
                required_option :logic
         
     | 
| 
      
 4 
     | 
    
         
            +
              
         
     | 
| 
      
 5 
     | 
    
         
            +
                def valid?(instance)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  instance.instance_eval(&logic)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  true # return true so no error is added. should look in the future at doing this different.
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
                
         
     | 
| 
      
 10 
     | 
    
         
            +
                def message(instance)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  super || "is invalid"
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,16 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Validatable
         
     | 
| 
      
 2 
     | 
    
         
            +
              class ValidatesFormatOf < ValidationBase #:nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
                required_option :with
         
     | 
| 
      
 4 
     | 
    
         
            +
              
         
     | 
| 
      
 5 
     | 
    
         
            +
                def valid?(instance)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  value = instance.send(self.attribute)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  return true if allow_nil && value.nil?
         
     | 
| 
      
 8 
     | 
    
         
            +
                  return true if allow_blank && value.blank?
         
     | 
| 
      
 9 
     | 
    
         
            +
                  not (value.to_s =~ self.with).nil?
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
                
         
     | 
| 
      
 12 
     | 
    
         
            +
                def message(instance)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  super || "is invalid"
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,30 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Validatable
         
     | 
| 
      
 2 
     | 
    
         
            +
              class ValidatesLengthOf < ValidationBase #:nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
                option :minimum, :maximum, :is, :within
         
     | 
| 
      
 4 
     | 
    
         
            +
                
         
     | 
| 
      
 5 
     | 
    
         
            +
                def message(instance)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  super || "is invalid"
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
                
         
     | 
| 
      
 9 
     | 
    
         
            +
                def valid?(instance)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  valid = true
         
     | 
| 
      
 11 
     | 
    
         
            +
                  value = instance.send(self.attribute)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  
         
     | 
| 
      
 13 
     | 
    
         
            +
                  if value.nil?
         
     | 
| 
      
 14 
     | 
    
         
            +
                    return true if allow_nil
         
     | 
| 
      
 15 
     | 
    
         
            +
                    value = ''
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  if value.blank?
         
     | 
| 
      
 19 
     | 
    
         
            +
                    return true if allow_blank
         
     | 
| 
      
 20 
     | 
    
         
            +
                    value = ''
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
                  
         
     | 
| 
      
 23 
     | 
    
         
            +
                  valid &&= value.length <= maximum unless maximum.nil? 
         
     | 
| 
      
 24 
     | 
    
         
            +
                  valid &&= value.length >= minimum unless minimum.nil?
         
     | 
| 
      
 25 
     | 
    
         
            +
                  valid &&= value.length == is unless is.nil?
         
     | 
| 
      
 26 
     | 
    
         
            +
                  valid &&= within.include?(value.length) unless within.nil?
         
     | 
| 
      
 27 
     | 
    
         
            +
                  valid
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Validatable 
         
     | 
| 
      
 2 
     | 
    
         
            +
              class ValidatesNumericalityOf < ValidationBase #:nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
                option :only_integer
         
     | 
| 
      
 4 
     | 
    
         
            +
                
         
     | 
| 
      
 5 
     | 
    
         
            +
                def valid?(instance)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  value = value_for(instance)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  return true if allow_nil && value.nil?
         
     | 
| 
      
 8 
     | 
    
         
            +
                  return true if allow_blank && value.blank?
         
     | 
| 
      
 9 
     | 
    
         
            +
                  
         
     | 
| 
      
 10 
     | 
    
         
            +
                  value = value.to_s
         
     | 
| 
      
 11 
     | 
    
         
            +
                  regex = self.only_integer ? /\A[+-]?\d+\Z/ : /^\d*\.{0,1}\d+$/
         
     | 
| 
      
 12 
     | 
    
         
            +
                  not (value =~ regex).nil?
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
                
         
     | 
| 
      
 15 
     | 
    
         
            +
                def message(instance)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  super || "must be a number"
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
                
         
     | 
| 
      
 19 
     | 
    
         
            +
                private
         
     | 
| 
      
 20 
     | 
    
         
            +
                  def value_for(instance)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    before_typecast_method = "#{self.attribute}_before_typecast"
         
     | 
| 
      
 22 
     | 
    
         
            +
                    value_method = instance.respond_to?(before_typecast_method.intern) ? before_typecast_method : self.attribute
         
     | 
| 
      
 23 
     | 
    
         
            +
                    instance.send(value_method)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
            end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     |