phone 0.9.9.1 → 0.9.9.3

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.
@@ -10,11 +10,11 @@ Or as a Rails plugin
10
10
  script/plugin install git://github.com/carr/phone.git
11
11
 
12
12
  == Initializing
13
- You can initialize a new phone object with the number, area code and country code.
13
+ You can initialize a new phone object with the number, area code, country code and extension number
14
14
 
15
15
  Phone.new('5125486', '91', '385')
16
16
  or
17
- Phone.new(:number => '5125486', :area_code => '91', :country_code => '385')
17
+ Phone.new(:number => '5125486', :area_code => '91', :country_code => '385', :extension => '143')
18
18
 
19
19
  == Parsing
20
20
  You can create a new phone object by parsing from a string. Phone does it's best to detect the country and area codes:
@@ -61,8 +61,9 @@ When given a string, it interpolates the string with the following fields:
61
61
  * %a - area_code (91)
62
62
  * %A - area_code with leading zero (091)
63
63
  * %n - number (5125486)
64
- * %n1 - first @@n1_length characters of number (configured through Phone.n1_length), default is 3 (512)
65
- * %n2 - last characters of number (5486)
64
+ * %f - first @@n1_length characters of number (configured through Phone.n1_length), default is 3 (512)
65
+ * %l - last characters of number (5486)
66
+ * %x - the extension number
66
67
 
67
68
  pn = Phone.parse('+385915125486')
68
69
  pn.to_s # => "+385915125486"
@@ -72,17 +73,35 @@ When given a string, it interpolates the string with the following fields:
72
73
  When given a symbol it is used as a lookup for the format in the <tt>Phone.named_formats</tt> hash.
73
74
  pn.format(:europe) # => "+385 (0) 91 512 5486"
74
75
  pn.format(:us) # => "(234) 123 4567"
76
+ pn.format(:default_with_extension) # => "+3851234567x143"
75
77
 
76
78
  You can add your own custom named formats like so:
77
79
  Phone.named_formats[:short] = '%A/%n1-%n2'
78
80
  pn.format(:short) # => 091/512-5486
79
81
 
80
82
  = TODO
81
- Parse testing for different countries. Currently tested on: US, South Africa, Croatia, Slovenia, Hungary, Serbia,
82
- Bosnia and Herzegovina, Germany, France.
83
-
83
+ Parse testing for different countries.
84
+
85
+ Currently tested on:
86
+ [AU] Australia
87
+ [BA] Bosnia and Herzegovina
88
+ [BE] Belgium
89
+ [DE] Germany
90
+ [FR] France
91
+ [GB] United Kingdom
92
+ [HR] Croatia
93
+ [HU] Hungary
94
+ [NL] Netherlands
95
+ [RS] Serbia
96
+ [SE] Sweden
97
+ [SI] Slovenia
98
+ [UA] Ukraine
99
+ [US] United States
100
+ [ZA] South Africa
101
+
84
102
  = Author
85
103
  Copyright © 2010 Tomislav Car, Infinum
86
104
 
87
- Modifications copyright © 2010 Todd Eichel for Fooala, Inc.
105
+ = Contributors
106
+ Don Morrison, Michael Squires, Todd Eichel (Fooala, Inc.), chipiga, Etienne Samson, Luke Randall
88
107
 
@@ -371,6 +371,7 @@
371
371
  :char_3_code: NL
372
372
  :name: Netherlands
373
373
  :international_dialing_prefix: "0"
374
+ :area_code: "6760|66|6|800|878|8[4578]|90[069]|1[035]|2[0346]|3[03568]|4[0356]|5[0358]|7[0-9]|11[134578]|16[124-8]|17[24]|18[0-467]|22[2-46-9]|25[125]|29[479]|31[3-8]|32[01]|34[1-8]|41[12368]|47[58]|48[15-8]|49[23579]|5[129][1-9]|54[134-8]|56[126]|57[0-3578]"
374
375
  "850":
375
376
  :country_code: "850"
376
377
  :national_dialing_prefix: "0"
@@ -413,6 +414,7 @@
413
414
  :char_3_code: BE
414
415
  :name: Belgium
415
416
  :international_dialing_prefix: "0"
417
+ :area_code: "800|90[0-9]|2|3|4|9|1[0-69]|5[0-9]|6[013-9]|7[01]|8[1-9]"
416
418
  "965":
417
419
  :country_code: "965"
418
420
  :national_dialing_prefix: None
@@ -487,9 +489,10 @@
487
489
  :country_code: "61"
488
490
  :national_dialing_prefix: "0"
489
491
  :char_2_code: "0"
