phony 2.15.0 → 2.20.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +5 -5
  2. data/README.textile +35 -7
  3. data/lib/phony/config.rb +91 -0
  4. data/lib/phony/countries/argentina.rb +355 -0
  5. data/lib/phony/countries/austria.rb +34 -24
  6. data/lib/phony/countries/bangladesh.rb +2 -0
  7. data/lib/phony/countries/belarus.rb +2 -0
  8. data/lib/phony/countries/brazil.rb +6 -4
  9. data/lib/phony/countries/cambodia.rb +6 -4
  10. data/lib/phony/countries/china.rb +7 -2
  11. data/lib/phony/countries/croatia.rb +13 -16
  12. data/lib/phony/countries/georgia.rb +6 -4
  13. data/lib/phony/countries/germany.rb +5 -2
  14. data/lib/phony/countries/guinea.rb +8 -5
  15. data/lib/phony/countries/india.rb +2 -0
  16. data/lib/phony/countries/indonesia.rb +8 -3
  17. data/lib/phony/countries/ireland.rb +27 -23
  18. data/lib/phony/countries/italy.rb +30 -17
  19. data/lib/phony/countries/japan.rb +61 -8
  20. data/lib/phony/countries/kyrgyzstan.rb +2 -0
  21. data/lib/phony/countries/latvia.rb +2 -0
  22. data/lib/phony/countries/libya.rb +3 -1
  23. data/lib/phony/countries/malaysia.rb +22 -2
  24. data/lib/phony/countries/moldova.rb +2 -0
  25. data/lib/phony/countries/montenegro.rb +2 -0
  26. data/lib/phony/countries/myanmar.rb +2 -0
  27. data/lib/phony/countries/namibia.rb +2 -0
  28. data/lib/phony/countries/nepal.rb +2 -0
  29. data/lib/phony/countries/netherlands.rb +5 -1
  30. data/lib/phony/countries/pakistan.rb +2 -0
  31. data/lib/phony/countries/paraguay.rb +2 -0
  32. data/lib/phony/countries/russia_kazakhstan_abkhasia_south_ossetia.rb +24 -14
  33. data/lib/phony/countries/saudi_arabia.rb +40 -0
  34. data/lib/phony/countries/serbia.rb +10 -4
  35. data/lib/phony/countries/somalia.rb +5 -1
  36. data/lib/phony/countries/south_korea.rb +16 -9
  37. data/lib/phony/countries/sweden.rb +53 -38
  38. data/lib/phony/countries/taiwan.rb +22 -46
  39. data/lib/phony/countries/tajikistan.rb +2 -0
  40. data/lib/phony/countries/turkmenistan.rb +2 -0
  41. data/lib/phony/countries/ukraine.rb +5 -2
  42. data/lib/phony/countries/united_kingdom.rb +5 -2
  43. data/lib/phony/countries/uruguay.rb +2 -0
  44. data/lib/phony/countries/vietnam.rb +94 -92
  45. data/lib/phony/countries/zimbabwe.rb +2 -0
  46. data/lib/phony/countries.rb +210 -98
  47. data/lib/phony/country.rb +15 -3
  48. data/lib/phony/country_codes.rb +17 -4
  49. data/lib/phony/dsl.rb +5 -3
  50. data/lib/phony/local_splitters/fixed.rb +2 -0
  51. data/lib/phony/national_code.rb +1 -1
  52. data/lib/phony/national_splitters/none.rb +1 -3
  53. data/lib/phony/trunk_code.rb +5 -4
  54. data/lib/phony/vanity.rb +1 -1
  55. data/lib/phony.rb +94 -59
  56. data/spec/functional/config_spec.rb +44 -0
  57. data/spec/functional/plausibility_spec.rb +373 -35
  58. data/spec/lib/phony/countries_spec.rb +295 -63
  59. data/spec/lib/phony/country_codes_spec.rb +106 -33
  60. data/spec/lib/phony/country_spec.rb +54 -15
  61. data/spec/lib/phony/dsl_spec.rb +2 -2
  62. data/spec/lib/phony/local_splitters/regex_spec.rb +12 -5
  63. data/spec/lib/phony/national_splitters/default_spec.rb +1 -1
  64. data/spec/lib/phony/trunk_code_spec.rb +85 -0
  65. data/spec/lib/phony/vanity_spec.rb +30 -0
  66. data/spec/lib/phony_spec.rb +70 -0
  67. metadata +27 -17
