validates_email_format_of 1.4.5 → 1.4.6
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 +5 -0
- data/lib/validates_email_format_of.rb +88 -49
- data/rakefile.rb +3 -4
- data/test/fixtures/person.rb +12 -0
- data/test/schema.rb +0 -5
- data/test/validates_email_format_of_test.rb +49 -16
- metadata +6 -5
- data/CHANGELOG.rdoc +0 -45
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
|
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
|
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 => [
|
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 => [
|
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
|
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 [
|
47
|
+
return [ opts[:message] ]
|
46
48
|
end
|
47
49
|
|
48
|
-
unless email =~
|
49
|
-
return [
|
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
|
53
|
-
return [
|
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
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
errors.
|
90
|
-
|
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
|
-
|
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
|
data/test/fixtures/person.rb
CHANGED
@@ -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
@@ -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
|
-
|
13
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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?, "
|
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?, "
|
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
|
-
-
|
9
|
-
version: 1.4.
|
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-
|
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
|