490
- :char_3_code: CC
491
- :name: Cocos (Keeling) Islands
492
+ :char_3_code: AU
493
+ :name: Australia
492
494
  :international_dialing_prefix: "11"
495
+ :area_code: "[234578]"
493
496
  "880":
494
497
  :country_code: "880"
495
498
  :national_dialing_prefix: "0"
@@ -963,11 +966,12 @@
963
966
  :international_dialing_prefix: "0"
964
967
  "380":
965
968
  :country_code: "380"
966
- :national_dialing_prefix: "8"
967
- :char_2_code: "8"
969
+ :national_dialing_prefix: "0"
970
+ :char_2_code: "0"
968
971
  :char_3_code: UA
969
972
  :name: Ukraine
970
- :international_dialing_prefix: "810"
973
+ :international_dialing_prefix: "00"
974
+ :area_code: "[1-9][0-9]"
971
975
  "41":
972
976
  :country_code: "41"
973
977
  :national_dialing_prefix: "0"
@@ -1130,6 +1134,7 @@
1130
1134
  :char_3_code: GB
1131
1135
  :name: United Kingdom
1132
1136
  :international_dialing_prefix: "0"
1137
+ :area_code: "2[03489]|11[3-8]|1[2-69]1|1[2-9][0-9]{2}|70|7[0-9]{3}|[8|9][0-9]{2}|3[0-9]{2}"
1133
1138
  "242":
1134
1139
  :country_code: "242"
1135
1140
  :national_dialing_prefix: None
@@ -1187,6 +1192,7 @@
1187
1192
  :char_3_code: SE
1188
1193
  :name: Sweden
1189
1194
  :international_dialing_prefix: "0"
1195
+ :area_code: "900|1[013689]|2[0136]|3[1356]|4[0246]|54|6[03]|7[01236]|8|9[09]|1[2457][0-9]|2[2457-9][0-9]|3[0247-9][0-9]|4[1357-9][0-9]|5[0-35-9][0-9]|6[124-9][0-9]|74[0-9]|9[1-8][0-9]"
1190
1196
  "386":
1191
1197
  :country_code: "386"
1192
1198
  :national_dialing_prefix: "0"
@@ -1379,13 +1385,6 @@
1379
1385
  :char_3_code: HN
1380
1386
  :name: Honduras
1381
1387
  :international_dialing_prefix: "0"
1382
- "618":
1383
- :country_code: "618"
1384
- :national_dialing_prefix: "0"
1385
- :char_2_code: "0"
1386
- :char_3_code: CX
1387
- :name: Christmas Island
1388
- :international_dialing_prefix: "11"
1389
1388
  "250":
1390
1389
  :country_code: "250"
1391
1390
  :national_dialing_prefix: "0"
@@ -9,13 +9,13 @@
9
9
  # Phone.default_country_code
10
10
  # Phone.default_area_code
11
11
  #
12
- require 'active_support/core_ext' # for Class#cattr_accessor, String#present?
12
+ require File.join(File.dirname(__FILE__), 'support') unless defined? ActiveSupport
13
13
  require File.join(File.dirname(__FILE__), 'phone_country')
14
- class Phone
15
- NUMBER = '([^0][0-9]{1,7})$'
14
+ class Phone
15
+ NUMBER = '([0-9]{1,8})$'
16
16
  DEFAULT_AREA_CODE = '[2-9][0-8][0-9]' # USA
17
17
 
18
- attr_accessor :country_code, :area_code, :number
18
+ attr_accessor :country_code, :area_code, :number, :extension
19
19
 
20
20
  cattr_accessor :default_country_code
21
21
  cattr_accessor :default_area_code
@@ -28,6 +28,7 @@ class Phone
28
28
 
29
29
  @@named_formats = {
30
30
  :default => "+%c%a%n",
31
+ :default_with_extension => "+%c%a%nx%x",
31
32
  :europe => '+%c (0) %a %f %l',
32
33
  :us => "(%a) %f-%l"
33
34
  }
@@ -35,14 +36,15 @@ class Phone
35
36
  def initialize(*hash_or_args)
36
37
  if hash_or_args.first.is_a?(Hash)
37
38
  hash_or_args = hash_or_args.first
38
- keys = {:number => :number, :area_code => :area_code, :country_code => :country_code}
39
+ keys = {:number => :number, :area_code => :area_code, :country_code => :country_code, :extension => :extension}
39
40
  else
40
- keys = {:number => 0, :area_code => 1, :country_code => 2}
41
+ keys = {:number => 0, :area_code => 1, :country_code => 2, :extension => 3}
41
42
  end
42
43
 
