phony 1.9.0 → 2.19.14

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.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/README.textile +64 -112
  3. data/lib/phony/config.rb +91 -0
  4. data/lib/phony/countries/argentina.rb +355 -0
  5. data/lib/phony/countries/austria.rb +56 -22
  6. data/lib/phony/countries/bangladesh.rb +57 -0
  7. data/lib/phony/countries/belarus.rb +133 -0
  8. data/lib/phony/countries/brazil.rb +101 -95
  9. data/lib/phony/countries/cambodia.rb +131 -0
  10. data/lib/phony/countries/china.rb +13 -6
  11. data/lib/phony/countries/croatia.rb +23 -0
  12. data/lib/phony/countries/georgia.rb +94 -0
  13. data/lib/phony/countries/germany.rb +66 -42
  14. data/lib/phony/countries/guinea.rb +46 -0
  15. data/lib/phony/countries/india.rb +50 -0
  16. data/lib/phony/countries/indonesia.rb +55 -0
  17. data/lib/phony/countries/ireland.rb +35 -28
  18. data/lib/phony/countries/italy.rb +272 -166
  19. data/lib/phony/countries/japan.rb +468 -0
  20. data/lib/phony/countries/kyrgyzstan.rb +120 -0
  21. data/lib/phony/countries/latvia.rb +43 -0
  22. data/lib/phony/countries/libya.rb +116 -0
  23. data/lib/phony/countries/malaysia.rb +31 -7
  24. data/lib/phony/countries/moldova.rb +53 -0
  25. data/lib/phony/countries/montenegro.rb +30 -0
  26. data/lib/phony/countries/myanmar.rb +55 -0
  27. data/lib/phony/countries/namibia.rb +37 -0
  28. data/lib/phony/countries/nepal.rb +73 -0
  29. data/lib/phony/countries/netherlands.rb +17 -5
  30. data/lib/phony/countries/pakistan.rb +121 -0
  31. data/lib/phony/countries/paraguay.rb +147 -0
  32. data/lib/phony/countries/{russia_kazakhstan_abhasia_south_osetia.rb → russia_kazakhstan_abkhasia_south_ossetia.rb} +35 -24
  33. data/lib/phony/countries/saudi_arabia.rb +40 -0
  34. data/lib/phony/countries/serbia.rb +47 -0
  35. data/lib/phony/countries/somalia.rb +26 -0
  36. data/lib/phony/countries/south_korea.rb +19 -10
  37. data/lib/phony/countries/sweden.rb +58 -38
  38. data/lib/phony/countries/taiwan.rb +28 -0
  39. data/lib/phony/countries/tajikistan.rb +79 -0
  40. data/lib/phony/countries/turkmenistan.rb +76 -0
  41. data/lib/phony/countries/ukraine.rb +630 -0
  42. data/lib/phony/countries/united_kingdom.rb +639 -44
  43. data/lib/phony/countries/uruguay.rb +53 -0
  44. data/lib/phony/countries/vietnam.rb +133 -0
  45. data/lib/phony/countries/zimbabwe.rb +39 -0
  46. data/lib/phony/countries.rb +901 -301
  47. data/lib/phony/country.rb +177 -20
  48. data/lib/phony/country_codes.rb +119 -101
  49. data/lib/phony/dsl.rb +113 -68
  50. data/lib/phony/local_splitters/fixed.rb +25 -1
  51. data/lib/phony/local_splitters/regex.rb +16 -2
  52. data/lib/phony/national_code.rb +7 -7
  53. data/lib/phony/national_splitters/default.rb +35 -3
  54. data/lib/phony/national_splitters/dsl.rb +12 -7
  55. data/lib/phony/national_splitters/fixed.rb +7 -1
  56. data/lib/phony/national_splitters/none.rb +7 -3
  57. data/lib/phony/national_splitters/regex.rb +6 -0
  58. data/lib/phony/national_splitters/variable.rb +13 -9
  59. data/lib/phony/trunk_code.rb +57 -0
  60. data/lib/phony/vanity.rb +3 -3
  61. data/lib/phony.rb +239 -55
  62. data/spec/functional/config_spec.rb +44 -0
  63. data/spec/functional/plausibility_spec.rb +656 -0
  64. data/spec/lib/phony/countries_spec.rb +1207 -119
  65. data/spec/lib/phony/country_codes_spec.rb +99 -81
  66. data/spec/lib/phony/country_spec.rb +54 -14
  67. data/spec/lib/phony/dsl_spec.rb +2 -2
  68. data/spec/lib/phony/local_splitters/fixed_spec.rb +4 -4
  69. data/spec/lib/phony/local_splitters/regex_spec.rb +50 -2
  70. data/spec/lib/phony/national_code_spec.rb +34 -34
  71. data/spec/lib/phony/national_splitters/default_spec.rb +34 -0
  72. data/spec/lib/phony/national_splitters/fixed_spec.rb +12 -6
  73. data/spec/lib/phony/national_splitters/none_spec.rb +13 -3
  74. data/spec/lib/phony/national_splitters/regex_spec.rb +1 -1
  75. data/spec/lib/phony/national_splitters/variable_spec.rb +11 -5
  76. data/spec/lib/phony/trunk_code_spec.rb +85 -0
  77. data/spec/lib/phony/vanity_spec.rb +15 -19
  78. data/spec/lib/phony_spec.rb +59 -277
  79. metadata +67 -34
  80. data/lib/phony/validator.rb +0 -26
  81. data/lib/phony/validators.rb +0 -88
  82. data/spec/lib/phony/validations_spec.rb +0 -109
