Skip to content

Instantly share code, notes, and snippets.

@rogerrohrbach
Created June 27, 2011 14:42
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save rogerrohrbach/1048992 to your computer and use it in GitHub Desktop.
Save rogerrohrbach/1048992 to your computer and use it in GitHub Desktop.
Active Model North American Telephone Number validator
# == Active Model North American Telephone Number Validator
# http://en.wikipedia.org/wiki/North_American_Numbering_Plan#Current_system
# [Author] Roger Rohrbach (roger@ecstatic.com)
class NanpValidator < ActiveModel::EachValidator
def self.matcher(require_area_code) # :nodoc:
%r{
(?<country_code> \+1 ){0}
(?<trunk_prefix> 1 ){0}
(?<delimiter> ([-\.]|\ +) ){0}
(?<area_code> [2-9]\d{2} ){0}
(?<exchange> [2-9]([02-9][0-9]|1[02-9]) ){0}
(?<station> \d{4} ){0}
^
\ *
((\g<country_code>|\g<trunk_prefix>)\g<delimiter>{0,1})*
(\(*\g<area_code>\)*){#{require_area_code ? '1' : '0,1'}}
\g<delimiter>{0,1}
\g<exchange>
\g<delimiter>{0,1}
\g<station>
\ *
$
}x
end
private_class_method :matcher
# <p><p>
# Validates a telephone number in the North American Numbering Plan.
# <p>
# Example:
# <p>
# class Person < ActiveRecord::Base
# validates :phone, :nanp => true
# end
# <p><p>
# Options:
# <p>
# * +require_area_code+ -
# consider number valid only if area code is present
# (default: +true+)
#
# * +allow_fictitious_numbers+ -
# allow numbers of the form 555-01<i>xx</i> or
# those with area code "958" (default: +false+)
# <p><p>
# e.g.:
# <p>
# class Person < ActiveRecord::Base
# validates :phone, :nanp => {require_area_code: false}
# end
def validate_each(record, attribute, value)
match = self.class.send(
:matcher,
({:require_area_code => true}.merge(options))[:require_area_code]
).match(value)
if match
if ["950", "958", "959", "976"].include?(match[:exchange])
record.errors[attribute] << "is not a subscriber number"
end
# http://en.wikipedia.org/wiki/Fictitious_telephone_number
unless options[:allow_fictitious_numbers]
if match[:area_code] == "958" ||
(match[:exchange] == "555" && match[:station] =~ /^01\d{2}$/)
record.errors[attribute] << "is fictitious"
end
end
else
record.errors[attribute] << "is not valid"
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment