validates_email_format_of 1.4.5 → 1.4.6

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -23,6 +23,11 @@ Or in your Rails 3 Gemfile
23
23
  validates_email_format_of :email
24
24
  end
25
25
 
26
+ # Rails 3
27
+ class Person < ActiveRecord::Base
28
+ validates :email, :email_format => {:message => 'is not looking good'}
29
+ end
30
+
26
31
  As of version 1.4, it's possible to run e-mail validation tests (including MX
27
32
  checks) without using ActiveRecord or even touching a database. The
28
33
  <tt>validate_email_format</tt> method will return <tt>nil</tt> on a valid
@@ -1,11 +1,13 @@
1
1
  # encoding: utf-8
2
2
  module ValidatesEmailFormatOf
3
3
  require 'resolv'
4
-
4
+
5
+ MessageScope = defined?(ActiveModel) ? :activemodel : :activerecord
6
+
5
7
  LocalPartSpecialChars = Regexp.escape('!#$%&\'*-/=?+-^_`{|}~')
6
8
  LocalPartUnquoted = '([[:alnum:]' + LocalPartSpecialChars + ']+[\.]+)*[[:alnum:]' + LocalPartSpecialChars + '+]+'
7
9
  LocalPartQuoted = '\"([[:alnum:]' + LocalPartSpecialChars + '\.]|\\\\[\x00-\xFF])*\"'
8
- Regex = Regexp.new('\A(' + LocalPartUnquoted + '|' + LocalPartQuoted + '+)@(((\w+\-+[^_])|(\w+\.[a-z0-9-]*))*([a-z0-9-]{1,63})\.[a-z]{2,6}(?:\.[a-z]{2,6})?\Z)', Regexp::EXTENDED | Regexp::IGNORECASE, 'n')
10
+ Regex = Regexp.new('\A(' + LocalPartUnquoted + '|' + LocalPartQuoted + '+)@(((\w+\-+[^_])|(\w+\.[a-z0-9-]*))*([a-z0-9\-\.]{1,63})\.[a-z]{2,6}(?:\.[a-z]{2,6})?\Z)', Regexp::EXTENDED | Regexp::IGNORECASE, 'n')
9
11
 
10
12
  def self.validate_email_domain(email)
11
13
  domain = email.match(/\@(.+)/)[1]
@@ -14,26 +16,26 @@ module ValidatesEmailFormatOf
14
16
  end
15
17
  @mx.size > 0 ? true : false
16
18
  end
17
-
19
+
18
20
  # Validates whether the specified value is a valid email address. Returns nil if the value is valid, otherwise returns an array
19
21
  # containing one or more validation error messages.
20
22
  #
21
23
  # Configuration options:
22
- # * <tt>message</tt> - A custom error message (default is: "does not appear to be a valid e-mail address")
24
+ # * <tt>message</tt> - A custom error message (default is: "does not appear to be valid")
23
25
  # * <tt>check_mx</tt> - Check for MX records (default is false)
24
26
  # * <tt>mx_message</tt> - A custom error message when an MX record validation fails (default is: "is not routable.")
25
27
  # * <tt>with</tt> The regex to use for validating the format of the email address (default is ValidatesEmailFormatOf::Regex)</tt>
26
28
  # * <tt>local_length</tt> Maximum number of characters allowed in the local part (default is 64)
27
29
  # * <tt>domain_length</tt> Maximum number of characters allowed in the domain part (default is 255)
28
30
  def self.validate_email_format(email, options={})