data/lib/phony.rb CHANGED
@@ -1,83 +1,270 @@
1
+ # frozen_string_literal: true
2
+
3
+ # NOTE We use Kernel.load here, as it's possible to redefine Phony via Phony::Config.
4
+
1
5
  # Framework.
2
6
  #
3
- require File.expand_path '../phony/vanity', __FILE__
4
- require File.expand_path '../phony/local_splitters/fixed', __FILE__
5
- require File.expand_path '../phony/local_splitters/regex', __FILE__
6
- require File.expand_path '../phony/national_splitters/dsl', __FILE__
7
- require File.expand_path '../phony/national_splitters/fixed', __FILE__
8
- require File.expand_path '../phony/national_splitters/variable', __FILE__
9
- require File.expand_path '../phony/national_splitters/regex', __FILE__
10
- require File.expand_path '../phony/national_splitters/default', __FILE__
11
- require File.expand_path '../phony/national_splitters/none', __FILE__
12
- require File.expand_path '../phony/national_code', __FILE__
13
- require File.expand_path '../phony/country', __FILE__
14
- require File.expand_path '../phony/country_codes', __FILE__
15
- require File.expand_path '../phony/validator', __FILE__
16
- require File.expand_path '../phony/validators', __FILE__
17
- require File.expand_path '../phony/dsl', __FILE__
7
+ load File.expand_path '../phony/config.rb', __FILE__
8
+ load File.expand_path '../phony/vanity.rb', __FILE__
9
+ load File.expand_path '../phony/local_splitters/fixed.rb', __FILE__
10
+ load File.expand_path '../phony/local_splitters/regex.rb', __FILE__
11
+ load File.expand_path '../phony/national_splitters/dsl.rb', __FILE__
12
+ load File.expand_path '../phony/national_splitters/fixed.rb', __FILE__
13
+ load File.expand_path '../phony/national_splitters/variable.rb', __FILE__
14
+ load File.expand_path '../phony/national_splitters/regex.rb', __FILE__
15
+ load File.expand_path '../phony/national_splitters/default.rb', __FILE__
16
+ load File.expand_path '../phony/national_splitters/none.rb', __FILE__
17
+ load File.expand_path '../phony/national_code.rb', __FILE__
18
+ load File.expand_path '../phony/country.rb', __FILE__
19
+ load File.expand_path '../phony/trunk_code.rb', __FILE__
20
+ load File.expand_path '../phony/country_codes.rb', __FILE__
21
+ load File.expand_path '../phony/dsl.rb', __FILE__
18
22
 
