phony 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +111 -0
- data/lib/ndc/austria.rb +69 -0
- data/lib/ndc/fixed_size.rb +113 -0
- data/lib/ndc/germany.rb +157 -0
- data/lib/ndc/prefix.rb +67 -0
- data/lib/ndc/splitter.rb +81 -0
- data/lib/phony.rb +496 -0
- data/spec/lib/ndc/austria_spec.rb +40 -0
- data/spec/lib/ndc/fixed_size_spec.rb +65 -0
- data/spec/lib/ndc/germany_spec.rb +40 -0
- data/spec/lib/ndc/prefix_spec.rb +25 -0
- data/spec/lib/ndc/splitter_spec.rb +59 -0
- data/spec/lib/phony_spec.rb +380 -0
- metadata +82 -0
data/README.textile
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
h1. Phony
|
2
|
+
|
3
|
+
h2. Description
|
4
|
+
|
5
|
+
This gem can normalize, format and split E164 numbers.
|
6
|
+
|
7
|
+
h2. Some examples
|
8
|
+
|
9
|
+
h3. Normalizing
|
10
|
+
|
11
|
+
@Phony.normalize('41443643533').should == '41443643533'@
|
12
|
+
|
13
|
+
@Phony.normalize('+41 44 364 35 33').should == '41443643533'@
|
14
|
+
|
15
|
+
@Phony.normalize('+41 44 364 35 33').should == '41443643533'@
|
16
|
+
|
17
|
+
@Phony.normalize('+41 800 11 22 33').should == '41800112233'@
|
18
|
+
|
19
|
+
@Phony.normalize('John: +41 44 364 35 33').should == '41443643533'@
|
20
|
+
|
21
|
+
@Phony.normalize('1 (703) 451-5115').should == '17034515115'@
|
22
|
+
|
23
|
+
@Phony.normalize('1-888-407-4747').should == '18884074747'@
|
24
|
+
|
25
|
+
@Phony.normalize('1.906.387.1698').should == '19063871698'@
|
26
|
+
|
27
|
+
@Phony.normalize('+41 (044) 364 35 33').should == '41443643533'@
|
28
|
+
|
29
|
+
h3. Formatting
|
30
|
+
|
31
|
+
@Phony.formatted('41443643532').should == '+41 44 364 35 32'@
|
32
|
+
|
33
|
+
@Phony.formatted('41800112233').should == '+41 800 11 22 33'@
|
34
|
+
|
35
|
+
@Phony.formatted('43198110').should == '+43 1 98110'@
|
36
|
+
|
37
|
+
@Phony.formatted('18705551122').should == '+1 870 555 1122'@
|
38
|
+
|
39
|
+
h4. International
|
40
|
+
|
41
|
+
@Phony.formatted('18091231234', :format => :international).should == '+1 809 123 1234'@
|
42
|
+
|
43
|
+
@Phony.formatted('43198110', :format => :international).should == '+43 1 98110'@
|
44
|
+
|
45
|
+
@Phony.formatted('43198110', :format => :international_absolute).should == '+43 1 98110'@
|
46
|
+
|
47
|
+
@Phony.formatted('33142278186', :format => :+).should == '+33 1 42 27 81 86'@
|
48
|
+
|
49
|
+
@Phony.formatted('43198110', :format => :international_relative).should == '0043 1 98110'@
|
50
|
+
|
51
|
+
@Phony.formatted('4233841148', :format => :international_relative).should == '00423 384 11 48'@
|
52
|
+
|
53
|
+
h4. With spaces
|
54
|
+
|
55
|
+
@Phony.formatted('18091231234', :format => :international, :spaces => '').should == '+18091231234'@
|
56
|
+
|
57
|
+
@Phony.formatted('43198110', :format => :international, :spaces => '').should == '+43198110'@
|
58
|
+
|
59
|
+
@Phony.formatted('43198110', :format => :international_absolute, :spaces => '').should == '+43198110'@
|
60
|
+
|
61
|
+
@Phony.formatted('33142278186', :format => :+, :spaces => '').should == '+33142278186'@
|
62
|
+
|
63
|
+
@Phony.formatted('43198110', :format => :international_relative, :spaces => '').should == '0043198110'@
|
64
|
+
|
65
|
+
@Phony.formatted('4233841148', :format => :international_relative, :spaces => '').should == '004233841148'@
|
66
|
+
|
67
|
+
h4. With special spaces
|
68
|
+
|
69
|
+
@Phony.formatted('18091231234', :format => :international, :spaces => :-).should == '+1-809-123-1234'@
|
70
|
+
|
71
|
+
@Phony.formatted('43198110', :format => :international, :spaces => :-).should == '+43-1-98110'@
|
72
|
+
|
73
|
+
@Phony.formatted('43198110', :format => :international_absolute, :spaces => :-).should == '+43-1-98110'@
|
74
|
+
|
75
|
+
@Phony.formatted('33142278186', :format => :+, :spaces => :-).should == '+33-1-42-27-81-86'@
|
76
|
+
|
77
|
+
@Phony.formatted('43198110', :format => :international_relative, :spaces => :-).should == '0043-1-98110'@
|
78
|
+
|
79
|
+
@Phony.formatted('4233841148', :format => :international_relative, :spaces => :-).should == '00423-384-11-48'@
|
80
|
+
|
81
|
+
h4. National
|
82
|
+
|
83
|
+
@Phony.formatted('41443643532', :format => :national).should == '044 364 35 32'@
|
84
|
+
|
85
|
+
@Phony.formatted('41800112233', :format => :national).should == '0800 11 22 33'@
|
86
|
+
|
87
|
+
@Phony.formatted('43198110', :format => :national).should == '01 98110'@
|
88
|
+
|
89
|
+
h4. Local
|
90
|
+
|
91
|
+
@Phony.formatted('41443643532', :format => :local).should == '364 35 32'@
|
92
|
+
|
93
|
+
@Phony.formatted('493038625454', :format => :local).should == '386 25454'@
|
94
|
+
|
95
|
+
h3. Splitting
|
96
|
+
|
97
|
+
@Phony.split('43198110').should == ['43', '1', '98110']@
|
98
|
+
|
99
|
+
@Phony.split('33112345678').should == ['33', '1', '12','34','56','78']@
|
100
|
+
|
101
|
+
@Phony.split('4976112345').should == ['49', '761', '123', '45']@
|
102
|
+
|
103
|
+
@Phony.split('3928061371').should == ['39', '280', '613', '71']@
|
104
|
+
|
105
|
+
@Phony.split('41443643532').should == ['41', '44', '364', '35', '32']@
|
106
|
+
|
107
|
+
@Phony.split('15551115511').should == ['1', '555', '111', '5511']@
|
108
|
+
|
109
|
+
@Phony.split('6491234567').should == ['64', '9', '123', '4567']@
|
110
|
+
|
111
|
+
@Phony.split('41800334455').should == ['41', '800', '33', '44', '55']@
|
data/lib/ndc/austria.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# Splits a national number into a fixed size NDC and rest.
|
2
|
+
#
|
3
|
+
module Phony
|
4
|
+
module NDC
|
5
|
+
class Austria < Prefix
|
6
|
+
|
7
|
+
length 1..4
|
8
|
+
local 10
|
9
|
+
|
10
|
+
ndcs '1',# Wient
|
11
|
+
'57', # -
|
12
|
+
'59', # -
|
13
|
+
'67', # Mobile Services
|
14
|
+
'68', # Mobile Services
|
15
|
+
'89', # Routing Number
|
16
|
+
'316', # Graz
|
17
|
+
'501', # -
|
18
|
+
'502', # -
|
19
|
+
'503', # -
|
20
|
+
'504', # -
|
21
|
+
'505', # -
|
22
|
+
'506', # -
|
23
|
+
'507', # -
|
24
|
+
'508', # -
|
25
|
+
'509', # -
|
26
|
+
'512', # Innsbruck
|
27
|
+
'517', # -
|
28
|
+
'644', # Mobile Services
|
29
|
+
'650', # Mobile Services
|
30
|
+
'651', # Mobile Services
|
31
|
+
'652', # Mobile Services
|
32
|
+
'653', # Mobile Services
|
33
|
+
'655', # Mobile Services
|
34
|
+
'657', # Mobile Services
|
35
|
+
'659', # Mobile Services
|
36
|
+
'660', # Mobile Services
|
37
|
+
'661', # Mobile Services
|
38
|
+
'662', # Salzburg
|
39
|
+
'663', # Mobile Services
|
40
|
+
'664', # Mobile Services
|
41
|
+
'665', # Mobile Services
|
42
|
+
'666', # Mobile Services
|
43
|
+
'667', # Mobile Services
|
44
|
+
'668', # Mobile Services
|
45
|
+
'669', # Mobile Services
|
46
|
+
'710', # Service Number
|
47
|
+
'711', # Service Number
|
48
|
+
'718', # Service Number
|
49
|
+
'720', #
|
50
|
+
'730', # Service Number
|
51
|
+
'732', # Linz
|
52
|
+
'740', # Service Number
|
53
|
+
'780', # Service Number
|
54
|
+
'800', # Service Number
|
55
|
+
'802', # Service Number
|
56
|
+
'804', # Service Number
|
57
|
+
'810', # Service Number
|
58
|
+
'820', # Service Number
|
59
|
+
'821', # Service Number
|
60
|
+
'828', # Service Number
|
61
|
+
'900', # Service Number
|
62
|
+
'901', # Service Number
|
63
|
+
'930', # Service Number
|
64
|
+
'931', # Service Number
|
65
|
+
'939' # Service Number
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# Splits a national number into a fixed size NDC and rest.
|
2
|
+
#
|
3
|
+
module Phony
|
4
|
+
module NDC
|
5
|
+
|
6
|
+
def self.fixed(national_code_length = 2, options = {})
|
7
|
+
klass = Class.new FixedSize
|
8
|
+
split_sizes, special_ndcs = klass.extract options
|
9
|
+
klass.special_ndc_strategy Phony::NDC::SpecialNdcStrategy.new(national_code_length, special_ndcs)
|
10
|
+
klass.fixed_ndc_strategy Phony::NDC::FixedNdcStrategy.new(national_code_length, split_sizes)
|
11
|
+
klass.format options[:format] || '%s%s%s%s%s'
|
12
|
+
klass.local split_sizes
|
13
|
+
klass
|
14
|
+
end
|
15
|
+
|
16
|
+
class FixedSize < Splitter
|
17
|
+
|
18
|
+
def self.extract options
|
19
|
+
[options[:local] || [3, 2, 2], options[:special_ndcs] || []]
|
20
|
+
end
|
21
|
+
|
22
|
+
# Sets the strategy object to handle special services numbers
|
23
|
+
def self.special_ndc_strategy strategy
|
24
|
+
@special_ndc_strategy = strategy
|
25
|
+
end
|
26
|
+
|
27
|
+
# Sets the strategy object to handle normal numbers (non special services)
|
28
|
+
def self.fixed_ndc_strategy strategy
|
29
|
+
@fixed_ndc_strategy = strategy
|
30
|
+
@ndc_strategy = @fixed_ndc_strategy
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns true if the number is a special services number
|
34
|
+
def self.special_ndc? number
|
35
|
+
@special_ndc_strategy.special_ndc? number
|
36
|
+
end
|
37
|
+
|
38
|
+
# Define a format for the country's national format.
|
39
|
+
#
|
40
|
+
# Default is NN followed by a space.
|
41
|
+
#
|
42
|
+
def self.ndc_format
|
43
|
+
@ndc_format || @ndc_format = @ndc_strategy.ndc_format
|
44
|
+
end
|
45
|
+
|
46
|
+
# A faster split method than the prefix splitter offers.
|
47
|
+
#
|
48
|
+
def self.split_ndc number
|
49
|
+
number = number.dup
|
50
|
+
if special_ndc? number
|
51
|
+
@ndc_strategy = @special_ndc_strategy
|
52
|
+
else
|
53
|
+
@ndc_strategy = @fixed_ndc_strategy
|
54
|
+
end
|
55
|
+
@ndc_strategy.split_ndc number
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.split_local number
|
59
|
+
@ndc_strategy.split_local number
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
# Base class for all Strategies
|
65
|
+
class NdcStrategy
|
66
|
+
attr_reader :split_sizes
|
67
|
+
|
68
|
+
def initialize national_code_length, split_sizes
|
69
|
+
@national_code_length = national_code_length
|
70
|
+
@split_sizes = split_sizes
|
71
|
+
end
|
72
|
+
|
73
|
+
def split_local number
|
74
|
+
local = []
|
75
|
+
split_sizes.each do |size|
|
76
|
+
local << number.slice!(0..size-1)
|
77
|
+
break if number.empty?
|
78
|
+
end
|
79
|
+
local
|
80
|
+
end
|
81
|
+
|
82
|
+
def ndc_format
|
83
|
+
'%s' + (@national_code_length == 0 ? '' : '%s')
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
class SpecialNdcStrategy < NdcStrategy
|
89
|
+
def initialize national_code_length, special_ndcs
|
90
|
+
super national_code_length, [2, 2, 2]
|
91
|
+
@special_ndcs = special_ndcs.flatten
|
92
|
+
@special_ndc_regexp = Regexp.compile "^(#{@special_ndcs.join('|')})"
|
93
|
+
end
|
94
|
+
|
95
|
+
def special_ndc? number
|
96
|
+
@special_ndcs && !@special_ndcs.empty? && @match = @special_ndc_regexp.match(number)
|
97
|
+
end
|
98
|
+
|
99
|
+
def split_ndc number
|
100
|
+
[number.slice!(0..@match[0].length-1), number]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class FixedNdcStrategy < NdcStrategy
|
105
|
+
|
106
|
+
def split_ndc number
|
107
|
+
@national_code_length.zero? ? ['', number] : [number.slice!(0..@national_code_length-1), number]
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
data/lib/ndc/germany.rb
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
# Splits a german national number into a fixed size NDC and rest.
|
2
|
+
#
|
3
|
+
# Note: We do ignore places with 5 numbers as NDC, like Groß Glienicke (33201)
|
4
|
+
#
|
5
|
+
module Phony
|
6
|
+
module NDC
|
7
|
+
class Germany < Prefix
|
8
|
+
|
9
|
+
length 2..4
|
10
|
+
local 3, 10
|
11
|
+
|
12
|
+
# prefix length => [ndcs]
|
13
|
+
ndcs '10', # Call-By-Call
|
14
|
+
'11', # formerly Value Added Services
|
15
|
+
'12', # Innovative Services
|
16
|
+
'13', # Voting and Lottery Numbers
|
17
|
+
'30', # Berlin
|
18
|
+
'32', # Non Geographical Numbers
|
19
|
+
'40', # Hamburg
|
20
|
+
'69', # Frankfurt am Main
|
21
|
+
'89', # München
|
22
|
+
'150', # Group3G/Quam
|
23
|
+
'151', # T-Mobile
|
24
|
+
'152', # Vodafone
|
25
|
+
'155', # E-Plus
|
26
|
+
'156', # Mobilcom
|
27
|
+
'157', # E-Plus
|
28
|
+
'159', # O2
|
29
|
+
'160', # T-Mobile
|
30
|
+
'161', # C-Netz
|
31
|
+
'162', # Vodafone
|
32
|
+
'163', # E-Plus
|
33
|
+
'164', # Cityruf
|
34
|
+
'165', # Quix
|
35
|
+
'166', # Telmi
|
36
|
+
'168', # Scall
|
37
|
+
'169', # Cityruf, Scall, Skyper (e*cityruf, e*message, e*skyper)
|
38
|
+
'170', # T-Mobile
|
39
|
+
'171', # T-Mobile
|
40
|
+
'172', # Vodafone
|
41
|
+
'173', # Vodafone
|
42
|
+
'174', # Vodafone
|
43
|
+
'175', # T-Mobile
|
44
|
+
'176', # O2 Germany
|
45
|
+
'177', # E-Plus
|
46
|
+
'178', # E-Plus
|
47
|
+
'179', # O2 Germany
|
48
|
+
'181', # IVPNs
|
49
|
+
'182', # Closed User Group
|
50
|
+
'183', # Closed User Group
|
51
|
+
'184', # Closed User Group
|
52
|
+
'185', # Closed User Group
|
53
|
+
'186', # Closed User Group
|
54
|
+
'187', # Closed User Group
|
55
|
+
'189', # Closed User Group
|
56
|
+
'190', # former Premium Rate Services
|
57
|
+
'191', # Online Services
|
58
|
+
'192', # Online Services
|
59
|
+
'193', # Online Services
|
60
|
+
'194', # Online Services
|
61
|
+
'199', # Network-Internal Traffic Control
|
62
|
+
'201', # Essen
|
63
|
+
'202', # Wuppertal
|
64
|
+
'203', # Duisburg
|
65
|
+
'208', # Mühlheim an der Ruhr
|
66
|
+
'209', # Gelsenkirchen
|
67
|
+
'211', # Düsseldorf
|
68
|
+
'212', # Solingen
|
69
|
+
'214', # Leverkusen
|
70
|
+
'221', # Köln
|
71
|
+
'228', # Bonn
|
72
|
+
'231', # Dortmund
|
73
|
+
'234', # Bochum
|
74
|
+
'241', # Aachen
|
75
|
+
'251', # Münster
|
76
|
+
'261', # Koblenz
|
77
|
+
'271', # Siegen
|
78
|
+
'281', # Wesel
|
79
|
+
'291', # Meschede
|
80
|
+
'310', # Test Number Long Distance
|
81
|
+
'311', # Test Number Local
|
82
|
+
'335', # Frankfurt (Oder)
|
83
|
+
'340', # Dessau
|
84
|
+
'341', # Leipzig
|
85
|
+
'345', # Halle (Saale)
|
86
|
+
'351', # Dresden
|
87
|
+
'355', # Cottbus
|
88
|
+
'361', # Erfurt
|
89
|
+
'365', # Gera
|
90
|
+
'371', # Chemnitz
|
91
|
+
'375', # Zwickau
|
92
|
+
'381', # Rostock
|
93
|
+
'385', # Schwerin
|
94
|
+
'391', # Magdeburg
|
95
|
+
'395', # Neubrandenburg
|
96
|
+
'421', # Bremen
|
97
|
+
'431', # Kiel
|
98
|
+
'441', # Oldenburg
|
99
|
+
'461', # Flensburg
|
100
|
+
'471', # Bremerhaven
|
101
|
+
'481', # Heide
|
102
|
+
'491', # Leer
|
103
|
+
'511', # Hannover
|
104
|
+
'521', # Bielefeld
|
105
|
+
'531', # Braunschweig
|
106
|
+
'541', # Osnabrück
|
107
|
+
'551', # Göttingen
|
108
|
+
'561', # Kassel
|
109
|
+
'571', # Minden
|
110
|
+
'581', # Uelzen
|
111
|
+
'591', # Lingen (Ems)
|
112
|
+
'611', # Wiesbaden
|
113
|
+
'621', # Mannheim / Ludwigshafen
|
114
|
+
'631', # Kaiserslautern
|
115
|
+
'641', # Gießen
|
116
|
+
'651', # Trier
|
117
|
+
'661', # Fulda
|
118
|
+
'671', # Bad Kreuznach
|
119
|
+
'681', # Saarbrücken
|
120
|
+
'700', # Personal Numbers
|
121
|
+
'701', # Personal Numbers, reserved
|
122
|
+
'711', # Stuttgart
|
123
|
+
'721', # Karlsruhe
|
124
|
+
'731', # Ulm
|
125
|
+
'741', # Rottweil
|
126
|
+
'751', # Ravensburg
|
127
|
+
'761', # Freiburg im Breisgau
|
128
|
+
'771', # Donaueschingen
|
129
|
+
'781', # Offenburg
|
130
|
+
'791', # Schwäbisch Hall
|
131
|
+
'800', # Toll-Free Numbers
|
132
|
+
'801', # Toll-Free Numbers, reserved
|
133
|
+
'811', # Hallbergmoos
|
134
|
+
'821', # Augsburg
|
135
|
+
'831', # Kempten
|
136
|
+
'841', # Ingolstadt
|
137
|
+
'851', # Passau
|
138
|
+
'861', # Traunstein
|
139
|
+
'871', # Landshut
|
140
|
+
'881', # Weilheim in Oberbayern
|
141
|
+
'900', # Premium Rate Numbers
|
142
|
+
'901', # Premium Rate Numbers, reserved
|
143
|
+
'902', # Replacement for 0137/0138
|
144
|
+
'906', # Donauwörth
|
145
|
+
'911', # Nürnberg
|
146
|
+
'921', # Bayreuth
|
147
|
+
'931', # Würzburg
|
148
|
+
'941', # Regensburg
|
149
|
+
'951', # Bamberg
|
150
|
+
'961', # Weiden
|
151
|
+
'971', # Bad Kissingen
|
152
|
+
'981', # Ansbach
|
153
|
+
'991' # Deggendorf
|
154
|
+
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|