@@ -1,6 +1,6 @@
1
1
  module Phony
2
2
 
3
- EMPTY_STRING = ''
3
+ EMPTY_STRING = '' unless defined?(EMPTY_STRING)
4
4
 
5
5
  # Handles determining the correct national code handler.
6
6
  #
@@ -66,7 +66,7 @@ module Phony
66
66
  country, cc, number = partial_split number
67
67
  country
68
68
  end
69
- number = country.normalize number
69
+ number = country.normalize number, cc: cc
70
70
  countrify! number, cc
71
71
  end
72
72
 
@@ -77,7 +77,7 @@ module Phony
77
77
  country, cc, national_number = partial_split number
78
78
 
79
79
  # Split the national number into ndc and local part.
80
- trunk, ndc, *local = country.split national_number
80
+ _, ndc, *local = country.split national_number
81
81
 
82
82
  [cc, ndc, *local]
83
83
  end
@@ -97,9 +97,20 @@ module Phony
97
97
 
98
98
  # False if it fails the basic check.
99
99
  #
100
- return false unless (4..15) === normalized.size
100
+ return false unless (4..16) === normalized.size # unless hints[:check_length] == false
101
101
 
102
102
  country, cc, rest = partial_split normalized
103
+
104
+ # Was a country calling code given?
105
+ #
106
+ if ccc = hints[:ccc]
107
+ cc, ndc, *local = split ccc
108
+
109
+ raise ArgumentError.new("The provided ccc option is too long and includes more than a cc ('#{cc}') and ndc ('#{ndc}'). It also includes '#{local.join}'.") unless local.size == 1 && local[0].empty?
110
+
111
+ hints[:cc] = cc
112
+ hints[:ndc] = ndc
113
+ end
103
114
 
104
115
  # Country code plausible?
105
116
  #
@@ -109,6 +120,8 @@ module Phony
109
120
  # Country specific tests.
110
121
  #
111
122
  country.plausible? rest, hints
123
+ rescue ArgumentError
124
+ raise
112
125
  rescue StandardError
113
126
  return false
114
127
  end
data/lib/phony/dsl.rb CHANGED
@@ -12,9 +12,9 @@ module Phony
12
12
  #
13
13
  # Phony.define.country ...
14
14
  #
15
- def self.define
15
+ def self.define(&block)
16
16
  dsl = DSL.new
17
- dsl.instance_eval(&Proc.new) if block_given?
17
+ dsl.instance_eval(&block) if block_given?
18
18
  dsl
19
19
  end
20
20
 
@@ -41,6 +41,8 @@ module Phony
41
41
  # country '27', # CC, followed by rules, for example fixed(2) >> ...
42
42
  #
43
43
  def country country_code, definition, options = {}
44
+ return unless Phony.config.load?(country_code)
45
+
44
46
  definition.with country_code, options
45
47
  Phony::CountryCodes.instance.add country_code, definition
46
48
  end
@@ -139,7 +141,7 @@ module Phony
139
141
  #
140
142
  ndcs = ndcs.first if Array === ndcs.first
141
143
 
142
- NationalSplitters::Variable.new options[:max_length], ndcs
144
+ NationalSplitters::Variable.new options[:max_length], ndcs.map(&:freeze)
143
145
  end
144
146
 
145
147
  # If you have a number of (possibly) variable length NDCs
@@ -62,6 +62,8 @@ module Phony
62
62
  #
63
63
  #
64
64
  def plausible? rest, hints = {}
