Skip to content

Instantly share code, notes, and snippets.

@sundevilyang
Forked from rogerrohrbach/nanp_validator.rb
Created February 15, 2013 00:23
Show Gist options
  • Select an option

  • Save sundevilyang/4957639 to your computer and use it in GitHub Desktop.

Select an option

Save sundevilyang/4957639 to your computer and use it in GitHub Desktop.

Revisions

  1. Roger Rohrbach renamed this gist Jun 27, 2011. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. Roger Rohrbach created this gist Jun 27, 2011.
    77 changes: 77 additions & 0 deletions gistfile1.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,77 @@
    # == 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