vjt-email_validator 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,45 @@
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
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2006-11 Alex Dunae
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,67 @@
1
+ = email_validator ActiveModel::EachValidator
2
+
3
+ Validate e-mail addresses against RFC 2822 and RFC 3696.
4
+
5
+ == Installation
6
+
7
+ gem 'vjt-email_validator', :git => 'git://github.com/vjt/email_validator'
8
+
9
+ == Usage
10
+
11
+ Standalone:
12
+
13
+ EmailValidator.valid?(email) # => true or false
14
+
15
+ Inside an ActiveRecord model:
16
+
17
+ class Person < ActiveRecord::Base
18
+ validates :email, :email => true
19
+ end
20
+
21
+ === Options
22
+
23
+ Giving `:email => true` to the `validate` method uses the following default options.
24
+ Customize them using `:email => { .. }`; E.g. `:email => {:check_mx => true}`
25
+
26
+ :message
27
+ String. A custom error message (default is: "does not appear to be a valid e-mail address")
28
+ :mx_message
29
+ String. A custom error message displayed when there is no MX for the given e-mail address
30
+ (default is: "is not routable")
31
+ :multiple_message
32
+ String. A custom error message displayed when one of the e-mail addresses in the record
33
+ is invalid (default is "appears to contain an invalid e-mail address)
34
+ :multiple
35
+ Boolean. Allows multiple email addresses separated by space and/or comma/colon
36
+ :check_mx
37
+ Boolean. Check domain for a valid MX record (default is false)
38
+ :local_length
39
+ Maximum number of characters allowed in the local part (default is 64)
40
+ :domain_length
41
+ Maximum number of characters allowed in the domain part (default is 255)
42
+
43
+ == Testing
44
+
45
+ To execute the unit tests run <tt>rake test</tt>.
46
+
47
+ The unit tests for this plugin use an in-memory sqlite3 database.
48
+
49
+ == Resources
50
+
51
+ * Based on http://github.com/alexdunae/validates_email_format_of
52
+ * http://github.com/vjt/email_validator
53
+
54
+ == Original Credits
55
+
56
+ Written by Alex Dunae (dunae.ca), 2006-11.
57
+
58
+ Many thanks to the plugin's recent contributors: https://github.com/alexdunae/validates_email_format_of/contributors
59
+
60
+ Thanks to Francis Hwang (http://fhwang.net/) at Diversion Media for creating the 1.1 update.
61
+ Thanks to Travis Sinnott for creating the 1.3 update.
62
+ Thanks to Denis Ahearn at Riverock Technologies (http://www.riverocktech.com/) for creating the 1.4 update.
63
+ Thanks to George Anderson (http://github.com/george) and 'history' (http://github.com/history) for creating the 1.4.1 update.
64
+
65
+ == Rewrite
66
+
67
+ Rewrote by Marcello Barnaba (vjt@openssl.it), 2011-02 as an ActiveModel::EachValidator
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'email_validator'
@@ -0,0 +1,93 @@
1
+ # encoding: utf-8
2
+ require 'active_model'
3
+ require 'resolv'
4
+
5
+ class EmailValidator < ActiveModel::EachValidator
6
+
7
+ local_part_special_chars = Regexp.escape('!#$%&\'*-/=?+-^_`{|}~')
8
+ local_part_unquoted = '(?:[[:alnum:]' + local_part_special_chars + ']+[\.\+])*[[:alnum:]' + local_part_special_chars + '+]'
9
+ local_part_quoted = '\"(?:[[:alnum:]' + local_part_special_chars + '\.]|\\\\[\x00-\xFF])*\"'
10
+ domain_part = '@(?:(?:(?:\w+\-+[^_])|(?:\w+\.[a-z0-9-]*))*(?:[a-z0-9-]{1,63})\.[a-z]{2,6}(?:\.[a-z]{2,6})?'
11
+ Pattern = Regexp.new('\A(?:' + local_part_unquoted + '+|' + local_part_quoted + '+)' + domain_part + '\Z)', Regexp::EXTENDED | Regexp::IGNORECASE, 'n').freeze
12
+ Separator = /[;,\s]\s*/.freeze # for multiple e-mail addresses
13
+ Defaults = {
14
+ :message => I18n.t(:invalid_email_address, :scope => [:activerecord, :errors, :messages], :default => 'does not appear to be a valid e-mail address'),
15
+ :multiple_message => I18n.t(:invalid_multiple_email, :scope => [:activerecord, :errors, :messages], :default => 'appears to contain an invalid e-mail address'),
16
+ :mx_message => I18n.t(:unroutable_email_address, :scope => [:activerecord, :errors, :messages], :default => 'is not routable'),
17
+ :check_mx => false,
18
+ :with => Pattern,
19
+ :local_length => 64,
20
+ :domain_length => 255
21
+ }.freeze
22
+
23
+ # Validates whether the specified value is a valid email address,
24
+ # and uses record.errors.add() to add the error if the provided
25
+ # value is not valid.
26
+ #
27
+ # Configuration options:
28
+ # * <tt>message</tt> - A custom error message
29
+ # (default: "does not appear to be a valid e-mail address")
30
+ # * <tt>check_mx</tt> - Check for MX records
31
+ # (default: false)
32
+ # * <tt>mx_message</tt> - A custom error message when an MX record validation fails
33
+ # (default: "is not routable.")
34
+ # * <tt>with</tt> - The regex to use for validating the format of the email address
35
+ # (default: +Pattern+)</tt>
36
+ # * <tt>multiple</tt> - Allow multiple e-mail addresses, separated by +Separator+
37
+ # (default: false)
38
+ # * <tt>multiple_message</tt> - A custom error message shown when there are 2 or more addresses
39
+ # to validate and one or more is invalid
40
+ # (default: "appears to contain an invalid e-mail address)
41
+ # * <tt>local_length</tt> - Maximum number of characters allowed in the local part
42
+ # (default: 64)
43
+ # * <tt>domain_length</tt> - Maximum number of characters allowed in the domain part
44
+ # (default: 255)
45
+ def validate_each(record, attribute, value)
46
+ return if value.blank? # Use :presence => true
47
+ error = self.class.errors_on(value, self.options)
48
+ record.errors.add(attribute, :invalid, :message => error, :value => value) if error
49
+ end
50
+
51
+ class << self
52
+ def valid?(email, options = {})
53
+ errors_on(email, options).nil?
54
+ end
55
+
56
+ def errors_on(email, options)
57
+ options = Defaults.merge(options)
58
+ options[:multiple] ? validate_many(email, options) : validate_one(email, options)
59
+ end
60
+
61
+ private
62
+ def validate_many(value, options)
63
+ emails = value.split(Separator)
64
+ errors = emails.map {|addr| validate_one(addr, options)}
65
+ errors.compact!
66
+ options[emails.size == 1 ? :message : :multiple_message] unless errors.empty?
67
+ end
68
+
69
+ def validate_one(value, options)
70
+ local, domain = value.split('@', 2)
71
+ if local.nil? || local.length > options[:local_length] or
72
+ domain.nil? || domain.length > options[:domain_length] or
73
+ value !~ options[:with]
74
+ options[:message]
75
+
76
+ elsif options[:check_mx] && !validate_email_domain(domain)
77
+ options[:mx_message]
78
+
79
+ end
80
+ end
81
+
82
+ def validate_email_domain(domain)
83
+ Resolv::DNS.open do |dns|
84
+ dns.getresources(domain, Resolv::DNS::Resource::IN::MX).size > 0
85
+ end
86
+
87
+ rescue Errno::ECONNREFUSED, NoMethodError
88
+ # DNS is not available - thus return true
89
+ true
90
+ end
91
+
92
+ end
93
+ end
data/rakefile.rb ADDED
@@ -0,0 +1,30 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ require 'pathname'
6
+
7
+ desc 'Default: run unit tests.'
8
+ task :default => [:clean, :test]
9
+
10
+ desc 'Remove the old log file'
11
+ task :clean do
12
+ Pathname(__FILE__).dirname.join('test', 'debug.log').unlink rescue nil
13
+ end
14
+
15
+ desc 'Test the email validator.'
16
+ Rake::TestTask.new(:test) do |t|
17
+ t.libs << 'lib'
18
+ t.pattern = 'test/**/*_test.rb'
19
+ t.verbose = true
20
+ end
21
+
22
+ desc 'Generate documentation for the email validator.'
23
+ Rake::RDocTask.new(:rdoc) do |rdoc|
24
+ rdoc.rdoc_dir = 'rdoc'
25
+ rdoc.title = 'email_validator'
26
+ rdoc.options << '--line-numbers --inline-source'
27
+ rdoc.rdoc_files.include('README')
28
+ rdoc.rdoc_files.include('TODO')
29
+ rdoc.rdoc_files.include('lib/**/*.rb')
30
+ end
data/test/database.yml ADDED
@@ -0,0 +1,3 @@
1
+ plugin_test:
2
+ adapter: sqlite3
3
+ database: ":memory:"
@@ -0,0 +1,165 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
+
3
+ class EmailValidatorTest < TEST_CASE
4
+ fixtures :people
5
+
6
+ def setup
7
+ @valid_email = 'valid@example.com'
8
+ @invalid_email = 'invalid@example.'
9
+ end
10
+
11
+ def test_should_allow_valid_email_addresses
12
+ ['valid@example.com',
13
+ 'Valid@test.example.com',
14
+ 'valid+valid123@test.example.com',
15
+ 'valid_valid123@test.example.com',
16
+ 'valid-valid+123@test.example.co.uk',
17
+ 'valid-valid+1.23@test.example.com.au',
18
+ 'valid@example.co.uk',
19
+ 'v@example.com',
20
+ 'valid@example.ca',
21
+ 'valid_@example.com',
22
+ 'valid123.456@example.org',
23
+ 'valid123.456@example.travel',
24
+ 'valid123.456@example.museum',
25
+ 'valid@example.mobi',
26
+ 'valid@example.info',
27
+ 'valid-@example.com',
28
+ # allow single character domain parts
29
+ 'valid@mail.x.example.com',
30
+ 'valid@x.com',
31
+ 'valid@example.w-dash.sch.uk',
32
+ # from RFC 3696, page 6
33
+ 'customer/department=shipping@example.com',
34
+ '$A12345@example.com',
35
+ '!def!xyz%abc@example.com',
36
+ '_somename@example.com',
37
+ # apostrophes
38
+ "test'test@example.com",
39
+ ].each do |email|
40
+ p = create_person(:email => email)
41
+ save_passes(p)
42
+ end
43
+ end
44
+
45
+ def test_should_not_allow_invalid_email_addresses
46
+ ['invalid@example-com',
47
+ # period can not start local part
48
+ '.invalid@example.com',
49
+ # period can not end local part
50
+ 'invalid.@example.com',
51
+ # period can not appear twice consecutively in local part
52
+ 'invali..d@example.com',
53
+ # should not allow underscores in domain names
54
+ 'invalid@ex_mple.com',
55
+ 'invalid@example.com.',
56
+ 'invalid@example.com_',
57
+ 'invalid@example.com-',
58
+ 'invalid-example.com',
59
+ 'invalid@example.b#r.com',
60
+ 'invalid@example.c',
61
+ 'invali d@example.com',
62
+ # unclosed quote
63
+ "\"a-17180061943-10618354-1993365053",
64
+ # too many special chars used to cause the regexp to hang
65
+ "-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++@foo",
66
+ 'invalidexample.com',
67
+ # should not allow special chars after a period in the domain
68
+ 'local@sub.)domain.com',
69
+ 'local@sub.#domain.com',
70
+ # one at a time
71
+ "foo@example.com\nexample@gmail.com",
72
+ 'invalid@example.'].each do |email|
73
+ p = create_person(:email => email)
74
+ save_fails(p)
75
+ end
76
+ end
77
+
78
+ # from http://www.rfc-editor.org/errata_search.php?rfc=3696
79
+ def test_should_allow_quoted_characters
80
+ ['"Abc\@def"@example.com',
81
+ '"Fred\ Bloggs"@example.com',
82
+ '"Joe.\\Blow"@example.com',
83
+ ].each do |email|
84
+ p = create_person(:email => email)
85
+ save_passes(p)
86
+ end
87
+ end
88
+
89
+ # from http://tools.ietf.org/html/rfc3696, page 5
90
+ # corrected in http://www.rfc-editor.org/errata_search.php?rfc=3696
91
+ def test_should_not_allow_escaped_characters_without_quotes
92
+ ['Fred\ Bloggs_@example.com',
93
+ 'Abc\@def+@example.com',
94
+ 'Joe.\\Blow@example.com'
95
+ ].each do |email|
96
+ p = create_person(:email => email)
97
+ save_fails(p)
98
+ end
99
+ end
100
+
101
+ def test_should_check_length_limits
102
+ ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@example.com',
103
+ 'test@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com'
104
+ ].each do |email|
105
+ p = create_person(:email => email)
106
+ save_fails(p)
107
+ end
108
+ end
109
+
110
+ def test_should_respect_validate_on_option
111
+ p = create_person(:email => @valid_email)
112
+ save_passes(p)
113
+
114
+ # we only asked to validate on :create so this should fail
115
+ assert p.update_attributes(:email => @invalid_email)
116
+ assert_equal @invalid_email, p.email
117
+ end
118
+
119
+ def test_should_allow_custom_error_message
120
+ p = create_person(:email => @invalid_email)
121
+ save_fails(p)
122
+ assert_equal ['fails with custom message'], p.errors[:email]
123
+ end
124
+
125
+ def test_should_allow_nil
126
+ p = create_person(:email => nil)
127
+ save_passes(p)
128
+ end
129
+
130
+ # TODO: find a future-proof way to check DNS records
131
+ def test_check_mx
132
+ pmx = MxRecord.new(:email => 'test@dunae.ca')
133
+ save_passes(pmx)
134
+
135
+ pmx = MxRecord.new(:email => 'test@somethingthathasntbeenregistered.com')
136
+ save_fails(pmx)
137
+ end
138
+
139
+ def test_should_be_usable_standalone
140
+ assert_equal true, EmailValidator.valid?('vjt@openssl.it')
141
+ assert_equal false, EmailValidator.valid?('antani')
142
+ end
143
+
144
+ def test_overriding_length_checks
145
+ assert_equal false, EmailValidator.valid?('valid@example.com', :local_length => 1)
146
+ assert_equal false, EmailValidator.valid?('valid@example.com', :domain_length => 1)
147
+ end
148
+
149
+ protected
150
+ def create_person(params)
151
+ Person.new(params)
152
+ end
153
+
154
+ def save_passes(p)
155
+ assert p.valid?, " validating #{p.email}"
156
+ assert p.save
157
+ assert_equal [], p.errors[:email]
158
+ end
159
+
160
+ def save_fails(p)
161
+ assert !p.valid?, " validating #{p.email}"
162
+ assert !p.save
163
+ assert_equal 1, p.errors[:email].size
164
+ end
165
+ end
@@ -0,0 +1,3 @@
1
+ existing:
2
+ id: 1
3
+ email: test@example.com
@@ -0,0 +1,9 @@
1
+ class Person < ActiveRecord::Base
2
+ validates :email, :email => {:message => 'fails with custom message'},
3
+ :on => :create
4
+ end
5
+
6
+ class MxRecord < ActiveRecord::Base
7
+ validates :email, :email => {:check_mx => true},
8
+ :on => :create
9
+ end
data/test/schema.rb ADDED
@@ -0,0 +1,10 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+ create_table :people, :force => true do |t|
3
+ t.column "email", :string
4
+ end
5
+
6
+ create_table :mx_records, :force => true do |t|
7
+ t.column "email", :string
8
+ end
9
+
10
+ end
@@ -0,0 +1,38 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'rubygems'
4
+ require 'test/unit'
5
+ require 'active_record'
6
+ require 'active_record/fixtures'
7
+ require "#{File.dirname(__FILE__)}/../init"
8
+
9
+ config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
10
+ ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
11
+ ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'plugin_test'])
12
+
13
+ load(File.dirname(__FILE__) + "/schema.rb") if File.exist?(File.dirname(__FILE__) + "/schema.rb")
14
+
15
+ if ActiveSupport.const_defined?(:TestCase)
16
+ ActiveSupport::TestCase.send(:include, ActiveRecord::TestFixtures)
17
+ TEST_CASE = ActiveSupport::TestCase
18
+ else
19
+ TEST_CASE = Test::Unit::TestCase
20
+ end
21
+
22
+ TEST_CASE.fixture_path = File.dirname(__FILE__) + "/fixtures/"
23
+ $:.unshift(TEST_CASE.fixture_path)
24
+
25
+ class TEST_CASE #:nodoc:
26
+ def create_fixtures(*table_names)
27
+ if block_given?
28
+ Fixtures.create_fixtures(TEST_CASE.fixture_path, table_names) { yield }
29
+ else
30
+ Fixtures.create_fixtures(TEST_CASE.fixture_path, table_names)
31
+ end
32
+ end
33
+
34
+ self.use_transactional_fixtures = false
35
+
36
+ self.use_instantiated_fixtures = false
37
+ end
38
+
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vjt-email_validator
3
+ version: !ruby/object:Gem::Version
4
+ hash: 1
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 5
9
+ - 1
10
+ version: 1.5.1
11
+ platform: ruby
12
+ authors:
13
+ - Marcello Barnaba
14
+ - Alex Dunae
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2011-02-28 00:00:00 +01:00
20
+ default_executable:
21
+ dependencies: []
22
+
23
+ description: ActiveModel::EachValidator to check for valid e-mail addresses
24
+ email: vjt@openssl.it
25
+ executables: []
26
+
27
+ extensions: []
28
+
29
+ extra_rdoc_files:
30
+ - README.rdoc
31
+ - CHANGELOG.rdoc
32
+ - MIT-LICENSE
33
+ files:
34
+ - MIT-LICENSE
35
+ - init.rb
36
+ - rakefile.rb
37
+ - CHANGELOG.rdoc
38
+ - README.rdoc
39
+ - lib/email_validator.rb
40
+ - test/email_validator_test.rb
41
+ - test/fixtures/person.rb
42
+ - test/schema.rb
43
+ - test/test_helper.rb
44
+ - test/database.yml
45
+ - test/fixtures/people.yml
46
+ has_rdoc: true
47
+ homepage: http://github.com/vjt/email_validator
48
+ licenses: []
49
+
50
+ post_install_message:
51
+ rdoc_options:
52
+ - --title
53
+ - email_validator
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 3
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ hash: 3
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ requirements: []
75
+
76
+ rubyforge_project:
77
+ rubygems_version: 1.4.1
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: Validate e-mail addresses against RFC 2822 and RFC 3696.
81
+ test_files:
82
+ - test/email_validator_test.rb
83
+ - test/fixtures/person.rb
84
+ - test/schema.rb
85
+ - test/test_helper.rb
86
+ - test/database.yml
87
+ - test/fixtures/people.yml