Use validates_email_format_of as a gem instead of a plugin

This commit is contained in:
Tom Hughes 2010-12-06 21:49:50 +00:00
parent 74fc891e9d
commit 90a7efcf4d
15 changed files with 1 additions and 482 deletions

View file

@ -11,6 +11,7 @@ gem 'httpclient'
gem 'SystemTimer', '>= 1.1.3', :require => 'system_timer'
gem 'sanitize'
gem 'rails-i18n-updater'
gem 'validates_email_format_of', '>= 1.4.2'
# Should only load if memcache is in use
gem 'memcached'

View file

@ -1,2 +0,0 @@
pkg
test/debug.log

View file

@ -1,33 +0,0 @@
= CHANGELOG
== Version 1.4.1 (the George Anderson and 'history' edition)
* don't allow domains with underscores
* removed extra spaces in validation messages
* updated tests for Rails 2.3+
== Version 1.4 (the Denis Ahearn edition)
* added ability to run validation tests without touching ActiveRecord or a database
== Version 1.3.1 (the Github edition)
* updated for github
== Version 1.3 (the Travis Sinnott edition)
* added optional MX record check
* now available as a gem
== Version 1.2.1 (the RTFM edition)
* added support for quoted local parts
* added length checks for domain and local parts
* corrected escaped character support for RFC 3696 Errata
* added :allow_blank option
* added :unless option
== Version 1.2 (the Ismael Santos Kafeltz and Michael MacDonald edition)
* added support for un-escaped and escaped special characters in the local part, per RFC 3696
* added :allow_nil option
== Version 1.1 (the Francis Hwang edition)
* moved Regexp out of class methods into the ValidatesEmailFormatOf module
== Version 1.0
* initial version

View file

