Skip to content

Commit

Permalink
+ experimental 1.6.6 release of plausibility checking
Browse files Browse the repository at this point in the history
  • Loading branch information
floere committed Mar 18, 2012
1 parent c957a70 commit 3bbddb8
Show file tree
Hide file tree
Showing 10 changed files with 177 additions and 69 deletions.
4 changes: 4 additions & 0 deletions history.textile
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
h2. Upcoming Version.

h2. Version 1.6.6

* hanke: Experimental @plausible?@ feature. Checks if the given number is a plausible number. Returns @false@ if 100% not plausible, @true@ if probably true.

h2. Version 1.6.5

* hanke: Ghana (thanks jschwertfeger!).
Expand Down
15 changes: 14 additions & 1 deletion lib/phony.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
require File.expand_path '../phony/national_code', __FILE__
require File.expand_path '../phony/country', __FILE__
require File.expand_path '../phony/country_codes', __FILE__
require File.expand_path '../phony/validator', __FILE__
require File.expand_path '../phony/validators', __FILE__
require File.expand_path '../phony/dsl', __FILE__

# Countries.
Expand All @@ -37,7 +39,8 @@ module Phony

# Phony uses a single country codes instance.
#
@codes = CountryCodes.instance
@codes = CountryCodes.instance
@validator = Validators.instance

class << self

Expand Down Expand Up @@ -74,6 +77,16 @@ def format! phone_number, options = {}
end
alias formatted format
alias formatted! format!

# Makes a plausibility check.
#
# If it returns false, it is not plausible.
# If it returns true, it is unclear whether it is plausible,
# leaning towards being plausible.
#
def plausible? number, hints = {}
@validator.plausible? number, hints
end

# def service? number
# @codes.service? number.dup
Expand Down
4 changes: 3 additions & 1 deletion lib/phony/countries.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@

# USA, Canada, etc.
#
country '1', fixed(3) >> split(3,4)
country '1',
fixed(3) >> split(3,4),
invalid_ndcs(/911/)

# Kazakhstan (Republic of) & Russian Federation.
#
Expand Down
19 changes: 11 additions & 8 deletions lib/phony/country_codes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module Phony
#
class CountryCodes

attr_reader :mapping
attr_reader :splitter_mapping
attr_accessor :international_absolute_format, :international_relative_format, :national_format

def initialize
Expand All @@ -22,11 +22,14 @@ def self.instance
@instance ||= new
end

@@normalizing_pattern = /^0+|\D/
def normalize number
@@basic_normalizing_pattern = /^0+|\D/
def clean number
# Remove non-digit chars.
#
number.gsub! @@normalizing_pattern, EMPTY_STRING
number.gsub! @@basic_normalizing_pattern, EMPTY_STRING
end
def normalize number
clean number
national_handler, cc, rest = split_cc number
@normalize_format % [cc, national_handler.normalize(rest)]
end
Expand Down Expand Up @@ -102,7 +105,7 @@ def split_cc rest
presumed_cc = ''
1.upto(3) do |i|
presumed_cc << rest.slice!(0..0)
national_code_handler = mapping[i][presumed_cc]
national_code_handler = splitter_mapping[i][presumed_cc]
return [national_code_handler, presumed_cc, rest] if national_code_handler
end
# This line is never reached as CCs are in prefix code.
Expand All @@ -121,9 +124,9 @@ def add country_code, country
country_code = country_code.to_s
optimized_country_code_access = country_code.size

@mapping ||= {}
@mapping[optimized_country_code_access] ||= {}
@mapping[optimized_country_code_access][country_code] = country
@splitter_mapping ||= {}
@splitter_mapping[optimized_country_code_access] ||= {}
@splitter_mapping[optimized_country_code_access][country_code] = country
end

end
Expand Down
9 changes: 8 additions & 1 deletion lib/phony/dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ class DSL

#
#
def country country_code, country
def country country_code, country, validator = nil
Phony::CountryCodes.instance.add country_code, country
Phony::Validators.instance.add country_code, validator if validator
end

# National matcher & splitters.
Expand Down Expand Up @@ -89,6 +90,12 @@ def split *local
def matched_split options = {}
Phony::LocalSplitters::Regex.instance_for options
end

# Validators
#
def invalid_ndcs ndc
Validator.new.ndc_check ndc
end

end

Expand Down
70 changes: 16 additions & 54 deletions lib/phony/validator.rb
Original file line number Diff line number Diff line change
@@ -1,62 +1,24 @@
# # Number: A possible phone number, E164 or not.
# # Hints: Information that helps or constricts the plausibility check.
# #
# plausible? number, hints = {}
#

