validates_email_format_of 1.4.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,33 @@
1
+ = CHANGELOG
2
+
3
+ == Version 1.4.1 (the George Anderson and 'history' edition)
4
+ * don't allow domains with underscores
5
+ * removed extra spaces in validation messages
6
+ * updated tests for Rails 2.3+
7
+
8
+ == Version 1.4 (the Denis Ahearn edition)
9
+ * added ability to run validation tests without touching ActiveRecord or a database
10
+
11
+ == Version 1.3.1 (the Github edition)
12
+ * updated for github
13
+
14
+ == Version 1.3 (the Travis Sinnott edition)
15
+ * added optional MX record check
16
+ * now available as a gem
17
+
18
+ == Version 1.2.1 (the RTFM edition)
19
+ * added support for quoted local parts
20
+ * added length checks for domain and local parts
21
+ * corrected escaped character support for RFC 3696 Errata
22
+ * added :allow_blank option
23
+ * added :unless option
24
+
25
+ == Version 1.2 (the Ismael Santos Kafeltz and Michael MacDonald edition)
26
+ * added support for un-escaped and escaped special characters in the local part, per RFC 3696
27
+ * added :allow_nil option
28
+
29
+ == Version 1.1 (the Francis Hwang edition)
30
+ * moved Regexp out of class methods into the ValidatesEmailFormatOf module
31
+
32
+ == Version 1.0
33
+ * initial version
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2006-09 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,77 @@
1
+ = validates_email_format_of Gem and Rails Plugin
2
+
3
+ Validate e-mail addresses against RFC 2822 and RFC 3696.
4
+
5
+ == Installation
6
+
7
+ Installing as a gem:
8
+
9
+ gem sources -a http://gems.github.com
10
+ gem install alexdunae-validates_email_format_of
11
+
12
+ Installing as a Ruby on Rails plugin:
13
+
14
+ ./script/plugin install http://github.com/alexdunae/validates_email_format_of.git
15
+
16
+
17
+ == Usage
18
+
19
+ class Person < ActiveRecord::Base
20
+ validates_email_format_of :email
21
+ end
22
+
23
+ As of version 1.4, it's possible to run e-mail validation tests (including MX
24
+ checks) without using ActiveRecord or even touching a database. The
25
+ <tt>validate_email_format</tt> method will return <tt>nil</tt> on a valid
26
+ e-mail address or an array of error messages for invalid addresses.
27
+
28
+ results = ValidatesEmailFormatOf::validate_email_format(email, options)
29
+
30
+ if results.nil?
31
+ # success!
32
+ else
33
+ puts results.join(', ')
34
+ end
35
+
36
+
37
+ === Options
38
+
39
+ :message
40
+ String. A custom error message (default is: " does not appear to be a valid e-mail address")
41
+ :on
42
+ Symbol. Specifies when this validation is active (default is :save, other options :create, :update)
43
+ :allow_nil
44
+ Boolean. Allow nil values (default is false)
45
+ :allow_blank
46
+ Boolean. Allow blank values (default is false)
47
+ :check_mx
48
+ Boolean. Check domain for a valid MX record (default is false)
49
+ :if
50
+ Specifies a method, proc or string to call to determine if the validation should occur
51
+ (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The method,
52
+ proc or string should return or evaluate to a true or false value.
53
+ :unless
54
+ See :if option.
55
+
56
+ == Testing
57
+
58
+ To execute the unit tests run <tt>rake test</tt>.
59
+
60
+ The unit tests for this plugin use an in-memory sqlite3 database.
61
+
62
+ == Resources
63
+
64
+ * http://github.com/alexdunae/validates_email_format_of
65
+ * http://code.dunae.ca/validates_email_format_of.html
66
+
67
+ == Credits
68
+
69
+ Written by Alex Dunae (dunae.ca), 2006-09.
70
+
71
+ Thanks to Francis Hwang (http://fhwang.net/) at Diversion Media for creating the 1.1 update.
72
+
73
+ Thanks to Travis Sinnott for creating the 1.3 update.
74
+
75
+ Thanks to Denis Ahearn at Riverock Technologies (http://www.riverocktech.com/) for creating the 1.4 update.
76
+
77
+ Thanks to George Anderson (http://github.com/george) and 'history' (http://github.com/history) for creating the 1.4.1 update.
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + '/rails/init'
@@ -0,0 +1,88 @@
1
+ module ValidatesEmailFormatOf
2
+ require 'resolv'
3
+
4
+ LocalPartSpecialChars = Regexp.escape('!#$%&\'*-/=?+-^_`{|}~')
5
+ LocalPartUnquoted = '(([[:alnum:]' + LocalPartSpecialChars + ']+[\.\+]+))*[[:alnum:]' + LocalPartSpecialChars + '+]+'
6
+ LocalPartQuoted = '\"(([[:alnum:]' + LocalPartSpecialChars + '\.\+]*|(\\\\[\x00-\xFF]))*)\"'
7
+ Regex = Regexp.new('^((' + LocalPartUnquoted + ')|(' + LocalPartQuoted + ')+)@(((\w+\-+[^_])|(\w+\.[^_]))*([a-z0-9-]{1,63})\.[a-z]{2,6}$)', Regexp::EXTENDED | Regexp::IGNORECASE)
8
+
9
+ def self.validate_email_domain(email)
10
+ domain = email.match(/\@(.+)/)[1]
11
+ Resolv::DNS.open do |dns|
12
+ @mx = dns.getresources(domain, Resolv::DNS::Resource::IN::MX)
13
+ end
14
+ @mx.size > 0 ? true : false
15
+ end
16
+
17
+ # Validates whether the specified value is a valid email address. Returns nil if the value is valid, otherwise returns an array
18
+ # containing one or more validation error messages.
19
+ #
20
+ # Configuration options:
21
+ # * <tt>message</tt> - A custom error message (default is: "does not appear to be a valid e-mail address")
22
+ # * <tt>check_mx</tt> - Check for MX records (default is false)
23
+ # * <tt>mx_message</tt> - A custom error message when an MX record validation fails (default is: "is not routable.")
24
+ # * <tt>with</tt> The regex to use for validating the format of the email address (default is ValidatesEmailFormatOf::Regex)</tt>
25
+ def self.validate_email_format(email, options={})
26
+ default_options = { :message => 'does not appear to be a valid e-mail address',
27
+ :check_mx => false,
28
+ :mx_message => 'is not routable.',
29
+ :with => ValidatesEmailFormatOf::Regex }
30
+ options.merge!(default_options) {|key, old, new| old} # merge the default options into the specified options, retaining all specified options
31
+
32
+ # local part max is 64 chars, domain part max is 255 chars
33
+ # TODO: should this decode escaped entities before counting?
34
+ begin
35
+ domain, local = email.reverse.split('@', 2)
36
+ rescue
37
+ return [ options[:message] ]
38
+ end
39
+
40
+ unless email =~ options[:with] and not email =~ /\.\./ and domain.length <= 255 and local.length <= 64
41
+ return [ options[:message] ]
42
+ end
43
+
44
+ if options[:check_mx] and !ValidatesEmailFormatOf::validate_email_domain(email)
45
+ return [ options[:mx_message] ]
46
+ end
47
+
48
+ return nil # represents no validation errors
49
+ end
50
+ end
51
+
52
+ module ActiveRecord
53
+ module Validations
54
+ module ClassMethods
55
+ # Validates whether the value of the specified attribute is a valid email address
56
+ #
57
+ # class User < ActiveRecord::Base
58
+ # validates_email_format_of :email, :on => :create
59
+ # end
60
+ #
61
+ # Configuration options:
62
+ # * <tt>message</tt> - A custom error message (default is: "does not appear to be a valid e-mail address")
63
+ # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update)
64
+ # * <tt>allow_nil</tt> - Allow nil values (default is false)
65
+ # * <tt>allow_blank</tt> - Allow blank values (default is false)
66
+ # * <tt>check_mx</tt> - Check for MX records (default is false)
67
+ # * <tt>mx_message</tt> - A custom error message when an MX record validation fails (default is: "is not routable.")
68
+ # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
69
+ # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
70
+ # method, proc or string should return or evaluate to a true or false value.
71
+ # * <tt>unless</tt> - See <tt>:if</tt>
72
+ def validates_email_format_of(*attr_names)
73
+ options = { :on => :save,
74
+ :allow_nil => false,
75
+ :allow_blank => false }
76
+ options.update(attr_names.pop) if attr_names.last.is_a?(Hash)
77
+
78
+ validates_each(attr_names, options) do |record, attr_name, value|
79
+ v = value.to_s
80
+ errors = ValidatesEmailFormatOf::validate_email_format(v, options)
81
+ errors.each do |error|
82
+ record.errors.add(attr_name, error)
83
+ end unless errors.nil?
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'validates_email_format_of'
data/rakefile.rb ADDED
@@ -0,0 +1,28 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => [:clean_log, :test]
7
+
8
+ desc 'Remove the old log file'
9
+ task :clean_log do
10
+ "rm -f #{File.dirname(__FILE__)}/test/debug.log" if File.exists?(File.dirname(__FILE__) + '/test/debug.log')
11
+ end
12
+
13
+ desc 'Test the validates_email_format_of plugin.'
14
+ Rake::TestTask.new(:test) do |t|
15
+ t.libs << 'lib'
16
+ t.pattern = 'test/**/*_test.rb'
17
+ t.verbose = true
18
+ end
19
+
20
+ desc 'Generate documentation for the validates_email_format_of plugin.'
21
+ Rake::RDocTask.new(:rdoc) do |rdoc|
22
+ rdoc.rdoc_dir = 'rdoc'
23
+ rdoc.title = 'validates_email_format_of plugin'
24
+ rdoc.options << '--line-numbers --inline-source'
25
+ rdoc.rdoc_files.include('README')
26
+ rdoc.rdoc_files.include('TODO')
27
+ rdoc.rdoc_files.include('lib/**/*.rb')
28
+ end
@@ -0,0 +1,3 @@
1
+ existing:
2
+ id: 1
3
+ email: test@example.com
@@ -0,0 +1,12 @@
1
+ class Person < ActiveRecord::Base
2
+ validates_email_format_of :email,
3
+ :on => :create,
4
+ :message => 'fails with custom message',
5
+ :allow_nil => true
6
+ end
7
+
8
+ class MxRecord < ActiveRecord::Base
9
+ validates_email_format_of :email,
10
+ :on => :create,
11
+ :check_mx => true
12
+ 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,40 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+ RAILS_ROOT = File.dirname(__FILE__)
3
+
4
+ require 'rubygems'
5
+ require 'test/unit'
6
+ require 'active_record'
7
+ require 'active_record/fixtures'
8
+ require "#{File.dirname(__FILE__)}/../init"
9
+
10
+
11
+ config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
12
+ ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
13
+ ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'plugin_test'])
14
+
15
+ load(File.dirname(__FILE__) + "/schema.rb") if File.exist?(File.dirname(__FILE__) + "/schema.rb")
16
+
17
+ if ActiveSupport.const_defined?(:TestCase)
18
+ ActiveSupport::TestCase.send(:include, ActiveRecord::TestFixtures)
19
+ TEST_CASE = ActiveSupport::TestCase
20
+ else
21
+ TEST_CASE = Test::Unit::TestCase
22
+ end
23
+
24
+ TEST_CASE.fixture_path = File.dirname(__FILE__) + "/fixtures/"
25
+ $LOAD_PATH.unshift(TEST_CASE.fixture_path)
26
+
27
+ class TEST_CASE #:nodoc:
28
+ def create_fixtures(*table_names)
29
+ if block_given?
30
+ Fixtures.create_fixtures(TEST_CASE.fixture_path, table_names) { yield }
31
+ else
32
+ Fixtures.create_fixtures(TEST_CASE.fixture_path, table_names)
33
+ end
34
+ end
35
+
36
+ self.use_transactional_fixtures = false
37
+
38
+ self.use_instantiated_fixtures = false
39
+ end
40
+
@@ -0,0 +1,147 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class ValidatesEmailFormatOfTest < TEST_CASE
4
+ fixtures :people, :peoplemx
5
+
6
+ def setup
7
+ @valid_email = 'valid@example.com'
8
+ @invalid_email = 'invalid@example.'
9
+ end
10
+
11
+ 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
15
+ end
16
+
17
+ def test_should_allow_valid_email_addresses
18
+ ['valid@example.com',
19
+ 'Valid@test.example.com',
20
+ 'valid+valid123@test.example.com',
21
+ 'valid_valid123@test.example.com',
22
+ 'valid-valid+123@test.example.co.uk',
23
+ 'valid-valid+1.23@test.example.com.au',
24
+ 'valid@example.co.uk',
25
+ 'v@example.com',
26
+ 'valid@example.ca',
27
+ 'valid_@example.com',
28
+ 'valid123.456@example.org',
29
+ 'valid123.456@example.travel',
30
+ 'valid123.456@example.museum',
31
+ 'valid@example.mobi',
32
+ 'valid@example.info',
33
+ 'valid-@example.com',
34
+ # from RFC 3696, page 6
35
+ 'customer/department=shipping@example.com',
36
+ '$A12345@example.com',
37
+ '!def!xyz%abc@example.com',
38
+ '_somename@example.com',
39
+ # apostrophes
40
+ "test'test@example.com",
41
+ ].each do |email|
42
+ p = create_person(:email => email)
43
+ save_passes(p, email)
44
+ end
45
+ end
46
+
47
+ def test_should_not_allow_invalid_email_addresses
48
+ ['invalid@example-com',
49
+ # period can not start local part
50
+ '.invalid@example.com',
51
+ # period can not end local part
52
+ 'invalid.@example.com',
53
+ # period can not appear twice consecutively in local part
54
+ 'invali..d@example.com',
55
+ # should not allow underscores in domain names
56
+ 'invalid@ex_mple.com',
57
+ 'invalid@example.com.',
58
+ 'invalid@example.com_',
59
+ 'invalid@example.com-',
60
+ 'invalid-example.com',
61
+ 'invalid@example.b#r.com',
62
+ 'invalid@example.c',
63
+ 'invali d@example.com',
64
+ 'invalidexample.com',
65
+ 'invalid@example.'].each do |email|
66
+ p = create_person(:email => email)
67
+ save_fails(p, email)
68
+ end
69
+ end
70
+
71
+ # from http://www.rfc-editor.org/errata_search.php?rfc=3696
72
+ def test_should_allow_quoted_characters
73
+ ['"Abc\@def"@example.com',
74
+ '"Fred\ Bloggs"@example.com',
75
+ '"Joe.\\Blow"@example.com',
76
+ ].each do |email|
77
+ p = create_person(:email => email)
78
+ save_passes(p, email)
79
+ end
80
+ end
81
+
82
+ # from http://tools.ietf.org/html/rfc3696, page 5
83
+ # corrected in http://www.rfc-editor.org/errata_search.php?rfc=3696
84
+ def test_should_not_allow_escaped_characters_without_quotes
85
+ ['Fred\ Bloggs_@example.com',
86
+ 'Abc\@def+@example.com',
87
+ 'Joe.\\Blow@example.com'
88
+ ].each do |email|
89
+ p = create_person(:email => email)
90
+ save_fails(p, email)
91
+ end
92
+ end
93
+
94
+ def test_should_check_length_limits
95
+ ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@example.com',
96
+ 'test@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com'
97
+ ].each do |email|
98
+ p = create_person(:email => email)
99
+ save_fails(p, email)
100
+ end
101
+ end
102
+
103
+ def test_should_respect_validate_on_option
104
+ p = create_person(:email => @valid_email)
105
+ save_passes(p)
106
+
107
+ # we only asked to validate on :create so this should fail
108
+ assert p.update_attributes(:email => @invalid_email)
109
+ assert_equal @invalid_email, p.email
110
+ end
111
+
112
+ def test_should_allow_custom_error_message
113
+ p = create_person(:email => @invalid_email)
114
+ save_fails(p)
115
+ assert_equal 'fails with custom message', p.errors.on(:email)
116
+ end
117
+
118
+ def test_should_allow_nil
119
+ p = create_person(:email => nil)
120
+ save_passes(p)
121
+ end
122
+
123
+ def test_check_mx
124
+ pmx = MxRecord.new(:email => 'test@dunae.ca')
125
+ save_passes(pmx)
126
+
127
+ pmx = MxRecord.new(:email => 'test@example.com')
128
+ save_fails(pmx)
129
+ end
130
+
131
+ protected
132
+ def create_person(params)
133
+ Person.new(params)
134
+ end
135
+
136
+ def save_passes(p, email = '')
137
+ assert p.valid?, " validating #{email}"
138
+ assert p.save
139
+ assert_nil p.errors.on(:email)
140
+ end
141
+
142
+ def save_fails(p, email = '')
143
+ assert !p.valid?, " validating #{email}"
144
+ assert !p.save
145
+ assert p.errors.on(:email)
146
+ end
147
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: validates_email_format_of
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.4.1
5
+ platform: ruby
6
+ authors:
7
+ - Alex Dunae
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-26 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Validate e-mail addresses against RFC 2822 and RFC 3696.
17
+ email: code@dunae.ca
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.rdoc
24
+ - CHANGELOG.rdoc
25
+ - MIT-LICENSE
26
+ files:
27
+ - init.rb
28
+ - rakefile.rb
29
+ - lib/validates_email_format_of.rb
30
+ - rails/init.rb
31
+ - README.rdoc
32
+ - CHANGELOG.rdoc
33
+ - MIT-LICENSE
34
+ has_rdoc: true
35
+ homepage: http://code.dunae.ca/validates_email_format_of.html
36
+ licenses: []
37
+
38
+ post_install_message:
39
+ rdoc_options:
40
+ - --title
41
+ - validates_email_format_of
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ version:
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ requirements: []
57
+
58
+ rubyforge_project:
59
+ rubygems_version: 1.3.5
60
+ signing_key:
61
+ specification_version: 3
62
+ summary: Validate e-mail addresses against RFC 2822 and RFC 3696.
63
+ test_files:
64
+ - test/validates_email_format_of_test.rb
65
+ - test/test_helper.rb
66
+ - test/schema.rb
67
+ - test/fixtures/person.rb
68
+ - test/fixtures/people.yml