65
+ return true if hints[:check_length] == false
66
+
65
67
  @length === rest.inject(0) { |total, part| total + part.size }
66
68
  end
67
69
 
@@ -26,7 +26,7 @@ module Phony
26
26
  #
27
27
  # Note: Some cases, like Italy, don't remove the relative zero.
28
28
  #
29
- def normalize national_number
29
+ def normalize national_number, options = {}
30
30
  national_number.gsub(/\A0+/, EMPTY_STRING)
31
31
  end
32
32
 
@@ -31,9 +31,7 @@ module Phony
31
31
  # since using nil is dangerous and breaks
32
32
  # abstraction)
33
33
  #
34
- # Note: Actually, it might stay in.
35
- #
36
- # TODO Flip nil/false?
34
+ # Note: Decided it stays in. When formatting, it's turned into nil.
37
35
  #
38
36
  def split national_number
39
37
  [nil, false, national_number]
@@ -6,8 +6,9 @@ module Phony
6
6
  # * code: The trunk code, e.g. 0.
7
7
  #
8
8
  # Options:
9
- # * normalize: Remove the trunk code when normalizing (only use if number scheme is defined unambiguously).
10
- # * split: Remove the trunk code when splitting (only use if number scheme is defined unambiguously).
9
+ # * normalize: [true (default), false] Remove the trunk code when normalizing (only use if number scheme is defined unambiguously).
10
+ # * split: [true, false (default)] Remove the trunk code when splitting (only use if number scheme is defined unambiguously).
11
+ # * format: [true (default), false] Add the trunk code when formatting (passing `false` will not add it).
11
12
  #
12
13
  def initialize code, options = {}
13
14
  @code = code
@@ -34,8 +35,8 @@ module Phony
34
35
 
35
36
  # Normalize normalizes the given national number.
36
37
  #
37
- def normalize national_number
38
- national_number.gsub! @trunk_code_replacement, EMPTY_STRING if @normalize
38
+ def normalize national_number, options = {}
39
+ national_number.gsub! @trunk_code_replacement, EMPTY_STRING if @normalize && options[:cc]
39
40
  return national_number
40
41
  end
41
42
 
data/lib/phony/vanity.rb CHANGED
@@ -20,7 +20,7 @@ module Phony
20
20
  end
21
21
 
22
22
  # Returns true if there is a character in the number
23
- # after the first four numbers.
23
+ # after the first three numbers.
24
24
  #
25
25
  @@vanity_regexp = /\A\d{3}[a-zA-Z]{6,12}\Z/
26
26
  def self.vanity? number