19
23
  # Countries.
20
24
  #
21
25
  # The ones that need more space to define.
22
26
  #
23
- require File.expand_path '../phony/countries/austria', __FILE__
24
- require File.expand_path '../phony/countries/brazil', __FILE__
25
- require File.expand_path '../phony/countries/china', __FILE__
26
- require File.expand_path '../phony/countries/germany', __FILE__
27
- require File.expand_path '../phony/countries/ireland', __FILE__
28
- require File.expand_path '../phony/countries/italy', __FILE__
29
- require File.expand_path '../phony/countries/malaysia', __FILE__
30
- require File.expand_path '../phony/countries/netherlands', __FILE__
31
- require File.expand_path '../phony/countries/russia_kazakhstan_abhasia_south_osetia', __FILE__
32
- require File.expand_path '../phony/countries/south_korea', __FILE__
33
- require File.expand_path '../phony/countries/sweden', __FILE__
34
- require File.expand_path '../phony/countries/united_kingdom', __FILE__
35
- #
27
+ load File.expand_path '../phony/countries/argentina.rb', __FILE__
28
+ load File.expand_path '../phony/countries/austria.rb', __FILE__
29
+ load File.expand_path '../phony/countries/bangladesh.rb', __FILE__
30
+ load File.expand_path '../phony/countries/belarus.rb', __FILE__
31
+ load File.expand_path '../phony/countries/brazil.rb', __FILE__
32
+ load File.expand_path '../phony/countries/cambodia.rb', __FILE__
33
+ load File.expand_path '../phony/countries/croatia.rb', __FILE__
34
+ load File.expand_path '../phony/countries/china.rb', __FILE__
35
+ load File.expand_path '../phony/countries/georgia.rb', __FILE__
36
+ load File.expand_path '../phony/countries/germany.rb', __FILE__
37
+ load File.expand_path '../phony/countries/guinea.rb', __FILE__
38
+ load File.expand_path '../phony/countries/india.rb', __FILE__
39
+ load File.expand_path '../phony/countries/indonesia.rb', __FILE__
40
+ load File.expand_path '../phony/countries/ireland.rb', __FILE__
41
+ load File.expand_path '../phony/countries/italy.rb', __FILE__
42
+ load File.expand_path '../phony/countries/japan.rb', __FILE__
43
+ load File.expand_path '../phony/countries/kyrgyzstan.rb', __FILE__
44
+ load File.expand_path '../phony/countries/latvia.rb', __FILE__
45
+ load File.expand_path '../phony/countries/libya.rb', __FILE__
46
+ load File.expand_path '../phony/countries/malaysia.rb', __FILE__
47
+ load File.expand_path '../phony/countries/moldova.rb', __FILE__
48
+ load File.expand_path '../phony/countries/montenegro.rb', __FILE__
49
+ load File.expand_path '../phony/countries/myanmar.rb', __FILE__
50
+ load File.expand_path '../phony/countries/namibia.rb', __FILE__
51
+ load File.expand_path '../phony/countries/nepal.rb', __FILE__
52
+ load File.expand_path '../phony/countries/netherlands.rb', __FILE__
53
+ load File.expand_path '../phony/countries/pakistan.rb', __FILE__
54
+ load File.expand_path '../phony/countries/paraguay.rb', __FILE__
55
+ load File.expand_path '../phony/countries/russia_kazakhstan_abkhasia_south_ossetia.rb', __FILE__
56
+ load File.expand_path '../phony/countries/saudi_arabia.rb', __FILE__
57
+ load File.expand_path '../phony/countries/serbia.rb', __FILE__
58
+ load File.expand_path '../phony/countries/somalia.rb', __FILE__
59
+ load File.expand_path '../phony/countries/south_korea.rb', __FILE__
60
+ load File.expand_path '../phony/countries/sweden.rb', __FILE__
61
+ load File.expand_path '../phony/countries/taiwan.rb', __FILE__
62
+ load File.expand_path '../phony/countries/tajikistan.rb', __FILE__
63
+ load File.expand_path '../phony/countries/turkmenistan.rb', __FILE__
64
+ load File.expand_path '../phony/countries/vietnam.rb', __FILE__
65
+ load File.expand_path '../phony/countries/ukraine.rb', __FILE__
66
+ load File.expand_path '../phony/countries/united_kingdom.rb', __FILE__
67
+ load File.expand_path '../phony/countries/uruguay.rb', __FILE__
68
+ load File.expand_path '../phony/countries/zimbabwe.rb', __FILE__
69
+
36
70
  # All other countries.