43
44
  self.number = hash_or_args[ keys[:number] ]
44
45
  self.area_code = hash_or_args[ keys[:area_code] ] || self.default_area_code
45
46
  self.country_code = hash_or_args[ keys[:country_code] ] || self.default_country_code
47
+ self.extension = hash_or_args[ keys[:extension] ]
46
48
 
47
49
  raise "Must enter number" if self.number.blank?
48
50
  raise "Must enter area code or set default area code" if self.area_code.blank?
@@ -54,6 +56,7 @@ class Phone
54
56
  def self.parse(string, options={})
55
57
  if string.present?
56
58
  PhoneCountry.load
59
+ extension = extract_extension(string)
57
60
  string = normalize(string)
58
61
 
59
62
  options[:country_code] ||= self.default_country_code
@@ -62,6 +65,10 @@ class Phone
62
65
  parts = split_to_parts(string, options)
63
66
 
64
67
  pn = Phone.new(parts) if parts
68
+ if pn.present? and extension.present?
69
+ pn.extension = extension
70
+ end
71
+ return pn
65
72
  end
66
73
  end
67
74
 
@@ -125,7 +132,7 @@ class Phone
125
132
  area_code_regexp = country.area_code || DEFAULT_AREA_CODE
126
133
  {
127
134
  # 047451588, 013668734
128
- :short => Regexp.new('^0(' + area_code_regexp + ')' + NUMBER),
135
+ :short => Regexp.new('^0?(' + area_code_regexp + ')' + NUMBER),
129
136
  # 451588
130
137
  :really_short => Regexp.new('^' + NUMBER)
131
138
  }
@@ -138,7 +145,11 @@ class Phone
138
145
  arr << format if string_with_number =~ regexp
139
146
  end
140
147
 
141
- raise "Detected more than 1 format for #{string_with_number}" if arr.size > 1
148
+ # raise "Detected more than 1 format for #{string_with_number}" if arr.size > 1
149
+ if arr.length > 1
150
+ # puts %Q{detect_format: more than one format found - #{arr.inspect}}
151
+ return :really_short
152
+ end
142
153
  arr.first
143
154
  end
144
155
 
@@ -146,7 +157,29 @@ class Phone
146
157
  def self.normalize(string_with_number)
147
158
  string_with_number.gsub("(0)", "").gsub(/[^0-9+]/, '').gsub(/^00/, '+')
148
159
  end