# plausible? number # Uses the definitions from the country definition to plausibility check.
# plausible? number, cc: 1 # => Checks cc.
# plausible? number, pattern: /[^5]/ # Uses def, checks against split.
# plausible? number, country: 1, pattern: [3, 4, 3] # Uses given country – adds cc.
#

# Basic plausibility is:
# * Max digits are 15.
# * Min digits are 2 (?)
#

module Phony

class Validator

# TODO Beautify.
#
def plausible? number, hints = {}
normalized = normalize number

# False if it fails the basic check.
#
return false unless normalized.size === (2..15)

# Hint based checking.
#
cc, ndc, *rest = split normalized

# CC.
#
cc_needed = hints[:cc]
return false if cc_needed && cc_needed != cc

# NDC.
#
ndc_needed = hints[:ndc]
return false if ndc_needed && ndc_needed != ndc

# Country specific checks?
#

# Get the country.
#

# Check.
#

attr_reader :ndc_checks

def initialize
@ndc_checks = []
end

def plausible? ndc, rest
ndc_checks && ndc_checks.each do |ndc_check|
return false if ndc_check === ndc
end

rescue StandardError
return false
true
end

def normalize number
number

def ndc_check ndc
@ndc_checks << ndc
self
end

end
Expand Down
77 changes: 77 additions & 0 deletions lib/phony/validators.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# # Number: A possible phone number, E164 or not.
# # Hints: Information that helps or constricts the plausibility check.
# #
# plausible? number, hints = {}
#

# plausible? number # Uses the definitions from the country definition to plausibility check.
# plausible? number, cc: 1 # => Checks cc.
# plausible? number, pattern: /[^5]/ # Uses def, checks against split.
# plausible? number, country: 1, pattern: [3, 4, 3] # Uses given country – adds cc.
#

# Basic plausibility is:
# * Max digits are 15.
# * Min digits are 2 (?)
#

module Phony

class Validators

def initialize
@validators = {}
end

def self.instance
@instance ||= new
end

# Add a specific country validator.
#
def add cc, validator
@validators[cc] = validator
end

# Is the given number plausible?
#
def plausible? number, hints = {}
normalized = CountryCodes.instance.clean number

# False if it fails the basic check.
#
return false unless (2..15) === normalized.size

# Hint based checking.
#
cc, ndc, *rest = Phony.split normalized

# CC.
#
cc_needed = hints[:cc]
return false if cc_needed && cc_needed != cc

# NDC.
#
ndc_needed = hints[:ndc]
return false if ndc_needed && ndc_needed != ndc

# Country specific checks.
#
validator = validator_for cc
validator.plausible? ndc, rest
rescue StandardError
return false
end

def validator_for cc
@validators[cc] || default_validator
end

def default_validator
@default_validator ||= Validator.new
end

end

end
2 changes: 1 addition & 1 deletion phony.gemspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Gem::Specification.new do |s|
s.name = 'phony'
s.version = '1.6.5'
s.version = '1.6.6'
s.authors = ['Florian Hanke']
s.email = '[email protected]'
s.homepage = 'http://github.com/floere/phony'
Expand Down
43 changes: 43 additions & 0 deletions spec/lib/phony/validations_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# encoding: utf-8
#
require 'spec_helper'

describe 'validations' do

describe 'plausible?' do

it "is correct" do
Phony.plausible?('0000000').should be_false
end
it "is correct" do
Phony.plausible?('hello').should be_false
end

it "is correct" do
Phony.plausible?('+41 44 111 22 33').should be_true
end
it "is correct for explicit checks" do
Phony.plausible?('+41 44 111 22 33', cc: '41').should be_true
end
it "is correct for explicit checks" do
Phony.plausible?('+41 44 111 22 33', ndc: '44').should be_true
end
it "is correct for explicit checks" do
Phony.plausible?('+41 44 111 22 33', cc: '1').should be_false
end
it "is correct for explicit checks" do
Phony.plausible?('+41 44 111 22 33', ndc: '43').should be_false
end

context 'countries' do

it "is correct for US numbers" do
Phony.plausible?('1-800-692-7753').should be_true
Phony.plausible?('1-911').should be_false
end

end

end

end
3 changes: 0 additions & 3 deletions spec/lib/phony_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,6 @@
it "should not normalize a number with a correct zero inside" do
Phony.normalize('+390909709511').should == '390909709511'
end
it "works with completely broken numbers" do
Phony.normalize('0000000').should == ''
end
end
end

Expand Down

0 comments on commit 3bbddb8

Please sign in to comment.