29
- default_options = { :message => I18n.t(:invalid_email_address, :scope => [:activerecord, :errors, :messages], :default => 'does not appear to be a valid e-mail address'),
31
+ default_options = { :message => I18n.t(:invalid_email_address, :scope => [MessageScope, :errors, :messages], :default => 'does not appear to be valid'),
30
32
  :check_mx => false,
31
- :mx_message => I18n.t(:email_address_not_routable, :scope => [:activerecord, :errors, :messages], :default => 'is not routable'),
33
+ :mx_message => I18n.t(:email_address_not_routable, :scope => [MessageScope, :errors, :messages], :default => 'is not routable'),
32
34
  :with => ValidatesEmailFormatOf::Regex ,
33
35
  :domain_length => 255,
34
36
  :local_length => 64
35
37
  }
36
- options.merge!(default_options) {|key, old, new| old} # merge the default options into the specified options, retaining all specified options
38
+ opts = options.merge(default_options) {|key, old, new| old} # merge the default options into the specified options, retaining all specified options
37
39
 
38
40
  email.strip!
39
41
 
@@ -42,55 +44,92 @@ module ValidatesEmailFormatOf
42
44
  begin
43
45
  domain, local = email.reverse.split('@', 2)
44
46
  rescue
45
- return [ options[:message] ]
47
+ return [ opts[:message] ]
46
48
  end
47
49
 
48
- unless email =~ options[:with] and not email =~ /\.\./ and domain.length <= options[:domain_length] and local.length <= options[:local_length]
49
- return [ options[:message] ]
50
+ unless email =~ opts[:with] and not email =~ /\.\./ and domain.length <= opts[:domain_length] and local.length <= opts[:local_length]
51
+ return [ opts[:message] ]
50
52
  end
51
-
52
- if options[:check_mx] and !ValidatesEmailFormatOf::validate_email_domain(email)
53
- return [ options[:mx_message] ]
53
+
54
+ if opts[:check_mx] and !ValidatesEmailFormatOf::validate_email_domain(email)
55
+ return [ opts[:mx_message] ]
56
+ end
57
+
58
+ local.reverse!
59
+
60
+ # check for proper escaping
61
+
62
+ if local[0] == '"'
63
+ local.gsub!(/\A\"|\"\Z/, '')
64
+ escaped = false
65
+ local.each_char do |c|
66
+ if escaped
67
+ escaped = false
68
+ elsif c == '"' # can't have a double quote without a preceding backslash
69
+ return [ opts[:mx_message] ]
70
+ else
71
+ escaped = c == '\\'
72
+ end
73
+ end
74
+
75
+ return [ opts[:mx_message] ] if escaped
54
76
  end
55
-
77
+
56
78
  return nil # represents no validation errors
57
79
  end
58
- end
59
80
 
60
- module ActiveRecord
61
81
  module Validations
62
- module ClassMethods
63
- # Validates whether the value of the specified attribute is a valid email address
64
- #
65
- # class User < ActiveRecord::Base
66
- # validates_email_format_of :email, :on => :create
67
- # end
68
- #
69
- # Configuration options:
70
- # * <tt>message</tt> - A custom error message (default is: "does not appear to be a valid e-mail address")
71
- # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update)
72
- # * <tt>allow_nil</tt> - Allow nil values (default is false)
73
- # * <tt>allow_blank</tt> - Allow blank values (default is false)
74
- # * <tt>check_mx</tt> - Check for MX records (default is false)
75
- # * <tt>mx_message</tt> - A custom error message when an MX record validation fails (default is: "is not routable.")
76
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
77
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
78
- # method, proc or string should return or evaluate to a true or false value.
79
- # * <tt>unless</tt> - See <tt>:if</tt>
80
- def validates_email_format_of(*attr_names)
81
- options = { :on => :save,
82
- :allow_nil => false,
83
- :allow_blank => false }
84
- options.update(attr_names.pop) if attr_names.last.is_a?(Hash)
85
-
86
- validates_each(attr_names, options) do |record, attr_name, value|
87
- v = value.to_s
88
- errors = ValidatesEmailFormatOf::validate_email_format(v, options)
89
- errors.each do |error|
90
- record.errors.add(attr_name, error)
91
- end unless errors.nil?
92
- end
82
+ # Validates whether the value of the specified attribute is a valid email address
83
+ #
84
+ # class User < ActiveRecord::Base
85
+ # validates_email_format_of :email, :on => :create
86
+ # end
87
+ #
88
+ # Configuration options:
89
+ # * <tt>message</tt> - A custom error message (default is: "does not appear to be valid")
90
+ # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update)
91
+ # * <tt>allow_nil</tt> - Allow nil values (default is false)
92
+ # * <tt>allow_blank</tt> - Allow blank values (default is false)
93
+ # * <tt>check_mx</tt> - Check for MX records (default is false)
94
+ # * <tt>mx_message</tt> - A custom error message when an MX record validation fails (default is: "is not routable.")
95
+ # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
96
+ # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
97
+ # method, proc or string should return or evaluate to a true or false value.
98
+ # * <tt>unless</tt> - See <tt>:if</tt>
99
+ def validates_email_format_of(*attr_names)
100
+ options = { :on => :save,
101
+ :allow_nil => false,
102
+ :allow_blank => false }
103
+ options.update(attr_names.pop) if attr_names.last.is_a?(Hash)
104
+
105
+ validates_each(attr_names, options) do |record, attr_name, value|
106
+ v = value.to_s
107
+ errors = ValidatesEmailFormatOf::validate_email_format(v, options)
108
+ errors.each do |error|
109
+ record.errors.add(attr_name, error)
110
+ end unless errors.nil?
93
111
  end
94
- end
112
+ end
113
+ end
114
+ end
115
+
116
+ if defined?(ActiveModel)
117
+ class EmailFormatValidator < ActiveModel::EachValidator
118
+ def validate_each(record, attribute, value)
119
+ err = ValidatesEmailFormatOf::validate_email_format(value, options)
120
+ record.errors[attribute] << err unless err.nil?
121
+ record.errors[attribute].flatten!
122
+ end
95
123
  end
96
- end
124
+
125
+ module ActiveModel::Validations::HelperMethods
126
+ def validates_email_format_of(*attr_names)
127
+ validates_with EmailFormatValidator, _merge_attributes(attr_names)
128
+ end
129
+ end
130
+ else
131
+ class ActiveRecord::Base
132
+ extend ValidatesEmailFormatOf::Validations
133
+ end
134
+ end
135
+
data/rakefile.rb CHANGED
@@ -17,12 +17,11 @@ Rake::TestTask.new(:test) do |t|
17
17
  t.verbose = true
18
18
  end
19
19
 
20
- desc 'Generate documentation for the validates_email_format_of plugin.'
20
+ desc 'Generate documentation for the validates_email_format_of plugin and gem.'
21
21
  Rake::RDocTask.new(:rdoc) do |rdoc|
22
22
  rdoc.rdoc_dir = 'rdoc'
23
- rdoc.title = 'validates_email_format_of plugin'
23
+ rdoc.title = 'validates_email_format_of plugin and gem'
24
24
  rdoc.options << '--line-numbers --inline-source'
25
- rdoc.rdoc_files.include('README')
26
- rdoc.rdoc_files.include('TODO')
25
+ rdoc.rdoc_files.include('README.rdoc')
27
26
  rdoc.rdoc_files.include('lib/**/*.rb')
28
27
  end
@@ -6,7 +6,19 @@ class Person < ActiveRecord::Base
6
6
  end
7
7
 
8
8
  class MxRecord < ActiveRecord::Base
9
+ set_table_name 'people'
10
+
9
11
  validates_email_format_of :email,
10
12
  :on => :create,
11
13
  :check_mx => true
12
14
  end
15
+
16
+ if ActiveRecord::VERSION::MAJOR >= 3
17
+ class Shorthand < ActiveRecord::Base
18
+ set_table_name 'people'
19
+
20
+ validates :email, :email_format => { :message => 'fails with shorthand message' },
21
+ :length => { :maximum => 1 }
22
+
23
+ end
24
+ end
data/test/schema.rb CHANGED
@@ -2,9 +2,4 @@ ActiveRecord::Schema.define(:version => 0) do
2
2
  create_table :people, :force => true do |t|
3
3
  t.column "email", :string
4
4
  end
5
-
6
- create_table :mx_records, :force => true do |t|
7
- t.column "email", :string
8
- end
9
-
10
5
  end
@@ -8,10 +8,17 @@ class ValidatesEmailFormatOfTest < TEST_CASE
8
8
  @invalid_email = 'invalid@example.'
9
9
  end
10
10
 
11
+ def test_with_activerecord
12
+ p = create_person(:email => @valid_email)
13
+ save_passes(p)
14
+
15
+ p = create_person(:email => @invalid_email)
16
+ save_fails(p)
17
+ end
18
+
11
19
  def test_without_activerecord
12
- assert_nil ValidatesEmailFormatOf::validate_email_format('valid@example.com')
13
- err = ValidatesEmailFormatOf::validate_email_format('valid@example-com')
14
- assert_equal 1, err.size
20
+ assert_valid(@valid_email)
21
+ assert_invalid(@invalid_email)
15
22
  end
16
23
 
17
24
  def test_should_allow_valid_email_addresses
@@ -31,6 +38,7 @@ class ValidatesEmailFormatOfTest < TEST_CASE
31
38
  'valid@example.mobi',
32
39
  'valid@example.info',
33
40
  'valid-@example.com',
41
+ 'fake@p-t.k12.ok.us',
34
42
  # allow single character domain parts
35
43
  'valid@mail.x.example.com',
36
44
  'valid@x.com',
@@ -43,8 +51,7 @@ class ValidatesEmailFormatOfTest < TEST_CASE
43
51
  # apostrophes
44
52
  "test'test@example.com",
45
53
  ].each do |email|
46
- p = create_person(:email => email)
47
- save_passes(p, email)
54
+ assert_valid(email)
48
55
  end
49
56
  end
50
57
 
@@ -58,6 +65,8 @@ class ValidatesEmailFormatOfTest < TEST_CASE
58
65
  'invali..d@example.com',
59
66
  # should not allow underscores in domain names
60
67
  'invalid@ex_mple.com',
68
+ 'invalid@e..example.com',
69
+ 'invalid@p-t..example.com',
61
70
  'invalid@example.com.',
62
71
  'invalid@example.com_',
63
72
  'invalid@example.com-',
@@ -76,22 +85,26 @@ class ValidatesEmailFormatOfTest < TEST_CASE
76
85
  # one at a time
77
86
  "foo@example.com\nexample@gmail.com",
78
87
  'invalid@example.'].each do |email|
