merge 19889:20181 of rails_port into the openID branch
[rails.git] / vendor / plugins / validates_email_format_of / lib / validates_email_format_of.rb
1 # encoding: utf-8
2
3 module ValidatesEmailFormatOf
4   LocalPartSpecialChars = Regexp.escape('!#$%&\'*-/=?+-^_`{|}~')
5   LocalPartUnquoted = '(([[:alnum:]' + LocalPartSpecialChars + ']+[\.\+]+))*[[:alnum:]' + LocalPartSpecialChars + '+]+'
6   LocalPartQuoted = '\"(([[:alnum:]' + LocalPartSpecialChars + '\.\+]*|(\\\\[\u0001-\uFFFF]))*)\"'
7   Regex = Regexp.new('^((' + LocalPartUnquoted + ')|(' + LocalPartQuoted + ')+)@(((\w+\-+)|(\w+\.))*\w{1,63}\.[a-z]{2,6}$)', Regexp::EXTENDED | Regexp::IGNORECASE)
8 end
9
10 module ActiveRecord
11   module Validations
12     module ClassMethods
13       # Validates whether the value of the specified attribute is a valid email address
14       #
15       #   class User < ActiveRecord::Base
16       #     validates_email_format_of :email, :on => :create
17       #   end
18       #
19       # Configuration options:
20       # * <tt>message</tt> - A custom error message (default is: " does not appear to be a valid e-mail address")
21       # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update)
22       # * <tt>allow_nil</tt> - Allow nil values (default is false)
23       # * <tt>allow_blank</tt> - Allow blank values (default is false)
24       # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
25       #   occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }).  The
26       #   method, proc or string should return or evaluate to a true or false value.
27       # * <tt>unless</tt> - See <tt>:if</tt>
28       def validates_email_format_of(*attr_names)
29         options = { :message => ' does not appear to be a valid e-mail address', 
30                     :on => :save, 
31                     :allow_nil => false,
32                     :allow_blank => false,
33                     :with => ValidatesEmailFormatOf::Regex }
34
35         options.update(attr_names.pop) if attr_names.last.is_a?(Hash)
36
37         validates_each(attr_names, options) do |record, attr_name, value|
38           v = value.to_s
39
40           # local part max is 64 chars, domain part max is 255 chars
41           # TODO: should this decode escaped entities before counting?
42           begin
43             domain, local = v.reverse.split('@', 2)
44           rescue
45             record.errors.add(attr_name, options[:message])
46             next
47           end
48
49           unless v =~ options[:with] and not v =~ /\.\./ and domain.length <= 255 and local.length <= 64
50             record.errors.add(attr_name, options[:message])
51           end
52         end
53       end
54     end   
55   end
56 end