alexdunae-validates_email_format_of 1.4

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.
@@ -0,0 +1,28 @@
1
+ = CHANGELOG
2
+
3
+ == Version 1.4 (the Denis Ahearn edition)
4
+ * added ability to run validation tests without touching ActiveRecord or a database
5
+
6
+ == Version 1.3.1 (the Github edition)
7
+ * updated for github
8
+
9
+ == Version 1.3 (the Travis Sinnott edition)
10
+ * added optional MX record check
11
+ * now available as a gem
12
+
13
+ == Version 1.2.1 (the RTFM edition)
14
+ * added support for quoted local parts
15
+ * added length checks for domain and local parts
16
+ * corrected escaped character support for RFC 3696 Errata
17
+ * added :allow_blank option
18
+ * added :unless option
19
+
20
+ == Version 1.2 (the Ismael Santos Kafeltz and Michael MacDonald edition)
21
+ * added support for un-escaped and escaped special characters in the local part, per RFC 3696
22
+ * added :allow_nil option
23
+
24
+ == Version 1.1 (the Francis Hwang edition)
25
+ * moved Regexp out of class methods into the ValidatesEmailFormatOf module
26
+
27
+ == Version 1.0
28
+ * initial version
@@ -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.
@@ -0,0 +1,59 @@
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 git://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
+ === Options
24
+
25
+ :message
26
+ String. A custom error message (default is: " does not appear to be a valid e-mail address")
27
+ :on
28
+ Symbol. Specifies when this validation is active (default is :save, other options :create, :update)
29
+ :allow_nil
30
+ Boolean. Allow nil values (default is false)
31
+ :allow_blank
32
+ Boolean. Allow blank values (default is false)
33
+ :check_mx
34
+ Boolean. Check domain for a valid MX record (default is false)
35
+ :if
36
+ Specifies a method, proc or string to call to determine if the validation should occur
37
+ (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The method,
38
+ proc or string should return or evaluate to a true or false value.
39
+ :unless
40
+ See :if option.
41
+
42
+ == Testing
43
+
44
+ To execute the unit tests run <tt>rake test</tt>.
45
+
46
+ The unit tests for this plugin use an in-memory sqlite3 database.
47
+
48
+ == Resources
49
+
50
+ * http://github.com/alexdunae/validates_email_format_of
51
+ * http://code.dunae.ca/validates_email_format_of.html
52
+
53
+ == Credits
54
+
55
+ Written by Alex Dunae (dunae.ca), 2006-09.
56
+
57
+ Thanks to Francis Hwang (http://fhwang.net/) at Diversion Media for creating the 1.1 update.
58
+
59
+ Thanks to Travis Sinnott for creating the 1.3 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+\.))*\w{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
@@ -0,0 +1 @@
1
+ require 'validates_email_format_of'
@@ -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
@@ -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,33 @@
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
+ Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
18
+ $LOAD_PATH.unshift(Test::Unit::TestCase.fixture_path)
19
+
20
+ class Test::Unit::TestCase #:nodoc:
21
+ def create_fixtures(*table_names)
22
+ if block_given?
23
+ Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names) { yield }
24
+ else
25
+ Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names)
26
+ end
27
+ end
28
+
29
+ self.use_transactional_fixtures = false
30
+
31
+ self.use_instantiated_fixtures = false
32
+ end
33
+
@@ -0,0 +1,145 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class ValidatesEmailFormatOfTest < Test::Unit::TestCase
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
+ '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
+ 'invalidexample.com',
63
+ 'invalid@example.'].each do |email|
64
+ p = create_person(:email => email)
65
+ save_fails(p, email)
66
+ end
67
+ end
68
+
69
+ # from http://www.rfc-editor.org/errata_search.php?rfc=3696
70
+ def test_should_allow_quoted_characters
71
+ ['"Abc\@def"@example.com',
72
+ '"Fred\ Bloggs"@example.com',
73
+ '"Joe.\\Blow"@example.com',
74
+ ].each do |email|
75
+ p = create_person(:email => email)
76
+ save_passes(p, email)
77
+ end
78
+ end
79
+
80
+ # from http://tools.ietf.org/html/rfc3696, page 5
81
+ # corrected in http://www.rfc-editor.org/errata_search.php?rfc=3696
82
+ def test_should_not_allow_escaped_characters_without_quotes
83
+ ['Fred\ Bloggs_@example.com',
84
+ 'Abc\@def+@example.com',
85
+ 'Joe.\\Blow@example.com'
86
+ ].each do |email|
87
+ p = create_person(:email => email)
88
+ save_fails(p, email)
89
+ end
90
+ end
91
+
92
+ def test_should_check_length_limits
93
+ ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@example.com',
94
+ 'test@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com'
95
+ ].each do |email|
96
+ p = create_person(:email => email)
97
+ save_fails(p, email)
98
+ end
99
+ end
100
+
101
+ def test_should_respect_validate_on_option
102
+ p = create_person(:email => @valid_email)
103
+ save_passes(p)
104
+
105
+ # we only asked to validate on :create so this should fail
106
+ assert p.update_attributes(:email => @invalid_email)
107
+ assert_equal @invalid_email, p.email
108
+ end
109
+
110
+ def test_should_allow_custom_error_message
111
+ p = create_person(:email => @invalid_email)
112
+ save_fails(p)
113
+ assert_equal 'fails with custom message', p.errors.on(:email)
114
+ end
115
+
116
+ def test_should_allow_nil
117
+ p = create_person(:email => nil)
118
+ save_passes(p)
119
+ end
120
+
121
+ def test_check_mx
122
+ pmx = MxRecord.new(:email => 'test@dunae.ca')
123
+ save_passes(pmx)
124
+
125
+ pmx = MxRecord.new(:email => 'test@example.com')
126
+ save_fails(pmx)
127
+ end
128
+
129
+ protected
130
+ def create_person(params)
131
+ Person.new(params)
132
+ end
133
+
134
+ def save_passes(p, email = '')
135
+ assert p.valid?, " validating #{email}"
136
+ assert p.save
137
+ assert_nil p.errors.on(:email)
138
+ end
139
+
140
+ def save_fails(p, email = '')
141
+ assert !p.valid?, " validating #{email}"
142
+ assert !p.save
143
+ assert p.errors.on(:email)
144
+ end
145
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: alexdunae-validates_email_format_of
3
+ version: !ruby/object:Gem::Version
4
+ version: "1.4"
5
+ platform: ruby
6
+ authors:
7
+ - Alex Dunae
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-12-22 00:00:00 -08: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
+ post_install_message:
37
+ rdoc_options:
38
+ - --title
39
+ - validates_email_format_of
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ version:
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ version:
54
+ requirements: []
55
+
56
+ rubyforge_project:
57
+ rubygems_version: 1.2.0
58
+ signing_key:
59
+ specification_version: 2
60
+ summary: Validate e-mail addresses against RFC 2822 and RFC 3696.
61
+ test_files:
62
+ - test/validates_email_format_of_test.rb
63
+ - test/test_helper.rb
64
+ - test/schema.rb
65
+ - test/fixtures/person.rb
66
+ - test/fixtures/people.yml