phony 1.9.0 → 2.19.14

Sign up to get free protection for your applications and to get access to all the features.
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