@ -1,20 +0,0 @@
Copyright (c) 2006-09 Alex Dunae
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,77 +0,0 @@
= validates_email_format_of Gem and Rails Plugin
Validate e-mail addresses against RFC 2822 and RFC 3696.
== Installation
Installing as a gem:
gem sources -a http://gems.github.com
gem install alexdunae-validates_email_format_of
Installing as a Ruby on Rails plugin:
./script/plugin install http://github.com/alexdunae/validates_email_format_of.git
== Usage
class Person < ActiveRecord::Base
validates_email_format_of :email
end
As of version 1.4, it's possible to run e-mail validation tests (including MX
checks) without using ActiveRecord or even touching a database. The
<tt>validate_email_format</tt> method will return <tt>nil</tt> on a valid
e-mail address or an array of error messages for invalid addresses.
results = ValidatesEmailFormatOf::validate_email_format(email, options)
if results.nil?
# success!
else
puts results.join(', ')
end
=== Options
:message
String. A custom error message (default is: " does not appear to be a valid e-mail address")
:on
Symbol. Specifies when this validation is active (default is :save, other options :create, :update)
:allow_nil
Boolean. Allow nil values (default is false)
:allow_blank
Boolean. Allow blank values (default is false)
:check_mx
Boolean. Check domain for a valid MX record (default is false)
:if
Specifies a method, proc or string to call to determine if the validation should occur
(e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The method,
proc or string should return or evaluate to a true or false value.
:unless
See :if option.
== Testing
To execute the unit tests run <tt>rake test</tt>.
The unit tests for this plugin use an in-memory sqlite3 database.
== Resources
* http://github.com/alexdunae/validates_email_format_of
* http://code.dunae.ca/validates_email_format_of.html
== Credits
Written by Alex Dunae (dunae.ca), 2006-09.
Thanks to Francis Hwang (http://fhwang.net/) at Diversion Media for creating the 1.1 update.
Thanks to Travis Sinnott for creating the 1.3 update.
Thanks to Denis Ahearn at Riverock Technologies (http://www.riverocktech.com/) for creating the 1.4 update.
Thanks to George Anderson (http://github.com/george) and 'history' (http://github.com/history) for creating the 1.4.1 update.

View file

@ -1 +0,0 @@
require 'validates_email_format_of'

View file

@ -1,88 +0,0 @@
module ValidatesEmailFormatOf
require 'resolv'
LocalPartSpecialChars = Regexp.escape('!#$%&\'*-/=?+-^_`{|}~')
LocalPartUnquoted = '(([[:alnum:]' + LocalPartSpecialChars + ']+[\.\+]+))*[[:alnum:]' + LocalPartSpecialChars + '+]+'
LocalPartQuoted = '\"(([[:alnum:]' + LocalPartSpecialChars + '\.\+]*|(\\\\[\x00-\xFF]))*)\"'
Regex = Regexp.new('^((' + LocalPartUnquoted + ')|(' + LocalPartQuoted + ')+)@(((\w+\-+[^_])|(\w+\.[^_]))*([a-z0-9-]{1,63})\.[a-z]{2,6}$)', Regexp::EXTENDED | Regexp::IGNORECASE, 'n')
def self.validate_email_domain(email)
domain = email.match(/\@(.+)/)[1]
Resolv::DNS.open do |dns|
@mx = dns.getresources(domain, Resolv::DNS::Resource::IN::MX) + dns.getresources(domain, Resolv::DNS::Resource::IN::A)
end
@mx.size > 0 ? true : false
end
# Validates whether the specified value is a valid email address. Returns nil if the value is valid, otherwise returns an array
# containing one or more validation error messages.
#
# Configuration options:
# * <tt>message</tt> - A custom error message (default is: "does not appear to be a valid e-mail address")
# * <tt>check_mx</tt> - Check for MX records (default is false)
# * <tt>mx_message</tt> - A custom error message when an MX record validation fails (default is: "is not routable.")
# * <tt>with</tt> The regex to use for validating the format of the email address (default is ValidatesEmailFormatOf::Regex)</tt>
def self.validate_email_format(email, options={})
default_options = { :message => I18n.t(:invalid_email_address, :scope => [:activerecord, :errors, :messages], :default => 'does not appear to be a valid e-mail address'),
:check_mx => false,
:mx_message => I18n.t(:email_address_not_routable, :scope => [:activerecord, :errors, :messages], :default => 'is not routable'),
:with => ValidatesEmailFormatOf::Regex }
options.merge!(default_options) {|key, old, new| old} # merge the default options into the specified options, retaining all specified options
# local part max is 64 chars, domain part max is 255 chars
# TODO: should this decode escaped entities before counting?
begin
domain, local = email.reverse.split('@', 2)
rescue
return [ options[:message] ]
end
unless email =~ options[:with] and not email =~ /\.\./ and domain.length <= 255 and local.length <= 64
return [ options[:message] ]
end
if options[:check_mx] and !ValidatesEmailFormatOf::validate_email_domain(email)
return [ options[:mx_message] ]
end
return nil # represents no validation errors
end
end
module ActiveRecord
module Validations
module ClassMethods
# Validates whether the value of the specified attribute is a valid email address
#
# class User < ActiveRecord::Base
# validates_email_format_of :email, :on => :create
# end
#
# Configuration options:
# * <tt>message</tt> - A custom error message (default is: "does not appear to be a valid e-mail address")
# * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update)
# * <tt>allow_nil</tt> - Allow nil values (default is false)
# * <tt>allow_blank</tt> - Allow blank values (default is false)
# * <tt>check_mx</tt> - Check for MX records (default is false)
# * <tt>mx_message</tt> - A custom error message when an MX record validation fails (default is: "is not routable.")
# * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
# occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
# method, proc or string should return or evaluate to a true or false value.
# * <tt>unless</tt> - See <tt>:if</tt>
def validates_email_format_of(*attr_names)
options = { :on => :save,
:allow_nil => false,
:allow_blank => false }
options.update(attr_names.pop) if attr_names.last.is_a?(Hash)
validates_each(attr_names, options) do |record, attr_name, value|
v = value.to_s
errors = ValidatesEmailFormatOf::validate_email_format(v, options)
errors.each do |error|
record.errors.add(attr_name, error)
end unless errors.nil?
end
end
end
end
end

View file

@ -1,28 +0,0 @@
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
desc 'Default: run unit tests.'
task :default => [:clean_log, :test]
desc 'Remove the old log file'
task :clean_log do
"rm -f #{File.dirname(__FILE__)}/test/debug.log" if File.exists?(File.dirname(__FILE__) + '/test/debug.log')
end
desc 'Test the validates_email_format_of plugin.'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.pattern = 'test/**/*_test.rb'
t.verbose = true
end
desc 'Generate documentation for the validates_email_format_of plugin.'
Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'validates_email_format_of plugin'
rdoc.options << '--line-numbers --inline-source'
rdoc.rdoc_files.include('README')
rdoc.rdoc_files.include('TODO')
rdoc.rdoc_files.include('lib/**/*.rb')
end

View file

@ -1,3 +0,0 @@
plugin_test:
adapter: sqlite3
database: ":memory:"

View file

@ -1,3 +0,0 @@
existing:
id: 1
email: test@example.com

View file

@ -1,12 +0,0 @@
class Person < ActiveRecord::Base
validates_email_format_of :email,
:on => :create,
:message => 'fails with custom message',
:allow_nil => true
end
class MxRecord < ActiveRecord::Base
validates_email_format_of :email,
:on => :create,
:check_mx => true
end

View file

@ -1,10 +0,0 @@
ActiveRecord::Schema.define(:version => 0) do
create_table :people, :force => true do |t|
t.column "email", :string
end
create_table :mx_records, :force => true do |t|
t.column "email", :string
end
end

View file

@ -1,40 +0,0 @@
$:.unshift(File.dirname(__FILE__) + '/../lib')
RAILS_ROOT = File.dirname(__FILE__)
require 'rubygems'
require 'test/unit'
require 'active_record'
require 'active_record/fixtures'
require "#{File.dirname(__FILE__)}/../init"
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'plugin_test'])
load(File.dirname(__FILE__) + "/schema.rb") if File.exist?(File.dirname(__FILE__) + "/schema.rb")
if ActiveSupport.const_defined?(:TestCase)
ActiveSupport::TestCase.send(:include, ActiveRecord::TestFixtures)
TEST_CASE = ActiveSupport::TestCase
else
TEST_CASE = Test::Unit::TestCase
end
TEST_CASE.fixture_path = File.dirname(__FILE__) + "/fixtures/"
$LOAD_PATH.unshift(TEST_CASE.fixture_path)
class TEST_CASE #:nodoc:
def create_fixtures(*table_names)
if block_given?
Fixtures.create_fixtures(TEST_CASE.fixture_path, table_names) { yield }
else
Fixtures.create_fixtures(TEST_CASE.fixture_path, table_names)
end
end
self.use_transactional_fixtures = false
self.use_instantiated_fixtures = false
end

View file

@ -1,147 +0,0 @@
require File.dirname(__FILE__) + '/test_helper'
class ValidatesEmailFormatOfTest < TEST_CASE
fixtures :people, :peoplemx
def setup
@valid_email = 'valid@example.com'
@invalid_email = 'invalid@example.'
end
def test_without_activerecord
assert_nil ValidatesEmailFormatOf::validate_email_format('valid@example.com')
err = ValidatesEmailFormatOf::validate_email_format('valid@example-com')
assert_equal 1, err.size
end
def test_should_allow_valid_email_addresses
['valid@example.com',
'Valid@test.example.com',
'valid+valid123@test.example.com',
'valid_valid123@test.example.com',
'valid-valid+123@test.example.co.uk',
'valid-valid+1.23@test.example.com.au',
'valid@example.co.uk',
'v@example.com',
'valid@example.ca',
'valid_@example.com',
'valid123.456@example.org',
'valid123.456@example.travel',
'valid123.456@example.museum',
'valid@example.mobi',
'valid@example.info',
'valid-@example.com',
# from RFC 3696, page 6
'customer/department=shipping@example.com',
'$A12345@example.com',
'!def!xyz%abc@example.com',
'_somename@example.com',
# apostrophes
"test'test@example.com",
].each do |email|
p = create_person(:email => email)
save_passes(p, email)
end
end
def test_should_not_allow_invalid_email_addresses
['invalid@example-com',
# period can not start local part
'.invalid@example.com',
# period can not end local part
'invalid.@example.com',
# period can not appear twice consecutively in local part
'invali..d@example.com',
# should not allow underscores in domain names
'invalid@ex_mple.com',
'invalid@example.com.',
'invalid@example.com_',
'invalid@example.com-',
'invalid-example.com',
'invalid@example.b#r.com',
'invalid@example.c',
'invali d@example.com',
'invalidexample.com',
'invalid@example.'].each do |email|
p = create_person(:email => email)
save_fails(p, email)
end
end
# from http://www.rfc-editor.org/errata_search.php?rfc=3696
def test_should_allow_quoted_characters
['"Abc\@def"@example.com',
'"Fred\ Bloggs"@example.com',
'"Joe.\\Blow"@example.com',
].each do |email|
p = create_person(:email => email)
save_passes(p, email)
end
end
# from http://tools.ietf.org/html/rfc3696, page 5
# corrected in http://www.rfc-editor.org/errata_search.php?rfc=3696
def test_should_not_allow_escaped_characters_without_quotes
['Fred\ Bloggs_@example.com',
'Abc\@def+@example.com',
'Joe.\\Blow@example.com'
].each do |email|
p = create_person(:email => email)
save_fails(p, email)
end
end
def test_should_check_length_limits
['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@example.com',
'test@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com'
].each do |email|
p = create_person(:email => email)
save_fails(p, email)
end
end
def test_should_respect_validate_on_option
p = create_person(:email => @valid_email)
save_passes(p)
# we only asked to validate on :create so this should fail
assert p.update_attributes(:email => @invalid_email)
assert_equal @invalid_email, p.email
end
def test_should_allow_custom_error_message
p = create_person(:email => @invalid_email)
save_fails(p)
assert_equal 'fails with custom message', p.errors.on(:email)
end
def test_should_allow_nil
p = create_person(:email => nil)
save_passes(p)
end
def test_check_mx
pmx = MxRecord.new(:email => 'test@dunae.ca')
save_passes(pmx)
pmx = MxRecord.new(:email => 'test@example.com')
save_fails(pmx)
end
protected
def create_person(params)
Person.new(params)
end
def save_passes(p, email = '')
assert p.valid?, " validating #{email}"
assert p.save
assert_nil p.errors.on(:email)
end
def save_fails(p, email = '')
assert !p.valid?, " validating #{email}"
assert !p.save
assert p.errors.on(:email)
end
end

View file

@ -1,18 +0,0 @@
spec = Gem::Specification.new do |s|
s.name = 'validates_email_format_of'
s.version = '1.4.1'
s.summary = 'Validate e-mail addresses against RFC 2822 and RFC 3696.'
s.description = s.summary
s.extra_rdoc_files = ['README.rdoc', 'CHANGELOG.rdoc', 'MIT-LICENSE']
s.test_files = ['test/validates_email_format_of_test.rb','test/test_helper.rb','test/schema.rb','test/fixtures/person.rb', 'test/fixtures/people.yml']
s.files = ['init.rb','rakefile.rb', 'lib/validates_email_format_of.rb','rails/init.rb']
s.files << s.test_files
s.files << s.extra_rdoc_files
s.require_path = 'lib'
s.has_rdoc = true
s.rdoc_options << '--title' << 'validates_email_format_of'
s.author = "Alex Dunae"
s.email = "code@dunae.ca"
s.homepage = "http://code.dunae.ca/validates_email_format_of.html"
end