79
- p = create_person(:email => email)
80
- save_fails(p, email)
88
+ assert_invalid(email)
81
89
  end
82
90
  end
83
-
91
+
84
92
  # from http://www.rfc-editor.org/errata_search.php?rfc=3696
85
93
  def test_should_allow_quoted_characters
86
94
  ['"Abc\@def"@example.com',
87
95
  '"Fred\ Bloggs"@example.com',
88
96
  '"Joe.\\Blow"@example.com',
89
97
  ].each do |email|
90
- p = create_person(:email => email)
91
- save_passes(p, email)
98
+ assert_valid(email)
92
99
  end
93
100
  end
94
101
 
102
+ def test_should_required_balanced_quoted_characters
103
+ assert_valid(%!"example\\\\\\""@example.com!)
104
+ assert_valid(%!"example\\\\"@example.com!)
105
+ assert_invalid(%!"example\\\\""example.com!)
106
+ end
107
+
95
108
  # from http://tools.ietf.org/html/rfc3696, page 5
96
109
  # corrected in http://www.rfc-editor.org/errata_search.php?rfc=3696
97
110
  def test_should_not_allow_escaped_characters_without_quotes
@@ -99,8 +112,7 @@ class ValidatesEmailFormatOfTest < TEST_CASE
99
112
  'Abc\@def+@example.com',
100
113
  'Joe.\\Blow@example.com'
101
114
  ].each do |email|
102
- p = create_person(:email => email)
103
- save_fails(p, email)
115
+ assert_invalid(email)
104
116
  end
105
117
  end
106
118
 
@@ -108,8 +120,7 @@ class ValidatesEmailFormatOfTest < TEST_CASE
108
120
  ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@example.com',
109
121
  'test@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com'
110
122
  ].each do |email|
