phony 2.20.15 → 3.0.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 969429cee208cbf144b3425d07a627958e7ee94cb254ab7a4740e926bb343c56
4
- data.tar.gz: b191047a4dea560cc1e5ed703ae42e77e608cae4b91b56975cdad10468237fd4
3
+ metadata.gz: 914522596278234ccd64fd27a07f0b32426738aa3b886233c14e5ca9469a99f9
4
+ data.tar.gz: 9fcbb9e8607a93d2271ff19f61215139a04f922b3f5bbfa1d309ae15b30222bb
5
5
  SHA512:
6
- metadata.gz: 1f586b94f21b174234c7cdef026193f49e239ffb3b3d24ea05f45eaaa5144ed7b4fbe06c200be18d8e99bb460dd36583eb910379a4844a4e1c45ac8b5245a6d0
7
- data.tar.gz: 6261e3738f15db6cb5465a36e1c4744098a0de29403c29216df4285df5a9f4eb2fd42319876ff1ef1a135778a5f095966db6a264d2176238bb4fc7c38b283d03
6
+ metadata.gz: 17cda2331907984caf6a7a876bc7021efd08d2026082081412a93c8a93dad3211c44db1c785f7971fb645b1ee0dbfb0ac10a9849618eab8e045e667f50d7a1b2
7
+ data.tar.gz: d6702bd8f91fdb5aaa8a01715a12726df2a4937b9f59161ceb4951049309674aa3e9306c398fc3901b55a3a83f74a634a2aa52ea8670509645dfa5d7e05c6710
data/README.md ADDED
@@ -0,0 +1,117 @@
1
+ [![Build Status](https://secure.travis-ci.org/floere/phony.png)](http://travis-ci.org/floere/phony)
2
+ [![Coverage Status](https://coveralls.io/repos/floere/phony/badge.svg?branch=master)](https://coveralls.io/r/floere/phony?branch=master)
3
+ [![Code Climate](https://codeclimate.com/github/floere/phony.png)](https://codeclimate.com/github/floere/phony)
4
+ [![Inline docs](http://inch-ci.org/github/floere/phony.png)](http://inch-ci.org/github/floere/phony)
5
+
6
+ # Phony
7
+
8
+ Disclaimer: Phony works with international numbers only, such as `61 412 345 678`!
9
+
10
+ The (admittedly crazy) goal of this Gem is to be able to normalize/format/split all phone numbers in the world.
11
+
12
+ Used in: [airbnb.com](http://airbnb.com), [socialcam.com](http://socialcam.com), [zendesk.com](http://www.zendesk.com/) (and many, many others).
13
+
14
+ ## Runtime Memory Usage {#memory}
15
+
16
+ According to [memory_profiler](https://github.com/SamSaffron/memory_profiler), the Phony gem uses roughly 1MB of memory per Ruby process.
17
+ Usage was generated using (look for `Total retained`): `ruby -e 'require "memory_profiler"; MemoryProfiler.report(allow_files: "phony"){ require "phony" }.pretty_print'`
18
+
19
+ ## Description
20
+
21
+ This gem normalizes, formats and splits "**E164 phone numbers**". A valid E164 phone number **must** include a country code.
22
+
23
+ E164 numbers are international numbers with a country dial prefix, usually an area code and a subscriber number. For example, the Australian number `+61 412 345 678` can be broken down into the following components:
24
+ * Country Code (CC): a country code of `61`
25
+ * National Destination Code (NDC): a mobile number denoted by the `4` (specific to Australia)
26
+ * Local Number Part: a subscriber number of `12 345 678`
27
+
28
+ It currently handles the countries listed at the end of this README.
29
+
30
+ It is covered by roughly 2,250 tests that run in 2 seconds (April 2019).
31
+ If it doesn't work, please [enter an issue](http://github.com/floere/phony/issues) or better, fork and [send a pull request](http://github.com/floere/phony/pulls).
32
+
33
+ ## Installation
34
+
35
+ With Rails? Check out: https://github.com/joost/phony_rails.
36
+
37
+ With Bundler: Append `gem 'phony'` to your `Gemfile` and `bundle install` it.
38
+
39
+ Without Bundler: Run `gem install phony` from your command line.
40
+
41
+ ## Usage docs {#usage}
42
+
43
+ Phony uses [qed](https://github.com/rubyworks/qed) as docs and to run its functional tests. Start here for usage docs: [Usage index](./qed/index.md).
44
+
45
+ ### Phony.normalize(number) {#normalizing}
46
+
47
+ Normalize intelligently removes all non-numeric characters of a number. Do it before storing a number in a DB.
48
+
49
+ [Phony.normalize docs](./qed/normalize.md)
50
+
51
+ `Phony.normalize('1-888-407-4747').assert == '18884074747'`
52
+
53
+ ### Phony.format(number, options = {}) {#formatting}
54
+
55
+ Format formats a normalized number according to a country's predominant formatting. Lots of options for int'l, national, local formatting.
56
+
57
+ [Phony.format docs](./qed/format.md)
58
+
59
+ `Phony.format('41443643532').assert == '+41 44 364 35 32'`
60
+
61
+ ### Phony.plausible?(number, options = {}) {#plausibility}
62
+
63
+ Is a number plausible?
64
+
65
+ [Phony.plausible? docs](./qed/plausibility.md)
66
+
67
+ `Phony.assert.plausible?('+41 44 111 22 33')`
68
+
69
+ ### Phony.split(number) {#splitting}
70
+
71
+ Split a number into its parts: CC, NDC, local.
72
+
73
+ [Phony.split docs](./qed/split.md)
74
+
75
+ `Phony.split('3928061371').assert == ['39', '2', '806', '1371']`
76
+
77
+ NB If a country does not have an NDC, `#split` will return `false` in the NDC position, for example for Denmark:
78
+
79
+ `Phony.split('4512121212').assert == ['45', false, '12', '12', '12', '12']`
80
+
81
+ ### Loading only a country subset (Phony 2.18.0+). {#loading}
82
+
83
+ Use this in case you'd like to save [memory](#memory) that is used by Phony's CC rules.
84
+
85
+ [Phony::Config.load docs](./qed/config.md)
86
+
87
+ First, `require 'phony/config'`.
88
+ Then, one of the following, which will load the rest of Phony.
89
+
90
+ Load only these CCs:
91
+ `Phony::Config.load(only: ['41', '44'])`
92
+
93
+ Loads everything except these CCs:
94
+ `Phony::Config.load(except: ['41', '44'])`
95
+
96
+ Convenience form of `only`:
97
+ `Phony::Config.load('41', '44')`
98
+
99
+ Each of these loads the rest of Phony.
100
+
101
+ Memory usage can be checked using (look for `Total retained`):
102
+ `ruby -e 'require "memory_profiler"; MemoryProfiler.report(allow_files: "phony"){ require "phony/config"; Phony::Config.load("1") }.pretty_print'`
103
+ For example, when just loading the NANP CC, the retained memory usage is ~63kB.
104
+
105
+ ## List of Handled Countries
106
+
107
+ Mildly unmaintained list: Abhas, Afghan, Algerian, Argentina, Austrian, Australian, Azerbaijani, Belgian, Brazilian, Cambodian, Chilean, Chinese, Croatian, Cuban, Cypriot, Czech, Danish, Dutch, Egyptian, El Salvadorian, Estonian, French, German, Ghanan, Gibraltar, Greek, Haiti, Hong Kong, Hungarian, Indian, Iran, Irish, Israel, Italian, Japanese, Kazakh, Liberian, Lithuanian, Luxembourgian, Malaysian, Malta, Mauritian, Mexican, Monaco, Morocco, New Zealand, Nigerian, Norwegian, Peruvian, Polish, Romanian, Russian, Rwandan, Seychelles, Singapore, Slovakian, South African, South Korean, South Osetian, Spanish, Sri Lankan, Sudan, Swedish, Swiss, Thailand, Tunisian, Turkish, Liechtenstein, UK, US, Venezuelan, Vietnamese, and Zambian numbers.
108
+
109
+ ## Proud Sponsors
110
+
111
+ * Renuo AG (July 2022 – January 2025): [Github](https://github.com/renuo), [Homepage](https://www.renuo.ch). Much appreciated!
112
+
113
+ ## License
114
+
115
+ MIT.
116
+ See [LICENSE](./LICENSE) file.
117
+
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Lybia, https://www.numberingplans.com/?page=dialling&sub=areacodes
3
+ # Libya, https://www.numberingplans.com/?page=dialling&sub=areacodes
4
4
  # https://www.numberingplans.com/?page=plans&sub=phonenr&alpha_2_input=LY
5
5
 
6
6
  ndcs_with_7_subscriber_numbers = %w[21]
@@ -106,11 +106,13 @@ ndcs_with_5_subscriber_numbers = %w[
106
106
  884
107
107
  ]
108
108
 
109
+ mobile_with_7_subscriber_numbers = %w[91 92 93 94 95]
110
+
109
111
  Phony.define do
110
112
  country '218',
111
113
  one_of(ndcs_with_5_subscriber_numbers) >> split(3, 2) |
112
114
  one_of(ndcs_with_6_subscriber_numbers) >> split(3, 3) |
113
115
  one_of(ndcs_with_7_subscriber_numbers) >> split(4, 3) |
114
- one_of(%w[91 92 94 95]) >> split(4, 3) | # mobile
116
+ one_of(mobile_with_7_subscriber_numbers) >> split(4, 3) |
115
117
  fixed(2) >> split(3, 3)
116
118
  end
@@ -2,27 +2,23 @@
2
2
 
3
3
  # Sweden uses a variable-length ndc code, thus we use a separate file to not let all_other.rb explode.
4
4
  #
5
- # Note: Sweden use a variable ndc format from length 2 to 3.
6
- # To save space, we only use ndcs of length 1 and 2 (and use the fallback of 3 to handle the rest).
7
- #
8
- # Taken from: http://en.wikipedia.org/wiki/Telephone_numbers_in_Sweden
9
- # http://www.pts.se/upload/Ovrigt/Tele/Nummerfragor/bilaga-2b.pdf
5
+ # Note: Sweden use a variable ndc format with length 1 to 3.
10
6
  #
7
+ # Taken from: https://pts.se/globalassets/globala-block/nummertillstand/the-swedish-numbering-plan-for-telephony-according-to-itu---2024-01-08.pdf
8
+ # https://nummer.pts.se/NbrPlanSearch
9
+ # https://www.sosalarm.se/en/112-and-other-important-numbers/important-phone-numbers/
10
+
11
+ regional_ndcs_1 = [
12
+ '8' # Stockholm
13
+ ]
11
14
 
12
- ndcs = [
13
- # '7', # Non-geographic - conflicts with mobile
14
- '8', # Stockholm
15
- '10', # VOIP
15
+ regional_ndcs_2 = [
16
16
  '11', # Norrköping
17
17
  '13', # Linköping
18
18
  '16', # Eskilstuna-Torshälla
19
- '18', # Uppsala
20
- '19', # Örebro-Kumla
21
- '20', # toll-free
22
19
  '21', # Västerås
23
20
  '23', # Falun
24
21
  '26', # Gävle-Sandviken
25
- '31', # Göteborg
26
22
  '33', # Borås
27
23
  '35', # Halmstad
28
24
  '36', # Jönköping-Huskvarna
@@ -30,33 +26,314 @@ ndcs = [
30
26
  '42', # Helsingborg-Höganäs
31
27
  '44', # Kristianstad
32
28
  '46', # Lund
33
- '54', # Karlstad
34
29
  '60', # Sundsvall-Timrå
35
30
  '63', # Östersund
36
- '90', # Umeå
37
- '77' # Dalarna
31
+ '90' # Umeå; NB: Conflicts with 900 (Premium cost services)
38
32
  ]
39
- mobile = [
40
- '70', # Mobile
41
- '71', # Telematics
42
- '72', # Mobile
43
- '73', # Mobile
44
- '74', # Pagers
45
- '76', # Mobile
46
- '79' # Mobile
33
+
34
+ large_regional_ndcs_2 = [
35
+ '18', # Uppsala
36
+ '19', # Örebro-Kumla
37
+ '31', # Göteborg
38
+ '54' # Karlstad
47
39
  ]
48
- services = [
49
- '112', # Emergency Service
50
- '1177', # Health Care Advice
51
- '11414' # Police
40
+
41
+ regional_ndcs_3 = [
42
+ '120', # Åtvidaberg
43
+ '121', # Söderköping
44
+ '122', # Finspång
45
+ '123', # Valdemarsvik
46
+ '125', # Vikbolandet
47
+ '140', # Tranås
48
+ '141', # Motala
49
+ '142', # Mjöby-Skänninge-Boxholm
50
+ '143', # Vadstena
51
+ '144', # Ödeshög
52
+ '150', # Katrineholm
53
+ '151', # Vingåker
54
+ '152', # Strängnäs
55
+ '155', # Nyköping-Oxelösund
56
+ '156', # Trosa-Vagnhärad
57
+ '157', # Flen Malmköping
58
+ '158', # Gnesta
59
+ '159', # Mariefred
60
+ '171', # Enköping
61
+ '173', # Öregrund-Östhammar
62
+ '174', # Alunda
63
+ '175', # Hallstavik-Rimbo
64
+ '176', # Norrtälje
65
+ '220', # Hallstahammar-Surahammar
66
+ '221', # Köping
67
+ '222', # Skinnskatteberg
68
+ '223', # Fagersta-Norberg
69
+ '224', # Sala-Heby
70
+ '225', # Hedemora-Säter
71
+ '226', # Avesta-Krylbo
72
+ '227', # Kungsör
73
+ '240', # Ludvika-Smedjebacken
74
+ '241', # Gagnef-Floda
75
+ '243', # Borlänge
76
+ '246', # Svärdsjö-Enviken
77
+ '247', # Leksand-Insjön
78
+ '248', # Rättvik
79
+ '250', # Mora-Orsa
80
+ '251', # Älvdalen
81
+ '253', # Idre-Särna
82
+ '258', # Furudal
83
+ '270', # Söderhamn
84
+ '271', # Alfta-Edsbyn
85
+ '278', # Bollnäs
86
+ '280', # Malung
87
+ '281', # Vansbro
88
+ '290', # Hofors-Storvik
89
+ '291', # Hedesunda-Österfärnebo
90
+ '292', # Tärnsjö-Östervåla
91
+ '293', # Tierp-Söderfors
92
+ '294', # Karlholmsbruk-Skärplinge
93
+ '295', # Örbyhus-Dannemora
94
+ '297', # Ockelbo-Hamrånge
95
+ '300', # Kungsbacka
96
+ '301', # Hindås
97
+ '302', # Lerum
98
+ '303', # Kungälv
99
+ '304', # Orust-Tjörn
100
+ '320', # Kinna
101
+ '321', # Ulricehamn
102
+ '322', # Alingsås-Vårgårda
103
+ '325', # Svenljunga-Tranemo
104
+ '340', # Varberg
105
+ '345', # Hyltebruk-Torup
106
+ '346', # Falkenberg
107
+ '370', # Värnamo
108
+ '371', # Gislaved-Anderstorp
109
+ '372', # Ljungby
110
+ '380', # Nässjö
111
+ '381', # Eksjö
112
+ '382', # Sävsjö
113
+ '383', # Vetlanda
114
+ '390', # Gränna
115
+ '392', # Mullsjö
116
+ '393', # Vaggeryd
117
+ '410', # Trelleborg
118
+ '411', # Ystad
119
+ '413', # Eslöv-Höör
120
+ '414', # Simrishamn
121
+ '415', # Hörby
122
+ '416', # Sjöbo
123
+ '417', # Tomelilla
124
+ '418', # Landskrona-Svalöv
125
+ '430', # Laholm
126
+ '431', # Ängelholm-Båstad
127
+ '433', # Markaryd-Strömsnäsbruk
128
+ '435', # Klippan-Perstorp
129
+ '451', # Hässleholm
130
+ '454', # Karlshamn-Olofström
131
+ '455', # Karlskrona
132
+ '456', # Sölvesborg-Bromölla
133
+ '457', # Ronneby
134
+ '459', # Ryd
135
+ '470', # Växjö
136
+ '471', # Emmaboda
137
+ '472', # Alvesta-Rydaholm
138
+ '474', # Åseda-Lenhovda
139
+ '476', # Älmhult
140
+ '477', # Tingsryd
141
+ '478', # Lessebo
142
+ '479', # Osby
143
+ '480', # Kalmar
144
+ '481', # Nybro
145
+ '485', # Öland
146
+ '486', # Torsås
147
+ '490', # Västervik
148
+ '491', # Oskarshamn-Högsby
149
+ '492', # Vimmerby
150
+ '493', # Gamleby
151
+ '494', # Kisa
152
+ '495', # Hultsfred-Virserum
153
+ '496', # Mariannelund
154
+ '498', # Gotland
155
+ '499', # Mönsterås
156
+ '500', # Skövde
157
+ '501', # Mariestad
158
+ '502', # Tidaholm
159
+ '503', # Hjo
160
+ '504', # Tibro
161
+ '505', # Karlsborg
162
+ '506', # Töreboda-Hova
163
+ '510', # Lidköping
164
+ '511', # Skara-Götene
165
+ '512', # Vara-Nossebro
166
+ '513', # Herrljunga
167
+ '514', # Grästorp
168
+ '515', # Falköping
169
+ '520', # Trollhättan
170
+ '521', # Vänerborg
171
+ '522', # Uddevalla
172
+ '523', # Lysekil
173
+ '524', # Munkedal
174
+ '525', # Grebbestad
175
+ '526', # Strömstad
176
+ '528', # Färgelanda
177
+ '530', # Mellerud
178
+ '531', # Bengtsfors
179
+ '532', # Åmål
180
+ '533', # Säffle
181
+ '534', # Ed
182
+ '550', # Kristinehamn
183
+ '551', # Gullspång
184
+ '552', # Deje
185
+ '553', # Molkom
186
+ '554', # Kil
187
+ '555', # Grums
188
+ '560', # Torsby
189
+ '563', # Hagfors-Munkfors
190
+ '564', # Sysslebäck
191
+ '565', # Sunne
192
+ '570', # Arvika
193
+ '571', # Charlottenberg-Åmotfors
194
+ '573', # Årjäng
195
+ '580', # Kopparberg
196
+ '581', # Lindesberg
197
+ '582', # Hallsberg
198
+ '583', # Askersund
199
+ '584', # Laxå
200
+ '585', # Fjugesta-Svartå
201
+ '586', # Karlskoga-Degerfors
202
+ '587', # Nora
203
+ '589', # Arboga
204
+ '590', # Filipstad
205
+ '591', # Hällefors-Grythyttan
206
+ '611', # Härnösand
207
+ '612', # Kramfors
208
+ '613', # Ullånger
209
+ '620', # Sollefteå
210
+ '621', # Junsele
211
+ '622', # Näsåker
212
+ '623', # Ramsele
213
+ '624', # Backe
214
+ '640', # Krokom
215
+ '642', # Lit
216
+ '643', # Hallen-Oviken
217
+ '644', # Hammerdal
218
+ '645', # Föllinge
219
+ '647', # Åre-Järpen
220
+ '650', # Hudiksvall
221
+ '651', # Ljusdal
222
+ '652', # Bergsjö
223
+ '653', # Delsbo
224
+ '657', # Los
225
+ '660', # Örnsköldsvik
226
+ '661', # Bredbyn
227
+ '662', # Björna
228
+ '663', # Husum
229
+ '670', # Strömsund
230
+ '671', # Hoting
231
+ '672', # Gäddede
232
+ '680', # Sveg
233
+ '682', # Rätan
234
+ '684', # Hede-Funäsdalen
235
+ '687', # Svenstavik
236
+ '690', # Ånge
237
+ '691', # Torpshammar
238
+ '692', # Liden
239
+ '693', # Bräcke-Gällö
240
+ '695', # Stugun
241
+ '696', # Hammarstrand
242
+ '910', # Skellefteå
243
+ '911', # Piteå
244
+ '912', # Byske
245
+ '913', # Lövånger
246
+ '914', # Burträsk
247
+ '915', # Bastuträsk
248
+ '916', # Jörn
249
+ '918', # Norsjö
250
+ '920', # Luleå
251
+ '921', # Boden
252
+ '922', # Haparanda
253
+ '923', # Kalix
254
+ '924', # Råneå
255
+ '925', # Lakaträsk
256
+ '926', # Överkalix
257
+ '927', # Övertorneå
258
+ '928', # Harads
259
+ '929', # Älvsbyn
260
+ '930', # Nordmaling
261
+ '932', # Bjurholm
262
+ '933', # Vindeln
263
+ '934', # Robertsfors
264
+ '935', # Vännäs
265
+ '940', # Vilhelmina
266
+ '941', # Åsele
267
+ '942', # Dorotea
268
+ '943', # Fredrika
269
+ '950', # Lycksele
270
+ '951', # Storuman
271
+ '952', # Sorsele
272
+ '953', # Malå
273
+ '954', # Tärnaby
274
+ '960', # Arvidsjaur
275
+ '961', # Arjeplog
276
+ '970', # Gällivare
277
+ '971', # Jokkmokk
278
+ '973', # Porjus
279
+ '975', # Hakkas
280
+ '976', # Vuollerim
281
+ '977', # Korpilombolo
282
+ '978', # Pajala
283
+ '980', # Kiruna
284
+ '981' # Vittangi
285
+ ]
286
+
287
+ location_independent_ndcs = [
288
+ '10', # Location independent services (VoIP)
289
+ '70', # Mobile telephony services
290
+ '72', # Mobile telephony services
291
+ '73', # Mobile telephony services
292
+ '74', # Paging services
293
+ '75', # Personal numbering services
294
+ '76', # Mobile telephony services
295
+ '77', # Shared cost services
296
+ '79' # Mobile telephony services
52
297
  ]
298
+
53
299
  service_ndcs = [
54
- '99', # Premium Rate
55
- '900', # Premium Rate
56
- '939', # Premium Rate
57
- '944' # Premium Rate
300
+ '20', # Toll-free services
301
+ '900', # Premium cost services; NB: Conflicts with 90 (Umeå)
302
+ '939', # Premium cost services
303
+ '944' # Premium cost services
304
+ ]
305
+
306
+ mobile_telematic_service_ndcs = ['71']
307
+ fixed_telematic_service_ndcs = ['378']
308
+ operator_specific_ndcs = ['78']
309
+ mass_call_service_ndcs = ['99']
310
+ routing_ndcs = [
311
+ '252', # Routing address - Assigned to Tele2 Sverige AB
312
+ '254', # Routing address – Assigned to Tele2 Sverige AB
313
+ '255', # Routing address – Assigned to Telenor Sverige AB
314
+ '673', # Routing address – Assigned to TeliaSonera Sverige AB
315
+ '674', # Routing address – Assigned to Telenor Sverige AB
316
+ '675', # Routing address – Assigned to Hi3G Access AB
317
+ '676', # Routing address – Assigned to Spring Mobil AB
318
+ '678' # Routing address – Assigned to Götalandsnätet AB
58
319
  ]
59
- three_digit_service = [
320
+
321
+ misc_ndcs = [
322
+ '649', # Routing address – Assigned to Eniro 118118 AB
323
+ '655', # Sample number (national use)
324
+ '656', # Sample number (national use)
325
+ '958' # Routing address – Assigned to TeliaSonera Sverige AB
326
+ ]
327
+
328
+ services = [
329
+ '112', # For emergencies when there is a danger to life, property, or the environment
330
+ '1177', # Healthcare advice for private individuals
331
+ '11313', # National information number for severe accidents and crises
332
+ '11414', # National police number for non-urgent police matters
333
+ '116000' # EU-wide hotline number to report missing children
334
+ ]
335
+
336
+ three_digit_service_ndcs = [
60
337
  '116', # Psychological Help (116 xxx)
61
338
  '118' # Number enquiries (118 xxx)
62
339
  ]
@@ -65,16 +342,47 @@ Phony.define do
65
342
  country '46',
66
343
  trunk('0') |
67
344
  match(/^(#{services.join('|')})$/) >> split(0) |
68
- one_of(service_ndcs) >> split(3, 3) |
69
- match(/^(#{three_digit_service.join('|')})\d{3}$/) >> split(3) |
70
- one_of(ndcs + mobile) >> matched_split(
345
+ match(/^(#{three_digit_service_ndcs.join('|')})\d{3}$/) >> split(3) |
346
+ one_of(service_ndcs) >> matched_split( # NB: Must be *before* the regional NDCs due to ambiguity of 0900
347
+ /^\d{4}$/ => [4],
71
348
  /^\d{5}$/ => [3, 2],
72
349
  /^\d{6}$/ => [2, 2, 2],
73
- /^\d{7}$/ => [3, 2, 2],
74
- /^\d{8}$/ => [3, 2, 3]
350
+ /^\d{7}$/ => [3, 2, 2]
75
351
  ) |
76
- fixed(3) >> matched_split(
352
+ one_of(fixed_telematic_service_ndcs) >> split(3, 2, 2) |
353
+ one_of(routing_ndcs) >> split(3, 3, 3) |
354
+ one_of(regional_ndcs_3) >> matched_split(
355
+ /^11\d$/ => [3],
356
+ /^95\d{2}$/ => [4],
77
357
  /^\d{5}$/ => [3, 2],
78
358
  /^\d{6}$/ => [2, 2, 2]
79
- )
359
+ ) |
360
+ one_of(large_regional_ndcs_2) >> matched_split(
361
+ /^11\d$/ => [3],
362
+ /^95\d{2}$/ => [4],
363
+ /^90\d{3}$/ => [3, 2],
364
+ /^\d{6}$/ => [2, 2, 2],
365
+ /^\d{7}$/ => [3, 2, 2]
366
+ ) |
367
+ one_of(regional_ndcs_2) >> matched_split(
368
+ /^11\d$/ => [3],
369
+ /^95\d{2}$/ => [4],
370
+ /^\d{5}$/ => [3, 2],
371
+ /^\d{6}$/ => [2, 2, 2],
372
+ /^\d{7}$/ => [3, 2, 2]
373
+ ) |
374
+ one_of(location_independent_ndcs) >> split(3, 2, 2) |
375
+ one_of(mobile_telematic_service_ndcs) >> split(3, 3, 3, 2) |
376
+ one_of(mass_call_service_ndcs) >> split(3, 2) |
377
+ one_of(regional_ndcs_1) >> matched_split(
378
+ /^11\d$/ => [3],
379
+ /^95\d$/ => [3],
380
+ /^95\d{2}$/ => [4],
381
+ /^90\d{3}$/ => [3, 2],
382
+ /^\d{6}$/ => [3, 3],
383
+ /^\d{7}$/ => [3, 2, 2],
384
+ /^\d{8}$/ => [3, 2, 3]
385
+ ) |
386
+ one_of(operator_specific_ndcs) >> split(1..11) |
387
+ one_of(misc_ndcs) >> split(1..10)
80
388
  end
@@ -90,6 +90,7 @@ mobile = [
90
90
  '38', # Viettel Mobile
91
91
  '39', # Viettel Mobile
92
92
  '52', # Vietnammobile
93
+ '55', # Wintel (previously known as Reddi)
93
94
  '56', # Vietnamobile
94
95
  '58', # Vietnamobile (previously known as HT Mobile)
95
96
  '59', # GTel (traded as Beeline)
@@ -101,7 +101,7 @@ Phony.define do
101
101
  match(/^(800|90\d)\d+$/) >> split(2, 3) | # Toll free service and premium numbers
102
102
  match(/^(46[056789])\d{6}$/) >> split(2, 2, 2) | # Mobile (Lycamobile, Telenet, Join Experience, Proximus 0460)
103
103
  match(/^(4[789]\d)\d{6}$/) >> split(2, 2, 2) | # Mobile
104
- match(/^(45[56])\d{6}$/) >> split(2, 2, 2) | # Mobile Vikings and Voo
104
+ match(/^(45[156])\d{6}$/) >> split(2, 2, 2) | # Mobile Vikings, Digi and Voo
105
105
  one_of('2', '3', '4', '9') >> split(3, 2, 2) | # Short NDCs
106
106
  fixed(2) >> split(2, 2, 2) # 2-digit NDCs
107
107
 
@@ -229,6 +229,7 @@ Phony.define do
229
229
  # Colombia.
230
230
  # http://www.itu.int/oth/T020200002C/en
231
231
  country '57',
232
+ match(/\A(1800)\d+\z/) >> split(3, 4) | # toll free 1800 numbers
232
233
  match(/\A(3\d\d)\d+\z/) >> split(3, 4) | # mobile (300 310 311 312 313 315 316)
233
234
  match(/\A(60\d)\d+\z/) >> split(3, 4) |
234
235
  fixed(1) >> split(3, 4)
@@ -250,7 +251,7 @@ Phony.define do
250
251
  match(/^(13)\d+$/) >> split(2, 2) | # 13 local rate
251
252
  fixed(1) >> split(4, 4) # Rest
252
253
 
253
- # country '62' # Indonesia (Republic of), see special file
254
+ # country '62' # Indonesia (Republic of), see special file
254
255
 
255
256
  # Philippines (Republic of the)
256
257
  # https://www.numberingplans.com/?page=plans&sub=phonenr&alpha_2_input=PH
@@ -278,7 +279,9 @@ Phony.define do
278
279
 
279
280
  # Singapore (Republic of).
280
281
  #
282
+ # There is no trunk code for this country and some numbers start with 0.
281
283
  country '65',
284
+ trunk('', normalize: false) |
282
285
  none >> matched_split(
283
286
  /^(800)\d{7}$/ => [3, 3, 4], # International Toll Free Service (ITFS) and Home Country Direct Service (HCDS) Numbers
284
287
  /^\d{8}$/ => [4, 4] # TODO: Short Codes
@@ -371,7 +374,16 @@ Phony.define do
371
374
 
372
375
  country '227', none >> split(4, 4) # Niger http://www.wtng.info/wtng-227-ne.html
373
376
  country '228', none >> split(4, 4) # Togolese Republic http://www.wtng.info/wtng-228-tg.html
374
- country '229', none >> split(4, 4) # Benin http://www.itu.int/oth/T0202000017/en
377
+
378
+ # Benin http://www.itu.int/oth/T0202000017/en
379
+ #
380
+ # There is no trunk code for this country and prefixes start with 0.
381
+ country '229',
382
+ trunk('', normalize: false) |
383
+ none >> matched_split(
384
+ # Old empty and new 01 prefix.
385
+ /\A(01)?\d+\z/ => [2, 2, 2, 2, 2]
386
+ )
375
387
 
376
388
  # Mauritius
377
389
  # http://www.wtng.info/wtng-230-mu.html
@@ -388,6 +400,7 @@ Phony.define do
388
400
  # https://www.numberingplans.com/?page=plans&sub=phonenr&alpha_2_input=LR
389
401
  country '231',
390
402
  none >> matched_split(
403
+ /\A88\d{7}\z/ => [2, 3, 4], # mobile Lonestar Cell MTN
391
404
  /\A[23]\d+\z/ => [4, 4], # LIBTELCO, TEMAS
392
405
  /\A[4568]\d+\z/ => [4, 3], # mobile Lonestar, Libercell, Comium Liberia Inc.
393
406
  /\A77\d+\z/ => [2, 3, 4], # http://monrovia.usembassy.gov/contact.html
@@ -791,7 +804,14 @@ Phony.define do
791
804
  one_of('1', '2', '3', '4', '5', '7') >> split(3, 4) | # Ljubljana, Maribor, Celje, Kranj, Nova Gorica, Novo mesto
792
805
  fixed(3) >> split(2, 3) # catchall
793
806
 
794
- country '387', trunk('0') | fixed(2) >> split(3, 3) # Bosnia and Herzegovina
807
+ # Bosnia and Herzegovina
808
+ country '387',
809
+ trunk('0') |
810
+ match(/^(60)(?:31|32|33|34|38|39)/) >> split(7) | # BH Mobile
811
+ match(/^(64)(?:40|41|42|43|44|45)/) >> split(7) | # Haloo
812
+ match(/^(67)(?:11|12)/) >> split(7) | # Novotel
813
+ fixed(2) >> split(3, 3) # catchall
814
+
795
815
  country '388', trunk('0') | fixed(2) >> split(3, 2, 2) # Group of countries, shared code
796
816
 
797
817
  # The Former Yugoslav Republic of Macedonia
@@ -883,6 +903,7 @@ Phony.define do
883
903
  # https://www.numberingplans.com/?page=plans&sub=phonenr&alpha_2_input=EC&current_page=1
884
904
  # https://en.wikipedia.org/wiki/Telephone_numbers_in_Ecuador
885
905
  country '593',
906
+ match(/\A(1800)\d+\z/) >> split(3, 3) | # toll free 1800 numbers
886
907
  one_of('9') >> split(4, 4) |
887
908
  match(/\A([\d]{2})\d{7}\z/) >> split(3, 4) |
888
909
  fixed(1) >> split(3, 4)
@@ -1167,6 +1188,7 @@ Phony.define do
1167
1188
  /\A65816\d+\z/ => [4, 4, 4], # voicemail (mobile), Wataniya Telecom
1168
1189
  /\A1\d+\z/ => [3, 4], # geographic
1169
1190
  /\A2\d+\z/ => [4, 4], # geographic
1191
+ /\A41\d+\z/ => [4, 4], # mobile (Virgin Mobile)
1170
1192
  /\A[569]\d+\z/ => [4, 4], # mobile
1171
1193
  /\A8\d+\z/ => [3, 3] # geographic
1172
1194
  )
data/lib/phony/country.rb CHANGED
@@ -62,6 +62,7 @@ module Phony
62
62
  @codes.each do |national_splitter|
63
63
  new_trunk, ndc, *rest = national_splitter.split national_number
64
64
  trunk ||= new_trunk
65
+ national_number = ndc if new_trunk
65
66
  return [national_splitter.local_splitter, trunk, ndc, *rest] if rest && !rest.empty?
66
67
  end
67
68
 
@@ -166,6 +167,7 @@ module Phony
166
167
  # Note: Options such as CC
167
168
  #
168
169
  def normalize(national_number, options = {})
170
+ national_number = national_number.dup
169
171
  clean! national_number
170
172
  @codes.each_with_object national_number do |code, number|
171
173
  result = code.normalize number, options
@@ -60,6 +60,7 @@ module Phony
60
60
  # * Non-digits.
61
61
  #
62
62
  def normalize(number, options = {})
63
+ number = number.dup
63
64
  country = if (cc = options[:cc])
64
65
  self[cc]
65
66
  else
@@ -94,6 +95,11 @@ module Phony
94
95
  # Is this number plausible?
95
96
  #
96
97
  def plausible?(number, hints = {})
98
+ # Fail if it contains too many of certain phone specific markers:
99
+ # * more than 1 +
100
+ #
101
+ return false if number.count('+') > 1
102
+
97
103
  normalized = clean number
98
104
 
99
105
  # False if it fails the basic check.
@@ -153,11 +159,11 @@ module Phony
153
159
  # Split off the country and the cc, and also return the national number part.
154
160
  #
155
161
  def partial_split(number)
156
- cc = +''
157
162
  1.upto(3) do |i|
158
- cc << number.slice!(0..0)
163
+ cc = number.slice(...i)
164
+ national_number = number.slice(i..)
159
165
  country = countries[i][cc]
160
- return [country, cc, number] if country
166
+ return [country, cc, national_number] if country
161
167
  end
162
168
  # This line is never reached as CCs are in prefix code.
163
169
  end
@@ -168,7 +174,7 @@ module Phony
168
174
  # Note: This won't be correct in some cases, but it is the best we can do.
169
175
  #
170
176
  def countrify(number, cc)
171
- countrify!(number, cc) || number
177
+ countrify!(number.dup, cc) || number
172
178
  end
173
179
 
174
180
  def countrify!(number, cc)
@@ -49,9 +49,11 @@ module Phony
49
49
  # * split '3643533' # => ['364', '35', '33'] # (Switzerland)
50
50
  #
51
51
  def split(number)
52
+ cursor = 0
52
53
  @format.each_with_object([]) do |size, result|
53
- result << number.slice!(0..size - 1)
54
- return result if number.empty?
54
+ result << number.slice(cursor...cursor + size)
55
+ cursor += size
56
+ return result if cursor >= number.size
55
57
  end
56
58
  end
57
59
 
@@ -55,9 +55,11 @@ module Phony
55
55
  private
56
56
 
57
57
  def split_with(number, format)
58
+ cursor = 0
58
59
  format.each_with_object([]) do |size, result|
59
- result << number.slice!(0..size - 1)
60
- return result if number.empty?
60
+ result << number.slice(cursor...cursor + size)
61
+ cursor += size
62
+ return result if cursor >= number.size
61
63
  end << number
62
64
  end
63
65
 
@@ -27,7 +27,7 @@ module Phony
27
27
  def split(national_number)
28
28
  return [@zero, national_number] unless @size
29
29
 
30
- [@zero, national_number.slice!(0...@size), national_number]
30
+ [@zero, national_number.slice(0...@size), national_number.slice(@size..)]
31
31
  end
32
32
 
33
33
  # A valid length.
@@ -11,6 +11,7 @@ module Phony
11
11
  # Takes a national number and splits it into ndc and rest.
12
12
  #
13
13
  def split(national_number)
14
+ national_number = national_number.dup
14
15
  fallback_number = national_number.dup
15
16
 
16
17
  # Extract a starting point.
@@ -29,15 +29,18 @@ module Phony
29
29
  # its parts.
30
30
  #
31
31
  def split(national_number)
32
- national_number.gsub! @trunk_code_replacement, EMPTY_STRING if @split
33
- [self, national_number]
32
+ return [self, national_number] unless @split
33
+
34
+ without_trunk = national_number.gsub @trunk_code_replacement, EMPTY_STRING
35
+ [self, without_trunk]
34
36
  end
35
37
 
36
38
  # Normalize normalizes the given national number.
37
39
  #
38
40
  def normalize(national_number, options = {})
39
- national_number.gsub! @trunk_code_replacement, EMPTY_STRING if @normalize && options[:cc]
40
- national_number
41
+ return national_number unless @normalize && options[:cc]
42
+
43
+ national_number.gsub @trunk_code_replacement, EMPTY_STRING
41
44
  end
42
45
 
43
46
  # Format the trunk code using the spaces given.
@@ -49,7 +52,6 @@ module Phony
49
52
  else
50
53
  @code
51
54
  end
52
-
53
55
  end
54
56
  end
55
57
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: phony
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.20.15
4
+ version: 3.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Hanke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-17 00:00:00.000000000 Z
11
+ date: 2025-12-13 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: 'Fast international phone number (E164 standard) normalizing, splitting
14
14
  and formatting. Lots of formatting options: International (+.., 00..), national
@@ -17,9 +17,9 @@ email: florian.hanke+phony@gmail.com
17
17
  executables: []
18
18
  extensions: []
19
19
  extra_rdoc_files:
20
- - README.textile
20
+ - README.md
21
21
  files:
22
- - README.textile
22
+ - README.md
23
23
  - lib/phony.rb
24
24
  - lib/phony/config.rb
25
25
  - lib/phony/countries.rb
@@ -82,7 +82,8 @@ files:
82
82
  homepage: https://github.com/floere/phony
83
83
  licenses:
84
84
  - MIT
85
- metadata: {}
85
+ metadata:
86
+ rubygems_mfa_required: 'true'
86
87
  post_install_message:
87
88
  rdoc_options: []
88
89
  require_paths:
@@ -91,7 +92,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
91
92
  requirements:
92
93
  - - ">="
93
94
  - !ruby/object:Gem::Version
94
- version: '2.7'
95
+ version: '3.2'
95
96
  required_rubygems_version: !ruby/object:Gem::Requirement
96
97
  requirements:
97
98
  - - ">="
data/README.textile DELETED
@@ -1,116 +0,0 @@
1
- "!{float:right}https://secure.travis-ci.org/floere/phony.png!":http://travis-ci.org/floere/phony
2
- !https://coveralls.io/repos/floere/phony/badge.svg?branch=master(Coverage Status)!:https://coveralls.io/r/floere/phony?branch=master
3
- "!https://codeclimate.com/github/floere/phony.png!":https://codeclimate.com/github/floere/phony
4
- !http://inch-ci.org/github/floere/phony.png!:http://inch-ci.org/github/floere/phony
5
-
6
- h1. Phony
7
-
8
- Disclaimer: Phony works with international numbers only, such as @61 412 345 678@!
9
-
10
- The (admittedly crazy) goal of this Gem is to be able to normalize/format/split all phone numbers in the world.
11
-
12
- Used in: "airbnb.com":http://airbnb.com, "socialcam.com":http://socialcam.com, "zendesk.com":http://www.zendesk.com/ (and many, many others).
13
-
14
- h2(#memory). Runtime Memory Usage
15
-
16
- According to "memory_profiler":https://github.com/SamSaffron/memory_profiler, the Phony gem uses roughly 1MB of memory per Ruby process.
17
- Usage was generated using (look for @Total retained@): @ruby -e 'require "memory_profiler"; MemoryProfiler.report(allow_files: "phony"){ require "phony" }.pretty_print'@
18
-
19
- h2. Description
20
-
21
- This gem normalizes, formats and splits "*E164 phone numbers*":http://en.wikipedia.org/wiki/E.164. A valid E164 phone number *must* include a country code.
22
-
23
- E164 numbers are international numbers with a country dial prefix, usually an area code and a subscriber number. For example, the Australian number @+61 412 345 678@ can be broken down into the following components:
24
- * Country Code (CC): a country code of @61@
25
- * National Destination Code (NDC): a mobile number denoted by the @4@ (specific to Australia)
26
- * Local Number Part: a subscriber number of @12 345 678@
27
-
28
- It currently handles the countries listed at the end of this README.
29
-
30
- It is covered by roughly 2,250 tests that run in 2 seconds (April 2019).
31
- If it doesn't work, please "enter an issue":http://github.com/floere/phony/issues or better, fork and "send a pull request":http://github.com/floere/phony/pulls.
32
-
33
- h2. Installation
34
-
35
- With Rails? Check out: https://github.com/joost/phony_rails.
36
-
37
- With Bundler: Append @gem 'phony'@ to your @Gemfile@ and @bundle install@ it.
38
-
39
- Without Bundler: Run @gem install phony@ from your command line.
40
-
41
- h2(#usage). Usage docs
42
-
43
- Phony uses "qed":https://github.com/rubyworks/qed as docs and to run its functional tests. Start here for usage docs: "Usage index":./qed/index.md.
44
-
45
- h3(#normalizing). Phony.normalize(number)
46
-
47
- Normalize intelligently removes all non-numeric characters of a number. Do it before storing a number in a DB.
48
-
49
- "Phony.normalize docs":./qed/normalize.md
50
-
51
- @Phony.normalize('1-888-407-4747').assert == '18884074747'@
52
-
53
- h3(#formatting). Phony.format(number, options = {})
54
-
55
- Format formats a normalized number according to a country's predominant formatting. Lots of options for int'l, national, local formatting.
56
-
57
- "Phony.format docs":./qed/format.md
58
-
59
- @Phony.format('41443643532').assert == '+41 44 364 35 32'@
60
-
61
- h3(#plausibility). Phony.plausible?(number, options = {})
62
-
63
- Is a number plausible?
64
-
65
- "Phony.plausible? docs":./qed/plausibility.md
66
-
67
- @Phony.assert.plausible?('+41 44 111 22 33')@
68
-
69
- h3(#splitting). Phony.split(number)
70
-
71
- Split a number into its parts: CC, NDC, local.
72
-
73
- "Phony.split docs":./qed/split.md
74
-
75
- @Phony.split('3928061371').assert == ['39', '2', '806', '1371']@
76
-
77
- NB If a country does not have an NDC, @#split@ will return @false@ in the NDC position, for example for Denmark:
78
-
79
- @Phony.split('4512121212').assert == ['45', false, '12', '12', '12', '12']@
80
-
81
- h3(#loading). Loading only a country subset (Phony 2.18.0+).
82
-
83
- Use this in case you'd like to save "memory":#memory that is used by Phony's CC rules.
84
-
85
- "Phony::Config.load docs":./qed/config.md
86
-
87
- First, @require 'phony/config'@.
88
- Then, one of the following, which will load the rest of Phony.
89
-
90
- Load only these CCs:
91
- @Phony::Config.load(only: ['41', '44'])@
92
-
93
- Loads everything except these CCs:
94
- @Phony::Config.load(except: ['41', '44'])@
95
-
96
- Convenience form of @only@:
97
- @Phony::Config.load('41', '44')@
98
-
99
- Each of these loads the rest of Phony.
100
-
101
- Memory usage can be checked using (look for @Total retained@):
102
- @ruby -e 'require "memory_profiler"; MemoryProfiler.report(allow_files: "phony"){ require "phony/config"; Phony::Config.load("1") }.pretty_print'@
103
- For example, when just loading the NANP CC, the retained memory usage is ~63kB.
104
-
105
- h2. List of Handled Countries
106
-
107
- Mildly unmaintained list: Abhas, Afghan, Algerian, Argentina, Austrian, Australian, Azerbaijani, Belgian, Brazilian, Cambodian, Chilean, Chinese, Croatian, Cuban, Cypriot, Czech, Danish, Dutch, Egyptian, El Salvadorian, Estonian, French, German, Ghanan, Gibraltar, Greek, Haiti, Hong Kong, Hungarian, Indian, Iran, Irish, Israel, Italian, Japanese, Kazakh, Liberian, Lithuanian, Luxembourgian, Malaysian, Malta, Mauritian, Mexican, Monaco, Morocco, New Zealand, Nigerian, Norwegian, Peruvian, Polish, Romanian, Russian, Rwandan, Seychelles, Singapore, Slovakian, South African, South Korean, South Osetian, Spanish, Sri Lankan, Sudan, Swedish, Swiss, Thailand, Tunisian, Turkish, Liechtenstein, UK, US, Venezuelan, Vietnamese, and Zambian numbers.
108
-
109
- h2. Proud Sponsors
110
-
111
- * Renuo AG (July 22 –): "Github":https://github.com/renuo, "Homepage":https://www.renuo.ch
112
-
113
- h2. License
114
-
115
- MIT.
116
- See "LICENSE":./LICENSE file.