data/lib/phony.rb CHANGED
@@ -1,69 +1,75 @@
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/trunk_code', __FILE__
15
- require File.expand_path '../phony/country_codes', __FILE__
16
-
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/bangladesh', __FILE__
25
- require File.expand_path '../phony/countries/belarus', __FILE__
26
- require File.expand_path '../phony/countries/brazil', __FILE__
27
- require File.expand_path '../phony/countries/cambodia', __FILE__
28
- require File.expand_path '../phony/countries/croatia', __FILE__
29
- require File.expand_path '../phony/countries/china', __FILE__
30
- require File.expand_path '../phony/countries/georgia', __FILE__
31
- require File.expand_path '../phony/countries/germany', __FILE__
32
- require File.expand_path '../phony/countries/guinea', __FILE__
33
- require File.expand_path '../phony/countries/india', __FILE__
34
- require File.expand_path '../phony/countries/indonesia', __FILE__
35
- require File.expand_path '../phony/countries/ireland', __FILE__
36
- require File.expand_path '../phony/countries/italy', __FILE__
37
- require File.expand_path '../phony/countries/japan', __FILE__
38
- require File.expand_path '../phony/countries/kyrgyzstan', __FILE__
39
- require File.expand_path '../phony/countries/latvia', __FILE__
40
- require File.expand_path '../phony/countries/libya', __FILE__
41
- require File.expand_path '../phony/countries/malaysia', __FILE__
42
- require File.expand_path '../phony/countries/moldova', __FILE__
43
- require File.expand_path '../phony/countries/montenegro', __FILE__
44
- require File.expand_path '../phony/countries/myanmar', __FILE__
45
- require File.expand_path '../phony/countries/namibia', __FILE__
46
- require File.expand_path '../phony/countries/nepal', __FILE__
47
- require File.expand_path '../phony/countries/netherlands', __FILE__
48
- require File.expand_path '../phony/countries/pakistan', __FILE__
49
- require File.expand_path '../phony/countries/paraguay', __FILE__
50
- require File.expand_path '../phony/countries/russia_kazakhstan_abkhasia_south_ossetia', __FILE__
51
- require File.expand_path '../phony/countries/serbia', __FILE__
52
- require File.expand_path '../phony/countries/somalia', __FILE__
53
- require File.expand_path '../phony/countries/south_korea', __FILE__
54
- require File.expand_path '../phony/countries/sweden', __FILE__
55
- require File.expand_path '../phony/countries/taiwan', __FILE__
56
- require File.expand_path '../phony/countries/tajikistan', __FILE__
57
- require File.expand_path '../phony/countries/turkmenistan', __FILE__
58
- require File.expand_path '../phony/countries/vietnam', __FILE__
59
- require File.expand_path '../phony/countries/ukraine', __FILE__
60
- require File.expand_path '../phony/countries/united_kingdom', __FILE__
61
- require File.expand_path '../phony/countries/uruguay', __FILE__
62
- require File.expand_path '../phony/countries/zimbabwe', __FILE__
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__
63
69
 
64
70
  # All other countries.
65
71
  #
66
- require File.expand_path '../phony/countries', __FILE__
72
+ load File.expand_path '../phony/countries.rb', __FILE__
67
73
 
68
74
  # Phony is the main module and is generally used to process
69
75
  # E164 phone numbers directly.
@@ -75,11 +81,33 @@ module Phony
75
81
  # @example
76
82
  # Phony.normalize("Fnork!") # Raises a Phony::NormalizationError.
77
83
  #
78
- class NormalizationError < StandardError
84
+ class NormalizationError < ArgumentError
79
85
  def initialize
80
86
  super %Q{Phony could not normalize the given number. Is it a phone number?}
81
87
  end
82
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
83
111
 
84
112
  # Phony uses a single country codes instance.
85
113
  #
@@ -120,6 +148,7 @@ module Phony
120
148
  #
121
149
  def normalize phone_number, options = {}
122
150
  raise ArgumentError, "Phone number cannot be nil. Use e.g. number && Phony.normalize(number)." unless phone_number
151
+
123
152
  normalize! phone_number.dup, options
124
153
  end
125
154
  # A destructive version of {#normalize}.
@@ -161,7 +190,8 @@ module Phony
161
190
  #
162
191
  def split phone_number
163
192
  raise ArgumentError, "Phone number cannot be nil. Use e.g. number && Phony.split(number)." unless phone_number
164
- split! phone_number.dup
193
+
194
+ split! phone_number.dup, phone_number
165
195
  end
166
196
  # A destructive version of {#split}.
167
197
  #
@@ -177,8 +207,11 @@ module Phony
177
207
  # @example Split a NANP number.
178
208
  # Phony.split!("13015550100") # => ["1", "301", "555", "0100"]
179
209
  #
180
- def split! phone_number
210
+ def split! phone_number, error_number = nil
181
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)
182
215
  end
183
216
 
184
217
  # Formats a normalized E164 number according to a country's formatting scheme.
@@ -230,6 +263,8 @@ module Phony
230
263
  #
231
264
  def format! phone_number, options = {}
232
265
  @codes.format phone_number, options
266
+ rescue
267
+ raise FormattingError.new
233
268
  end
234
269
  alias formatted format
235
270
  alias formatted! format!
@@ -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