111
- p = create_person(:email => email)
112
- save_fails(p, email)
123
+ assert_invalid(email)
113
124
  end
114
125
  end
115
126
 
@@ -156,14 +167,36 @@ class ValidatesEmailFormatOfTest < TEST_CASE
156
167
  pmx = MxRecord.new(:email => 'test@code.dunae.ca')
157
168
  save_passes(pmx)
158
169
  end
170
+
171
+ def test_shorthand
172
+ if ActiveRecord::VERSION::MAJOR >= 3
173
+ s = Shorthand.new(:email => 'invalid')
174
+ assert !s.save
175
+ assert_equal 2, s.errors[:email].size
176
+ assert_block do
177
+ s.errors[:email].any? do |err|
178
+ err =~ /fails with shorthand message/
179
+ end
180
+ end
181
+ end
182
+ end
159
183
 
160
184
  protected
161
185
  def create_person(params)
162
186
  Person.new(params)
163
187
  end
188
+
189
+ def assert_valid(email)
190
+ assert_nil ValidatesEmailFormatOf::validate_email_format(email)
191
+ end
192
+
193
+ def assert_invalid(email)
194
+ err = ValidatesEmailFormatOf::validate_email_format(email)
195
+ assert_equal 1, err.size
196
+ end
164
197
 
