phony 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|