Permalink
Browse files

email validation added and url validation improved

  • Loading branch information...
molte committed Sep 11, 2009
1 parent e384f5a commit 66fa41b3c894eb7defeade24817d4ed42c36f92a
Showing with 74 additions and 15 deletions.
  1. +25 −6 lib/acts_as_url.rb
  2. +47 −9 test/acts_as_url_test.rb
  3. +2 −0 test/schema.rb
View
@@ -8,9 +8,10 @@ def self.included(base)
self.default_protocols = %w( http https )
module ClassMethods
- URL_SUBDOMAINS_PATTERN = '(?:[-\w]+\.)+'
- URL_TLD_PATTERN = '[a-z]{2,6}'
+ URL_SUBDOMAINS_PATTERN = '(?:[a-z0-9-]+\.)+'
+ URL_TLD_PATTERN = '(?:[a-z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|jobs|museum)'
URL_PORT_PATTERN = '(?::\d{1,5})?'
+ EMAIL_NAME_PATTERN = '[\w.%+-]+'
attr_accessor :protocols
@@ -22,7 +23,7 @@ def acts_as_url(*attributes)
# Set default protocols
self.protocols[attribute] ||= ActsAsUrl.default_protocols
- add_url_validation(attribute, self.protocols[attribute].to_a)
+ validates_url(attribute, :protocols => self.protocols[attribute].to_a)
# Define before save callback
callback_name = "convert_#{attribute}_to_url".to_sym
@@ -47,9 +48,22 @@ def url.to_uri
send(:include, InstanceMethods)
end
- private
- def add_url_validation(attribute, protocols)
- validates_format_of(attribute, :with => /\A(?:(?:#{protocols.join('|')}):\/\/)?#{URL_SUBDOMAINS_PATTERN + URL_TLD_PATTERN + URL_PORT_PATTERN}(?:\/\S*)?\z/, :allow_blank => true)
+ protected
+ def validates_url(*attr_names)
+ options = attr_names.extract_options!
+ protocol_pattern = "(?:(?:#{ (options.delete(:protocols) || ActsAsUrl.default_protocols).map { |p| ActsAsUrl.escape_regex p } * '|' }):\/\/)?"
+ port_pattern = options[:ports] ? "(?: :#{ options.delete(:ports).map { |p| ActsAsUrl.escape_regex p } * '|' } )" : URL_PORT_PATTERN
+
+ validates_format_of(*attr_names << { :allow_blank => true,
+ :with => /\A #{protocol_pattern + URL_SUBDOMAINS_PATTERN + URL_TLD_PATTERN + port_pattern} (?:\/\S*)? \z/ix }.merge(options))
+ end
+
+ def validates_email(*attr_names)
+ options = attr_names.extract_options!
+
+ validates_format_of(*attr_names << { :allow_blank => true,
+ # Regex inspired by rick olson's restful-authentication plugin
+ :with => /\A #{EMAIL_NAME_PATTERN} @ #{URL_SUBDOMAINS_PATTERN + URL_TLD_PATTERN} \z/ix }.merge(options))
end
end
@@ -84,4 +98,9 @@ def url_without_protocol(url, protocol)
end
+ # Escapes all regular expression tokens in a given string.
+ def self.escape_regex(regex_str)
+ regex_str.to_s.gsub(/[[\\^$.|?*+()\/]/) { |token_char| '\\' + token_char[0] }
+ end
+
end
View
@@ -5,53 +5,91 @@ class ActsAsUrlTest < Test::Unit::TestCase # ActiveSupport::TestCase
class Item < ActiveRecord::Base
acts_as_url :website, :repository => 'git'
+ validates_url :second_website, :ports => [ 80, 8080 ]
+ validates_email :email
end
def test_schema_has_loaded_correctly
assert_not_nil Item.all
end
- # Validation tests
- def test_validation_when_no_protocol_or_path
+ # Url validation tests
+ def test_url_validation_when_no_protocol_or_path
@item.website = 'example.com'
assert @item.valid?
end
- def test_validation_when_no protocol_but_path
+ def test_url_validation_when_no_protocol_but_path
@item.website = 'example.info/directory/page.html?query=true&still=true#hash'
assert @item.valid?
end
- def test_validation_when_protocol
+ def test_url_validation_when_protocol
@item.website = 'https://example.com/'
assert @item.valid?
end
- def test_validation_when_subdomains
+ def test_url_validation_when_subdomains
@item.website = 'dk.subdomain.example.net'
assert @item.valid?
end
- def test_validation_when_port
+ def test_url_validation_when_port
@item.website = 'http://example.com:8080/'
assert @item.valid?
end
- def test_validation_when_no_tld
+ def test_url_validation_when_no_tld
@item.website = 'example'
assert @item.invalid?
end
- def test_validation_when_wrong_protocol
+ def test_url_validation_when_wrong_tld
+ @item.website = 'example.abc'
+ assert @item.invalid?
+ end
+
+ def test_url_validation_when_wrong_protocol
@item.website = 'ftp://example.com/'
assert @item.invalid?
end
- def test_validation_when_blank
+ def test_url_validation_when_blank
@item.website = ''
assert @item.valid?
end
+ def test_url_validation_when_wrong_port
+ @item.second_website = 'example.com:123'
+ assert @item.invalid?
+ end
+
+ # Email validation tests
+ def test_email_validation_when_no_name
+ @item.email = '@example.com'
+ assert @item.invalid?
+ end
+
+ def test_email_validation_when_no_at
+ @item.email = 'nameexample.com'
+ assert @item.invalid?
+ end
+
+ def test_email_validation_when_invalid_domain
+ @item.email = 'name@in!valid.com'
+ assert @item.invalid?
+ end
+
+ def test_email_validation_when_subdomains
+ @item.email = 'name@sub.example.com'
+ assert @item.valid?
+ end
+
+ def test_email_validation_when_blank
+ @item.email = ''
+ assert @item.valid?
+ end
+
# Convertion tests
def test_default_convertion
@item.website = 'example.com'
View
@@ -2,5 +2,7 @@
create_table :items, :force => true do |t|
t.string :website
t.string :repository
+ t.string :email
+ t.string :second_website
end
end

0 comments on commit 66fa41b

Please sign in to comment.