149
-
160
+
161
+ # pull off anything that look like an extension
162
+ #TODO: refactor things so this doesn't change string as a side effect
163
+ #
164
+ def self.extract_extension(string)
165
+ return nil if string.nil?
166
+ if string.sub! /[ ]*(ext|ex|x|xt|#|:)+[^0-9]*\(*([-0-9]{1,})\)*#?$/i, ''
167
+ extension = $2
168
+ return extension
169
+ end
170
+ #
171
+ # We already returned any recognizable extension.
172
+ # However, we might still have extra junk to the right
173
+ # of the phone number proper, so just chop it off.
174
+ #
175
+ idx = string.rindex(/[0-9]/)
176
+ return nil if idx.nil?
177
+ return nil if idx == (string.length - 1) # at the end
178
+ string.slice!((idx+1)..-1) # chop it
179
+ return nil
180
+ end
181
+
182
+ # format area_code with trailing zero (e.g. 91 as 091)
150
183
  # format area_code with trailing zero (e.g. 91 as 091)
151
184
  def area_code_long
152
185
  "0" + area_code if area_code
@@ -171,8 +204,9 @@ class Phone
171
204
  # * %a - area_code (91)
172
205
  # * %A - area_code with leading zero (091)
173
206
  # * %n - number (5125486)
174
- # * %n1 - first @@n1_length characters of number (configured through Phone.n1_length), default is 3 (512)
175
- # * %n2 - last characters of number (5486)
207
+ # * %f - first @@n1_length characters of number (configured through Phone.n1_length), default is 3 (512)
208
+ # * %l - last characters of number (5486)
209
+ # * %x - entire extension
176
210
  #
177
211
  # if the method argument is a Symbol, it is used as a lookup key for a format String in Phone.named_formats
178
212
  # pn.format(:europe)
@@ -203,11 +237,13 @@ class Phone
203
237
  private
204
238
 
205
239
  def format_number(fmt)
206
- fmt.gsub("%c", country_code || "").
240
+ result = fmt.gsub("%c", country_code || "").
207
241
  gsub("%a", area_code || "").
208
242
  gsub("%A", area_code_long || "").
209
243
  gsub("%n", number || "").
210
244
  gsub("%f", number1 || "").
211
- gsub("%l", number2 || "")
245
+ gsub("%l", number2 || "").
246
+ gsub("%x", extension || "")
247
+ return result
212
248
  end
213
249
  end
@@ -1,5 +1,3 @@
1
- require 'active_support/core_ext' # for Class#cattr_accessor
2
-
3
1
  class PhoneCountry < Struct.new(:name, :country_code, :char_2_code, :area_code)
4
2
  cattr_accessor :all
5
3
 
@@ -0,0 +1,78 @@
1
+ require 'yaml'
2
+ # support methods to remove dependencies on ActiveSupport
3
+ class String
4
+ def present?
5
+ !blank?
6
+ end
7
+
8
+ def blank?
9
+ if respond_to?(:empty?) && respond_to?(:strip)
10
+ empty? or strip.empty?
11
+ elsif respond_to?(:empty?)
12
+ empty?
13
+ else
14
+ !self
15
+ end
16
+ end
17
+ end
18
+
19
+ class Hash
20
+ alias_method :blank?, :empty?
21
+
22
+ def present?
23
+ !blank?
24
+ end
25
+ end
26
+
27
+ class Object
28
+ def present?
29
+ self.class!=NilClass
30
+ end
31
+ end
32
+
33
+ class NilClass #:nodoc:
34
+ def blank?
35
+ true
36
+ end
37
+
38
+ def present?
39
+ false
40
+ end
41
+ end
42
+
43
+ module Accessorize
44
+ module ClassMethods
45
+ def cattr_accessor(*syms)
46
+ syms.flatten.each do |sym|
47
+ class_eval(<<-EOS, __FILE__, __LINE__)
48
+ unless defined? @@#{sym}
49
+ @@#{sym} = nil
50
+ end
51
+
52
+ def self.#{sym}
53
+ @@#{sym}
54
+ end
55
+
56
+ def #{sym}=(value)
57
+ @@#{sym} = value
58
+ end
59
+
60
+ def self.#{sym}=(value)
61
+ @@#{sym} = value
62
+ end
63
+
64
+ def #{sym}
65
+ @@#{sym}
66
+ end
67
+ EOS
68
+ end
69
+ end
70
+ end
71
+
72
+
73
+ def self.included(receiver)
74
+ receiver.extend ClassMethods
75
+ end
76
+ end
77
+
78
+ Object.send(:include, Accessorize)
@@ -0,0 +1,49 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ # 0x 5551 reserved for fictitious use. (not including x=3)
4
+ # 0x 7010 reserved for fictitious use.
5
+
6
+ ## Australia
7
+ class AUTest < Test::Unit::TestCase
8
+
9
+ # 00 Emergency and International access
10
+ # 01 Alternate phone services
11
+ # 014 Satellite phone services
12
+ # 016 Paging [+3D or +6D]
13
+ # 018 Analogue (AMPS) mobile phone - few numbers still in use [+6D]
14
+ # 0198 Data networks [+2D or +6D] - e.g. 0198 379 000 is the Dial-Up POP number for iiNet
15
+
16
+ # 02 Central East region (NSW, ACT)
17
+ def test_central_east
18
+ parse_test('+61 2 5551 1234', '61', '2', '55511234')
19
+ end
20
+
21
+ # 03 South-east region (VIC, TAS)
22
+ def test_south_east
23
+ parse_test('+61 3 5551 1234', '61', '3', '55511234')
24
+ end
25
+
26
+ # 04 Mobile services (Digital - GSM, CDMA, 3G)
27
+ def test_mobile
28
+ parse_test('+61 4 5551 1234', '61', '4', '55511234')
29
+ end
30
+
31
+ # 05 Universal/Personal numberings (uncommon)
32
+ def test_personal
33
+ parse_test('+61 5 5551 1234', '61', '5', '55511234')
34
+ end
35
+
36
+ # 07 North-east region (QLD)
37
+ def test_north_east
38
+ parse_test('+61 7 5551 1234', '61', '7', '55511234')
39
+ end
40
+
41
+ # 08 Central and West region (SA, NT, WA)
42
+ def test_central
43
+ parse_test('+61 8 5551 1234', '61', '8', '55511234')
44
+ end
45
+
46
+ # (Geographical region boundaries do not exactly follow state borders.)
47
+ # 1 Non-geographic numbers
48
+
49
+ end
@@ -0,0 +1,10 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ ## Bosnia and Herzegovina
4
+ class BATest < Test::Unit::TestCase
5
+
6
+ def test_local
7
+ parse_test('+387 33 25 02 33', '387', '33', '250233')
8
+ end
9
+
10
+ end
@@ -0,0 +1,116 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ ## Belgium
4
+ class BETest < Test::Unit::TestCase
5
+
6
+ ## single digit
7
+ # 02: Brussels (Bruxelles/Brussel)
8
+ def test_brussels
9
+ parse_test('+32 2 1234567', '32', '2', '1234567')
10
+ end
11
+ # 03: Antwerpen (Antwerp), Sint-Niklaas
12
+ def test_antwerpen
13
+ parse_test('+32 3 1234567', '32', '3', '1234567')
14
+ end
15
+ # 04: Liège (Luik), Voeren (Fourons)
16
+ def test_liege
17
+ parse_test('+32 4 1234567', '32', '4', '1234567')
18
+ end
19
+ # 09: Gent (Ghent/Gand)
20
+ def test_gent
21
+ parse_test('+32 9 1234567', '32', '9', '1234567')
22
+ end
23
+
24
+ ## two digit
25
+ # 010: Wavre (Waver)
26
+ def test_wavre
27
+ parse_test('+32 10 123456', '32', '10', '123456')
28
+ end
29
+ # 011: Hasselt
30
+ def test_hasselt
31
+ parse_test('+32 11 123456', '32', '11', '123456')
32
+ end
33
+ # 012: Tongeren (Tongres)
34
+ def test_tongeren
35
+ parse_test('+32 12 123456', '32', '12', '123456')
36
+ end
37
+ # 013: Diest
38
+ def test_diest
39
+ parse_test('+32 13 123456', '32', '13', '123456')
40
+ end
41
+ # 014: Herentals, Turnhout
42
+ # 015: Mechelen (Malines)
43
+ # 016: Leuven (Louvain), Tienen (Tirlemont)
44
+ # 019: Waremme (Borgworm)
45
+ def test_waremme
46
+ parse_test('+32 19 123456', '32', '19', '123456')
47
+ end
48
+
49
+ # 050: Brugge (Bruges), Zeebrugge
50
+ def test_brugge
51
+ parse_test('+32 50 123456', '32', '50', '123456')
52
+ end
53
+ # 051: Roeselare (Roulers)
54
+ def test_roeselare
55
+ parse_test('+32 51 123456', '32', '51', '123456')
56
+ end
57
+ # 052: Dendermonde (Termonde)
58
+ # 053: Aalst (Alost)
59
+ # 054: Ninove
60
+ # 055: Ronse (Renaix)
61
+ # 056: Kortrijk (Courtrai), Comines-Warneton, Mouscron (Moeskroen)
62
+ # 057: Ieper (Ypres)
63
+ # 058: Veurne (Furnes)
64
+ # 059: Oostende (Ostend)
65
+ def test_oostende
66
+ parse_test('+32 59 123456', '32', '59', '123456')
67
+ end
68
+
69
+ # 060: Chimay
70
+ def test_chimay
71
+ parse_test('+32 60 123456', '32', '60', '123456')
72
+ end
73
+ # 061: Bastogne, Libramont-Chevigny
74
+ # 063: Arlon (Aarlen)
75
+ # 064: La Louviere
76
+ # 065: Mons (Bergen)
77
+ # 067: Nivelles (Nijvel)
78
+ def test_nivelles
79
+ parse_test('+32 67 123456', '32', '67', '123456')
80
+ end
81
+ # 068: Ath (Aat)
82
+ # 069: Tournai (Doornik)
83
+
84
+ # 070: Specialty Numbers (i.e. bus information or bank information)
85
+ def test_specialty
86
+ parse_test('+32 70 123456', '32', '70', '123456')
87
+ end
88
+ # 071: Charleroi
89
+
90
+ # 081: Namur (Namen)
91
+ def test_namur
92
+ parse_test('+32 81 123456', '32', '81', '123456')
93
+ end
94
+ # 082: Dinant
95
+ # 083: Ciney
96
+ # 084: Jemelle, Marche-en-Famenne
97
+ # 085: Huy
98
+ # 086: Durbuy
99
+ # 087: Verviers
100
+ # 089: Genk
101
+
102
+ # 0800: toll free service
103
+ def test_toll_free
104
+ parse_test('+32 800 12345', '32', '800', '12345')
105
+ end
106
+
107
+ # 090x: Premium numbers (0900, 0901, 0902, 0903, 0904, 0905, 0906, 0907, 0908, 0909)
108
+ def test_premium_900
109
+ parse_test('+32 900 12345', '32', '900', '12345')
110
+ end
111
+
112
+ def test_premium_901
113
+ parse_test('+32 901 12345', '32', '901', '12345')
114
+ end
115
+
116
+ end