165
198
  def save_passes(p, email = '')
166
- assert p.valid?, " validating #{email}"
199
+ assert p.valid?, " #{email} should pass"
167
200
  assert p.save
168
201
  if ActiveRecord::VERSION::MAJOR >= 3
169
202
  assert p.errors[:email].empty?
@@ -173,7 +206,7 @@ class ValidatesEmailFormatOfTest < TEST_CASE
173
206
  end
174
207
 
175
208
  def save_fails(p, email = '')
176
- assert !p.valid?, " validating #{email}"
209
+ assert !p.valid?, " #{email} should fail"
177
210
  assert !p.save
178
211
  if ActiveRecord::VERSION::MAJOR >= 3
179
212
  assert_equal 1, p.errors[:email].size
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: validates_email_format_of
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 11
4
5
  prerelease: false
5
6
  segments:
6
7
  - 1
7
8
  - 4
8
- - 5
9
- version: 1.4.5
9
+ - 6
10
+ version: 1.4.6
10
11
  platform: ruby
11
12
  authors:
12
13
  - Alex Dunae
@@ -14,7 +15,7 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2011-01-20 00:00:00 -08:00
18
+ date: 2011-05-02 00:00:00 -07:00
18
19
  default_executable:
19
20
  dependencies: []
20
21
 
@@ -26,13 +27,11 @@ extensions: []
26
27
 
27
28
  extra_rdoc_files:
28
29
  - README.rdoc
29
- - CHANGELOG.rdoc
30
30
  - MIT-LICENSE
31
31
  files:
32
32
  - MIT-LICENSE
33
33
  - init.rb
34
34
  - rakefile.rb
35
- - CHANGELOG.rdoc
36
35
  - README.rdoc
37
36
  - lib/validates_email_format_of.rb
38
37
  - test/fixtures/person.rb
@@ -56,6 +55,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
56
55
  requirements:
57
56
  - - ">="
58
57
  - !ruby/object:Gem::Version
58
+ hash: 3
59
59
  segments:
60
60
  - 0
61
61
  version: "0"
@@ -64,6 +64,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
64
64
  requirements:
65
65
  - - ">="
66
66
  - !ruby/object:Gem::Version
67
+ hash: 3
67
68
  segments:
68
69
  - 0
69
70
  version: "0"
data/CHANGELOG.rdoc DELETED
@@ -1,45 +0,0 @@
1
- = CHANGELOG
2
-
3
- == Version 1.4.4
4
-
5
- * https://github.com/alexdunae/validates_email_format_of/compare/1.4.3...1.4.4
6
-
7
- == Version 1.4.3
8
-
9
- * https://github.com/alexdunae/validates_email_format_of/compare/1.4.2...1.4.3
10
-
11
- == Version 1.4.2
12
-
13
- * See https://github.com/alexdunae/validates_email_format_of/compare/1.4.1...1.4.2
14
-
15
- == Version 1.4.1 (the George Anderson and 'history' edition)
16
- * don't allow domains with underscores
17
- * removed extra spaces in validation messages
18
- * updated tests for Rails 2.3+
19
-
20
- == Version 1.4 (the Denis Ahearn edition)
21
- * added ability to run validation tests without touching ActiveRecord or a database
22
-
23
- == Version 1.3.1 (the Github edition)
24
- * updated for github
25
-
26
- == Version 1.3 (the Travis Sinnott edition)
27
- * added optional MX record check
28
- * now available as a gem
29
-
30
- == Version 1.2.1 (the RTFM edition)
31
- * added support for quoted local parts
32
- * added length checks for domain and local parts
33
- * corrected escaped character support for RFC 3696 Errata
34
- * added :allow_blank option
35
- * added :unless option
36
-
37
- == Version 1.2 (the Ismael Santos Kafeltz and Michael MacDonald edition)
38
- * added support for un-escaped and escaped special characters in the local part, per RFC 3696
39
- * added :allow_nil option
40
-
41
- == Version 1.1 (the Francis Hwang edition)
42
- * moved Regexp out of class methods into the ValidatesEmailFormatOf module
43
-
44
- == Version 1.0
45
- * initial version