37
71
  #
38
- require File.expand_path '../phony/countries', __FILE__
72
+ load File.expand_path '../phony/countries.rb', __FILE__
39
73
 
74
+ # Phony is the main module and is generally used to process
75
+ # E164 phone numbers directly.
76
+ #
40
77
  module Phony
41
78
 
79
+ # Raised in case Phony can't normalize a given number.
80
+ #
81
+ # @example
82
+ # Phony.normalize("Fnork!") # Raises a Phony::NormalizationError.
83
+ #
84
+ class NormalizationError < ArgumentError
85
+ def initialize
86
+ super %Q{Phony could not normalize the given number. Is it a phone number?}
87
+ end
88
+ end
89
+
90
+ # Raised in case Phony can't split a given number.
91
+ #
92
+ # @example
93
+ # Phony.split("Fnork!") # Raises a Phony::SplittingError.
94
+ #
95
+ class SplittingError < ArgumentError
96
+ def initialize number
97
+ super %Q{Phony could not split the given number. Is #{(number.nil? || number == '') ? 'it' : number.inspect} a phone number?}
98
+ end
99
+ end
100
+
101
+ # Raised in case Phony can't format a given number.
102
+ #
103
+ # @example
104
+ # Phony.format("Fnork!") # Raises a Phony::FormattingError.
105
+ #
106
+ class FormattingError < ArgumentError
107
+ def initialize
108
+ super %Q{Phony could not format the given number. Is it a phone number?}
109
+ end
110
+ end
111
+
42
112
  # Phony uses a single country codes instance.
43
113
  #
44
- @codes = CountryCodes.instance
45
- @validators = Validators.instance
114
+ @codes = CountryCodes.instance
46
115
 
47
116
  class << self
48
117
 
49
- # Normalizes the given number.
118
+ # Get the Country for the given CC.
119
+ #
120
+ # @param [String] cc A valid country code.
121
+ #
122
+ # @return [Country] for the given CC.
123
+ #
124
+ # @example Country for the NANP (includes the US)
125
+ # nanp = Phony['1']
126
+ # normalized_number = nanp.normalize number
127
+ #
128
+ def [] cc
129
+ @codes[cc]
130
+ end
131
+
132
+ # Normalizes the given number into a digits-only String.
50
133
  #
51
134
  # Useful before inserting the number into a database.
52
135
  #
53
- def normalize phone_number
136
+ # @param [String] phone_number An E164 number.
137
+ # @param [Hash] options An options hash (With :cc as the only used key).
138
+ #
139
+ # @return [String] A normalized E164 number.
140
+ #
141
+ # @raise [Phony::NormalizationError] If phony can't normalize the given number.
142
+ #
143
+ # @example Normalize a Swiss number.
144
+ # Phony.normalize("+41 (044) 123 45 67") # => "41441234567"
145
+ #
146
+ # @example Normalize a phone number assuming it's a NANP number.
147
+ # Phony.normalize("301 555 0100", cc: '1') # => "13015550100"
148
+ #
149
+ def normalize phone_number, options = {}
54
150
  raise ArgumentError, "Phone number cannot be nil. Use e.g. number && Phony.normalize(number)." unless phone_number
55
- normalize! phone_number.dup
151
+
152
+ normalize! phone_number.dup, options
56
153
  end
57
- def normalize! phone_number
58
- @codes.normalize phone_number
154
+ # A destructive version of {#normalize}.
155
+ #
156
+ # @see #normalize
157
+ #
158
+ # @param [String] phone_number An E164 number.
159
+ # @param [Hash] options An options hash (With :cc as the only used key).
160
+ #
161
+ # @return [String] The normalized E164 number.
162
+ #
163
+ # @raise [Phony::NormalizationError] If phony can't normalize the given number.
164
+ #
165
+ # @example Normalize a Swiss number.
166
+ # Phony.normalize!("+41 (044) 123 45 67") # => "41441234567"
167
+ #
168
+ # @example Normalize a phone number assuming it's a NANP number.
169
+ # Phony.normalize!("301 555 0100", cc: '1') # => "13015550100"
170
+ #
171
+ def normalize! phone_number, options = {}
172
+ @codes.normalize phone_number, options
173
+ rescue
174
+ raise NormalizationError.new
59
175
  end
60
176
 
61
177
  # Splits the phone number into pieces according to the country codes.
62
178
  #
179
+ # Useful for manually processing the CC, NDC, and local pieces.
180
+ #
181
+ # @param [String] phone_number An E164 number.
182
+ #
183
+ # @return [Array<String>] The pieces of a phone number.
184
+ #
185
+ # @example Split a Swiss number.
186
+ # Phony.split("41441234567") # => ["41", "44", "123", "45", "67"]
187
+ #
188
+ # @example Split a NANP number.
189
+ # Phony.split("13015550100") # => ["1", "301", "555", "0100"]
190
+ #
63
191
  def split phone_number
64
192
  raise ArgumentError, "Phone number cannot be nil. Use e.g. number && Phony.split(number)." unless phone_number
65
- split! phone_number.dup
193
+
194
+ split! phone_number.dup, phone_number
66
195
  end
67
- def split! phone_number
68
- parts = @codes.split phone_number
69
- parts.delete_at 1
70
- parts
196
+ # A destructive version of {#split}.
197
+ #
198
+ # @see #split
199
+ #
200
+ # @param [String] phone_number An E164 number.
201
+ #
202
+ # @return [Array<String>] The pieces of the phone number.
203
+ #
204
+ # @example Split a Swiss number.
205
+ # Phony.split!("41441234567") # => ["41", "44", "123", "45", "67"]
206
+ #
207
+ # @example Split a NANP number.
208
+ # Phony.split!("13015550100") # => ["1", "301", "555", "0100"]
209
+ #
210
+ def split! phone_number, error_number = nil
211
+ @codes.split phone_number
212
+ rescue
213
+ # NB The error_number (reference) is used because phone_number is destructively handled.
214
+ raise SplittingError.new(error_number)
71
215
  end
72
216
 
73
- # Formats a E164 number according to local customs.
217
+ # Formats a normalized E164 number according to a country's formatting scheme.
218
+ #
219
+ # Absolutely needs a normalized E164 number.
220
+ #
221
+ # @param [String] phone_number A normalized E164 number.
222
+ # @param [Hash] options See the README for a list of options.
223
+ #
224
+ # @return [Array<String>] The pieces of a phone number.
225
+ #
226
+ # @example Format a Swiss number.
227
+ # Phony.format("41441234567") # => "+41 44 123 45 67"
228
+ #
229
+ # @example Format a NANP number.
230
+ # Phony.format("13015550100") # => "+1 301 555 0100"
231
+ #
232
+ # @example Format a NANP number in local format.
233
+ # Phony.format("13015550100", :format => :local) # => "555 0100"
234
+ #
235
+ # @example Format a NANP number in a specific format.
236
+ # Phony.format("13015550100", :format => '%{cc} (%{trunk}%{ndc}) %{local}') # => "555 0100"
74
237
  #
75
238
  def format phone_number, options = {}
76
239
  raise ArgumentError, "Phone number cannot be nil. Use e.g. number && Phony.format(number)." unless phone_number
77
- formatted! phone_number.dup, options
240
+ format! phone_number.dup, options
78
241
  end
242
+ # A destructive version of {#format}.
243
+ #
244
+ # @see #format
245
+ #
246
+ # Formats a normalized E164 number according to a country's formatting scheme.
247
+ #
248
+ # Absolutely needs a normalized E164 number.
249
+ #
250
+ # @param [String] phone_number A normalized E164 number.
251
+ # @param [Hash] options See the README for a list of options.
252
+ #
253
+ # @return [Array<String>] The pieces of the phone number.
254
+ #
255
+ # @example Format a Swiss number.
256
+ # Phony.format!("41441234567") # => "+41 44 123 45 67"
257
+ #
258
+ # @example Format a NANP number.
259
+ # Phony.format!("13015550100") # => "+1 301 555 0100"
260
+ #
261
+ # @example Format a NANP number in local format.
262
+ # Phony.format!("13015550100", :format => :local) # => "555 0100"
263
+ #
79
264
  def format! phone_number, options = {}
80
- @codes.formatted phone_number, options
265
+ @codes.format phone_number, options
266
+ rescue
267
+ raise FormattingError.new
81
268
  end
82
269
  alias formatted format
83
270
  alias formatted! format!
@@ -89,19 +276,9 @@ module Phony
89
276
  # leaning towards being plausible.
90
277
  #
91
278
  def plausible? number, hints = {}
92
- @validators.plausible? number, hints
279
+ @codes.plausible? number, hints
93
280
  end
94
281
 
95
- # def service? number
96
- # @codes.service? number.dup
97
- # end
98
- # def mobile? number
99
- # @codes.mobile? number.dup
100
- # end
101
- # def landline? number
102
- # @codes.landline? number.dup
103
- # end
104
-
105
282
  # Returns true if there is a character in the number
106
283
  # after the first four numbers.
107
284
  #
@@ -112,6 +289,13 @@ module Phony
112
289
  # Converts any character in the vanity_number to its numeric representation.
113
290
  # Does not check if the passed number is a valid vanity_number, simply does replacement.
114
291
  #
292
+ # @param [String] vanity_number A vanity number.
293
+ #
294
+ # @return [String] The de-vanitized phone number.
295
+ #
296
+ # @example De-vanitize a number.
297
+ # Phony.vanity_to_number("1-800-HELLOTHERE") # => "1-800-4355684373"
298
+ #
115
299
  def vanity_to_number vanity_number
116
300
  @codes.vanity_to_number vanity_number.dup
117
301
  end
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+ #
3
+ describe 'Phony::Config' do
4
+ describe 'load' do
5
+ before do
6
+ # NOTE We redefine Phony as if it was not loaded for this set of tests.
7
+ Object.__send__(:remove_const, :Phony) if Object.constants.include?(:Phony)
8
+
9
+ load 'phony/config.rb'
10
+ end
11
+ after(:all) do
12
+ # After running this suite, we load all of Phony for the following tests.
13
+ load 'phony/config.rb'
14
+
15
+ Phony::Config.load
16
+ end
17
+
18
+ it 'does not fail when loading all' do
19
+ Phony::Config.load
20
+
21
+ Phony.split('15551115511').should == ['1', '555', '111', '5511']
22
+ end
23
+ it 'raises when a CC is used that has not been loaded.' do
24
+ Phony::Config.load('41')
25
+
26
+ expect { Phony.split('15551115511') }.to raise_error
27
+ end
28
+ it 'raises when a CC is used that has not been loaded.' do
29
+ Phony::Config.load(only: ['41'])
30
+
31
+ expect { Phony.split('15551115511') }.to raise_error
32
+ end
33
+ it 'raises when a CC is used that has not been loaded.' do
34
+ Phony::Config.load(except: ['1'])
35
+
36
+ expect { Phony.split('15551115511') }.to raise_error
37
+ end
38
+ it 'does not raise when a CC is used that has been loaded.' do
39
+ Phony::Config.load(except: ['41'])
40
+
41
+ Phony.split('15551115511').should == ['1', '555', '111', '5511']
42
+ end
43
+ end
44
+ end