worldwide 0.10.2 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -1
- data/CHANGELOG.md +40 -23
- data/Gemfile.lock +15 -13
- data/data/cldr/locales/ar/subdivisions.yml +12 -12
- data/data/cldr/locales/bn/subdivisions.yml +12 -12
- data/data/cldr/locales/ca/subdivisions.yml +14 -14
- data/data/cldr/locales/ceb/subdivisions.yml +13 -13
- data/data/cldr/locales/cs/subdivisions.yml +2 -2
- data/data/cldr/locales/da/subdivisions.yml +12 -12
- data/data/cldr/locales/de/subdivisions.yml +12 -12
- data/data/cldr/locales/el/subdivisions.yml +14 -14
- data/data/cldr/locales/es/subdivisions.yml +4 -4
- data/data/cldr/locales/eu/subdivisions.yml +14 -14
- data/data/cldr/locales/fi/subdivisions.yml +11 -11
- data/data/cldr/locales/fr/subdivisions.yml +13 -13
- data/data/cldr/locales/gu/subdivisions.yml +12 -12
- data/data/cldr/locales/hi/subdivisions.yml +3 -3
- data/data/cldr/locales/hu/subdivisions.yml +14 -14
- data/data/cldr/locales/id/subdivisions.yml +14 -14
- data/data/cldr/locales/it/subdivisions.yml +13 -13
- data/data/cldr/locales/ja/subdivisions.yml +14 -14
- data/data/cldr/locales/kn/subdivisions.yml +12 -12
- data/data/cldr/locales/ko/subdivisions.yml +14 -14
- data/data/cldr/locales/lt/subdivisions.yml +14 -14
- data/data/cldr/locales/lv/subdivisions.yml +12 -12
- data/data/cldr/locales/mr/subdivisions.yml +12 -12
- data/data/cldr/locales/ms/subdivisions.yml +12 -12
- data/data/cldr/locales/no/subdivisions.yml +8 -8
- data/data/cldr/locales/ro/subdivisions.yml +14 -14
- data/data/cldr/locales/ru/subdivisions.yml +1 -1
- data/data/cldr/locales/si/subdivisions.yml +12 -12
- data/data/cldr/locales/sv/subdivisions.yml +7 -7
- data/data/cldr/locales/ta/subdivisions.yml +12 -12
- data/data/cldr/locales/te/subdivisions.yml +12 -12
- data/data/cldr/locales/tr/subdivisions.yml +11 -11
- data/data/cldr/locales/uk/subdivisions.yml +10 -10
- data/data/cldr/locales/ur/subdivisions.yml +14 -14
- data/data/cldr/locales/vi/subdivisions.yml +12 -12
- data/data/cldr/locales/zh/subdivisions.yml +14 -14
- data/db/data/regions/AE/bg-BG.yml +1 -0
- data/db/data/regions/AE/cs.yml +1 -0
- data/db/data/regions/AE/da.yml +1 -0
- data/db/data/regions/AE/de.yml +1 -0
- data/db/data/regions/AE/el.yml +1 -0
- data/db/data/regions/AE/en.yml +1 -0
- data/db/data/regions/AE/es.yml +1 -0
- data/db/data/regions/AE/fi.yml +1 -0
- data/db/data/regions/AE/fr.yml +1 -0
- data/db/data/regions/AE/hi.yml +1 -0
- data/db/data/regions/AE/hr-HR.yml +1 -0
- data/db/data/regions/AE/hu.yml +1 -0
- data/db/data/regions/AE/id.yml +1 -0
- data/db/data/regions/AE/it.yml +1 -0
- data/db/data/regions/AE/ja.yml +1 -0
- data/db/data/regions/AE/ko.yml +1 -0
- data/db/data/regions/AE/lt-LT.yml +1 -0
- data/db/data/regions/AE/nb.yml +1 -0
- data/db/data/regions/AE/nl.yml +1 -0
- data/db/data/regions/AE/pl.yml +1 -0
- data/db/data/regions/AE/pt-BR.yml +1 -0
- data/db/data/regions/AE/pt-PT.yml +1 -0
- data/db/data/regions/AE/ro-RO.yml +1 -0
- data/db/data/regions/AE/ru.yml +1 -0
- data/db/data/regions/AE/sk-SK.yml +1 -0
- data/db/data/regions/AE/sl-SI.yml +1 -0
- data/db/data/regions/AE/sv.yml +1 -0
- data/db/data/regions/AE/th.yml +1 -0
- data/db/data/regions/AE/tr.yml +1 -0
- data/db/data/regions/AE/vi.yml +1 -0
- data/db/data/regions/AE/zh-CN.yml +1 -0
- data/db/data/regions/AE/zh-TW.yml +1 -0
- data/db/data/regions/CA/bg-BG.yml +1 -0
- data/db/data/regions/CA/cs.yml +1 -0
- data/db/data/regions/CA/da.yml +1 -0
- data/db/data/regions/CA/de.yml +1 -0
- data/db/data/regions/CA/el.yml +1 -0
- data/db/data/regions/CA/en.yml +2 -0
- data/db/data/regions/CA/es.yml +1 -0
- data/db/data/regions/CA/fi.yml +1 -0
- data/db/data/regions/CA/fr.yml +1 -0
- data/db/data/regions/CA/hi.yml +1 -0
- data/db/data/regions/CA/hr-HR.yml +1 -0
- data/db/data/regions/CA/hu.yml +1 -0
- data/db/data/regions/CA/id.yml +1 -0
- data/db/data/regions/CA/it.yml +1 -0
- data/db/data/regions/CA/ja.yml +1 -0
- data/db/data/regions/CA/ko.yml +1 -0
- data/db/data/regions/CA/lt-LT.yml +1 -0
- data/db/data/regions/CA/ms.yml +1 -0
- data/db/data/regions/CA/nb.yml +1 -0
- data/db/data/regions/CA/nl.yml +1 -0
- data/db/data/regions/CA/pl.yml +1 -0
- data/db/data/regions/CA/pt-BR.yml +1 -0
- data/db/data/regions/CA/pt-PT.yml +1 -0
- data/db/data/regions/CA/ro-RO.yml +2 -0
- data/db/data/regions/CA/ru.yml +1 -0
- data/db/data/regions/CA/sk-SK.yml +1 -0
- data/db/data/regions/CA/sl-SI.yml +1 -0
- data/db/data/regions/CA/sv.yml +1 -0
- data/db/data/regions/CA/th.yml +1 -0
- data/db/data/regions/CA/tr.yml +1 -0
- data/db/data/regions/CA/vi.yml +1 -0
- data/db/data/regions/CA/zh-CN.yml +1 -0
- data/db/data/regions/CA/zh-TW.yml +1 -0
- data/db/data/regions/GB.yml +1 -1
- data/db/data/regions/JP/ja.yml +1 -1
- data/db/data/regions/US/bg-BG.yml +2 -0
- data/db/data/regions/US/cs.yml +2 -0
- data/db/data/regions/US/da.yml +2 -0
- data/db/data/regions/US/de.yml +2 -0
- data/db/data/regions/US/el.yml +2 -0
- data/db/data/regions/US/en.yml +3 -0
- data/db/data/regions/US/es.yml +2 -0
- data/db/data/regions/US/fi.yml +2 -0
- data/db/data/regions/US/fr.yml +2 -0
- data/db/data/regions/US/hi.yml +2 -0
- data/db/data/regions/US/hr-HR.yml +2 -0
- data/db/data/regions/US/hu.yml +2 -0
- data/db/data/regions/US/id.yml +2 -0
- data/db/data/regions/US/it.yml +2 -0
- data/db/data/regions/US/ja.yml +2 -0
- data/db/data/regions/US/ko.yml +2 -0
- data/db/data/regions/US/lt-LT.yml +2 -0
- data/db/data/regions/US/ms.yml +2 -0
- data/db/data/regions/US/nb.yml +2 -0
- data/db/data/regions/US/nl.yml +2 -0
- data/db/data/regions/US/pl.yml +2 -0
- data/db/data/regions/US/pt-BR.yml +2 -0
- data/db/data/regions/US/pt-PT.yml +2 -0
- data/db/data/regions/US/ro-RO.yml +3 -0
- data/db/data/regions/US/ru.yml +2 -0
- data/db/data/regions/US/sk-SK.yml +2 -0
- data/db/data/regions/US/sl-SI.yml +2 -0
- data/db/data/regions/US/sv.yml +2 -0
- data/db/data/regions/US/th.yml +2 -0
- data/db/data/regions/US/tr.yml +2 -0
- data/db/data/regions/US/vi.yml +2 -0
- data/db/data/regions/US/zh-CN.yml +2 -0
- data/db/data/regions/US/zh-TW.yml +2 -0
- data/db/data/regions/_default/bg-BG.yml +0 -2
- data/db/data/regions/_default/cs.yml +0 -2
- data/db/data/regions/_default/da.yml +0 -2
- data/db/data/regions/_default/de.yml +0 -2
- data/db/data/regions/_default/el.yml +0 -2
- data/db/data/regions/_default/en.yml +0 -1
- data/db/data/regions/_default/es.yml +0 -2
- data/db/data/regions/_default/fi.yml +0 -2
- data/db/data/regions/_default/fr.yml +0 -2
- data/db/data/regions/_default/hi.yml +0 -2
- data/db/data/regions/_default/hr-HR.yml +0 -2
- data/db/data/regions/_default/hu.yml +0 -2
- data/db/data/regions/_default/id.yml +0 -2
- data/db/data/regions/_default/it.yml +0 -2
- data/db/data/regions/_default/ja.yml +0 -1
- data/db/data/regions/_default/ko.yml +0 -1
- data/db/data/regions/_default/lt-LT.yml +0 -2
- data/db/data/regions/_default/ms.yml +0 -1
- data/db/data/regions/_default/nb.yml +0 -2
- data/db/data/regions/_default/nl.yml +0 -2
- data/db/data/regions/_default/pl.yml +0 -2
- data/db/data/regions/_default/pt-BR.yml +0 -2
- data/db/data/regions/_default/pt-PT.yml +0 -2
- data/db/data/regions/_default/ro-RO.yml +0 -2
- data/db/data/regions/_default/ru.yml +0 -2
- data/db/data/regions/_default/sk-SK.yml +0 -2
- data/db/data/regions/_default/sl-SI.yml +0 -2
- data/db/data/regions/_default/sv.yml +0 -2
- data/db/data/regions/_default/th.yml +0 -1
- data/db/data/regions/_default/tr.yml +0 -2
- data/db/data/regions/_default/vi.yml +0 -2
- data/db/data/regions/_default/zh-CN.yml +0 -1
- data/db/data/regions/_default/zh-TW.yml +0 -1
- data/db/extant_outcodes.yml +3134 -0
- data/lib/worldwide/address.rb +1 -1
- data/lib/worldwide/address_validator.rb +1 -1
- data/lib/worldwide/currencies.rb +1 -1
- data/lib/worldwide/currency.rb +3 -7
- data/lib/worldwide/extant_outcodes.rb +32 -0
- data/lib/worldwide/locale.rb +1 -1
- data/lib/worldwide/numbers.rb +2 -2
- data/lib/worldwide/phone.rb +5 -0
- data/lib/worldwide/region.rb +8 -3
- data/lib/worldwide/regions_loader.rb +2 -2
- data/lib/worldwide/version.rb +1 -1
- data/lib/worldwide/zip.rb +118 -39
- data/lib/worldwide.rb +1 -0
- metadata +5 -3
data/lib/worldwide/address.rb
CHANGED
@@ -300,7 +300,7 @@ module Worldwide
|
|
300
300
|
end
|
301
301
|
|
302
302
|
def normalize_city
|
303
|
-
Worldwide.region(code: @country_code)&.
|
303
|
+
Worldwide.region(code: @country_code)&.autofill_city || @city
|
304
304
|
end
|
305
305
|
|
306
306
|
def normalize_country_code(autocorrect_level:)
|
@@ -73,7 +73,7 @@ module Worldwide
|
|
73
73
|
|
74
74
|
return [] if country.nil?
|
75
75
|
return [] if country.zones.nil?
|
76
|
-
return [] if country.zones.
|
76
|
+
return [] if country.zones.none?(&:province?)
|
77
77
|
return [] if country.hide_provinces_from_addresses
|
78
78
|
|
79
79
|
if Util.blank?(address.province_code)
|
data/lib/worldwide/currencies.rb
CHANGED
data/lib/worldwide/currency.rb
CHANGED
@@ -12,15 +12,11 @@ module Worldwide
|
|
12
12
|
|
13
13
|
class << self
|
14
14
|
def digits_and_rounding
|
15
|
-
@digits_and_rounding ||= YAML.
|
16
|
-
File.read(File.join(Worldwide::Paths::OTHER_DATA_ROOT, "currency", "digits.yml")),
|
17
|
-
).freeze
|
15
|
+
@digits_and_rounding ||= YAML.safe_load_file(File.join(Worldwide::Paths::OTHER_DATA_ROOT, "currency", "digits.yml")).freeze
|
18
16
|
end
|
19
17
|
|
20
18
|
def minor_symbols
|
21
|
-
@minor_symbols ||= YAML.
|
22
|
-
File.read(File.join(Worldwide::Paths::OTHER_DATA_ROOT, "currency", "minor_symbols.yml")),
|
23
|
-
).freeze
|
19
|
+
@minor_symbols ||= YAML.safe_load_file(File.join(Worldwide::Paths::OTHER_DATA_ROOT, "currency", "minor_symbols.yml")).freeze
|
24
20
|
end
|
25
21
|
end
|
26
22
|
|
@@ -170,7 +166,7 @@ module Worldwide
|
|
170
166
|
|
171
167
|
if prefix?(locale)
|
172
168
|
if formatted.include?("-")
|
173
|
-
"-#{symbol}#{space}#{formatted.sub(
|
169
|
+
"-#{symbol}#{space}#{formatted.sub("-", "")}"
|
174
170
|
else
|
175
171
|
"#{symbol}#{space}#{formatted}"
|
176
172
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "forwardable"
|
4
|
+
require "singleton"
|
5
|
+
require "yaml"
|
6
|
+
|
7
|
+
module Worldwide
|
8
|
+
class ExtantOutcodes
|
9
|
+
include Singleton
|
10
|
+
|
11
|
+
class << self
|
12
|
+
extend Forwardable
|
13
|
+
def_delegators :instance, :for_country
|
14
|
+
end
|
15
|
+
|
16
|
+
def for_country(code:)
|
17
|
+
extant[code.to_s.downcase]
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@extant = nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def extant
|
27
|
+
@extant ||= YAML.safe_load_file("#{::Worldwide::Paths::GEM_ROOT}/db/extant_outcodes.yml").dig("extant_outcodes")&.map do |key, value|
|
28
|
+
[key, value.to_set]
|
29
|
+
end&.to_h || {}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/worldwide/locale.rb
CHANGED
@@ -155,7 +155,7 @@ module Worldwide
|
|
155
155
|
return if parts.size <= 1
|
156
156
|
|
157
157
|
region_code = parts.last
|
158
|
-
return if
|
158
|
+
return if Util.blank?(region_code)
|
159
159
|
|
160
160
|
region = Worldwide::Cldr.t(region_code, scope: :territories, default: nil)
|
161
161
|
region = region.nil? ? region_code : Worldwide::Cldr::ContextTransforms.transform(region, :territory, :start_of_sentence)
|
data/lib/worldwide/numbers.rb
CHANGED
@@ -92,10 +92,10 @@ module Worldwide
|
|
92
92
|
|
93
93
|
result = number.reverse.scan(/.{1,4}/).zip(JAPAN_MYRIAD_UNITS).map do |segment, unit|
|
94
94
|
segment.gsub!(/0*$/, "")
|
95
|
-
|
95
|
+
Util.blank?(segment) ? "" : (unit + segment)
|
96
96
|
end.join.reverse
|
97
97
|
|
98
|
-
result = "0" if
|
98
|
+
result = "0" if Util.blank?(result)
|
99
99
|
result = "#{result}#{decimal_marker}#{decimal}" if decimal
|
100
100
|
|
101
101
|
result
|
data/lib/worldwide/phone.rb
CHANGED
@@ -48,6 +48,11 @@ module Worldwide
|
|
48
48
|
@parsed_number.valid?
|
49
49
|
end
|
50
50
|
|
51
|
+
# Returns the country prefix for the phone number
|
52
|
+
def country_prefix
|
53
|
+
@parsed_number.country_code
|
54
|
+
end
|
55
|
+
|
51
56
|
private
|
52
57
|
|
53
58
|
# For various reasons, Worldwide considers these territories to be zones inside the USA
|
data/lib/worldwide/region.rb
CHANGED
@@ -291,9 +291,14 @@ module Worldwide
|
|
291
291
|
zip_example if @zip_autofill_enabled
|
292
292
|
end
|
293
293
|
|
294
|
+
# The value with which to autofill the city, if this region has a default city; otherwise, nil.
|
295
|
+
def autofill_city(locale: I18n.locale)
|
296
|
+
field(key: :city).autofill(locale: locale)
|
297
|
+
end
|
298
|
+
|
294
299
|
# Does this region require cities to be specified?
|
295
300
|
def city_required?
|
296
|
-
|
301
|
+
autofill_city(locale: :en).nil?
|
297
302
|
end
|
298
303
|
|
299
304
|
# Is this Region a continent?
|
@@ -386,7 +391,7 @@ module Worldwide
|
|
386
391
|
# If the Region has an autofill zip, return the value that will be autofilled
|
387
392
|
# Otherwise, return nil
|
388
393
|
def zip_autofill
|
389
|
-
|
394
|
+
zip_example if zip_autofill_enabled
|
390
395
|
end
|
391
396
|
|
392
397
|
# is a postal code required for this region?
|
@@ -511,7 +516,7 @@ module Worldwide
|
|
511
516
|
return iso_code if iso_code.nil? || iso_code.length < 3
|
512
517
|
|
513
518
|
country_code, subdivision_code = iso_code.split("-")
|
514
|
-
|
519
|
+
subdivision_code if country_code.casecmp(associated_country.iso_code).zero?
|
515
520
|
end
|
516
521
|
|
517
522
|
def valid_normalized_zip?(normalized, province_code: nil, partial_match: false)
|
@@ -199,7 +199,7 @@ module Worldwide
|
|
199
199
|
|
200
200
|
def country_codes
|
201
201
|
@country_codes ||=
|
202
|
-
YAML.
|
202
|
+
YAML.safe_load_file("#{Worldwide::Paths::DB_DATA_ROOT}/country_codes.yml")["country_codes"]
|
203
203
|
end
|
204
204
|
|
205
205
|
def find_region(code:)
|
@@ -212,7 +212,7 @@ module Worldwide
|
|
212
212
|
end
|
213
213
|
|
214
214
|
def load_territory(filename)
|
215
|
-
spec = YAML.
|
215
|
+
spec = YAML.safe_load_file(filename)
|
216
216
|
code = spec["code"]
|
217
217
|
|
218
218
|
loaded_regions = []
|
data/lib/worldwide/version.rb
CHANGED
data/lib/worldwide/zip.rb
CHANGED
@@ -107,40 +107,38 @@ module Worldwide
|
|
107
107
|
zip = strip_extraneous_characters(zip: zip, country_code: country_code)
|
108
108
|
end
|
109
109
|
|
110
|
-
|
111
|
-
|
110
|
+
return normalize_for_gb(zip: zip) if gb_style?(country_code: country.iso_code)
|
111
|
+
|
112
|
+
# Remove both normal-width and double-width spaces
|
113
|
+
zip.delete!(" ")
|
114
|
+
zip = replace_letters_and_numbers(country_code: country.iso_code, zip: zip)
|
115
|
+
|
116
|
+
result = if "BD" == country.iso_code
|
117
|
+
normalize_for_bd(zip: zip)
|
118
|
+
elsif "FO" == country.iso_code
|
119
|
+
normalize_for_fo(zip: zip)
|
120
|
+
elsif "GH" == country.iso_code
|
121
|
+
normalize_for_gh(zip: zip)
|
122
|
+
elsif "HT" == country.iso_code
|
123
|
+
normalize_for_ht(zip: zip)
|
124
|
+
elsif "LK" == country.iso_code
|
125
|
+
normalize_for_lk(zip: zip)
|
126
|
+
elsif "MD" == country.iso_code
|
127
|
+
normalize_for_md(zip: zip)
|
128
|
+
elsif "MG" == country.iso_code
|
129
|
+
normalize_for_mg(zip: zip)
|
130
|
+
elsif "NG" == country.iso_code
|
131
|
+
normalize_for_ng(zip: zip)
|
132
|
+
elsif "SG" == country.iso_code
|
133
|
+
normalize_for_sg(zip: zip)
|
134
|
+
elsif "MA" == country.iso_code
|
135
|
+
normalize_for_ma(zip: zip)
|
136
|
+
elsif "XK" == country.iso_code
|
137
|
+
normalize_for_xk(zip: zip)
|
138
|
+
elsif "BR" == country.iso_code || "JP" == country.iso_code
|
139
|
+
insert_spaces_and_hyphens_for_partial_code(country_code: country.iso_code, zip: zip)
|
112
140
|
else
|
113
|
-
|
114
|
-
zip.delete!(" ")
|
115
|
-
zip = replace_letters_and_numbers(country_code: country.iso_code, zip: zip)
|
116
|
-
|
117
|
-
if "BD" == country.iso_code
|
118
|
-
normalize_for_bd(zip: zip)
|
119
|
-
elsif "FO" == country.iso_code
|
120
|
-
normalize_for_fo(zip: zip)
|
121
|
-
elsif "GH" == country.iso_code
|
122
|
-
normalize_for_gh(zip: zip)
|
123
|
-
elsif "HT" == country.iso_code
|
124
|
-
normalize_for_ht(zip: zip)
|
125
|
-
elsif "LK" == country.iso_code
|
126
|
-
normalize_for_lk(zip: zip)
|
127
|
-
elsif "MD" == country.iso_code
|
128
|
-
normalize_for_md(zip: zip)
|
129
|
-
elsif "MG" == country.iso_code
|
130
|
-
normalize_for_mg(zip: zip)
|
131
|
-
elsif "NG" == country.iso_code
|
132
|
-
normalize_for_ng(zip: zip)
|
133
|
-
elsif "SG" == country.iso_code
|
134
|
-
normalize_for_sg(zip: zip)
|
135
|
-
elsif "MA" == country.iso_code
|
136
|
-
normalize_for_ma(zip: zip)
|
137
|
-
elsif "XK" == country.iso_code
|
138
|
-
normalize_for_xk(zip: zip)
|
139
|
-
elsif "BR" == country.iso_code || "JP" == country.iso_code
|
140
|
-
insert_spaces_and_hyphens_for_partial_code(country_code: country.iso_code, zip: zip)
|
141
|
-
else
|
142
|
-
insert_spaces_and_hyphens(country_code: country.iso_code, zip: zip)
|
143
|
-
end
|
141
|
+
insert_spaces_and_hyphens(country_code: country.iso_code, zip: zip)
|
144
142
|
end
|
145
143
|
|
146
144
|
if country.send(:valid_normalized_zip?, result)
|
@@ -161,7 +159,26 @@ module Worldwide
|
|
161
159
|
|
162
160
|
return zip unless @split_code_countries.include?(country_code.to_s.upcase)
|
163
161
|
|
164
|
-
normalize(country_code: country_code, zip: zip)
|
162
|
+
normalized_input = normalize(country_code: country_code, zip: zip).upcase
|
163
|
+
normalized_country_code = country_code.to_s.upcase
|
164
|
+
|
165
|
+
if Worldwide.region(code: country_code).valid_zip?(normalized_input)
|
166
|
+
# We successfully normalized the postcode, so we can split on the space to determine the outcode
|
167
|
+
normalized_input&.split(" ")&.first
|
168
|
+
else
|
169
|
+
# We have either an invalid or an incomplete postcode. Let's try some fancy heuristics
|
170
|
+
case country_code.to_s.upcase
|
171
|
+
when "CA", "IE"
|
172
|
+
# the FSA / routing code is the first 3 characters
|
173
|
+
normalized_input[0..2]
|
174
|
+
when "GB", "GG", "IM", "JE"
|
175
|
+
gb_style_outcode(country_code: normalized_country_code, input: normalized_input)
|
176
|
+
when "GI"
|
177
|
+
"GX11"
|
178
|
+
else
|
179
|
+
normalized_input
|
180
|
+
end
|
181
|
+
end
|
165
182
|
end
|
166
183
|
|
167
184
|
def strip_optional_country_prefix(country_code:, zip:)
|
@@ -195,6 +212,55 @@ module Worldwide
|
|
195
212
|
end
|
196
213
|
end
|
197
214
|
|
215
|
+
def gb_style_outcode(country_code:, input:)
|
216
|
+
normalized = input
|
217
|
+
|
218
|
+
m = /^([A-Z]{1,2})/.match(normalized)
|
219
|
+
return normalized if m.nil?
|
220
|
+
|
221
|
+
area = m[1]
|
222
|
+
return normalized if area.nil?
|
223
|
+
|
224
|
+
# Let's get the first, second and third characters following the area
|
225
|
+
first = normalized[area.length]
|
226
|
+
second = normalized[area.length + 1]
|
227
|
+
third = normalized[area.length + 2]
|
228
|
+
|
229
|
+
candidate = case area
|
230
|
+
when "E", "EC", "N", "NW", "SE", "SW", "W", "WC"
|
231
|
+
# These London districts may include a single-letter suffix as part of the district
|
232
|
+
# In all such cases, the district is one digit + one letter
|
233
|
+
|
234
|
+
if /[A-Z]/.match?(second)
|
235
|
+
# This must be a district suffix, so disctrict consists of first + second
|
236
|
+
"#{area}#{first}#{second}".strip
|
237
|
+
elsif /[A-Z]/.match?(third)
|
238
|
+
# Because third is a letter, second must be the sector, and the district must be a single digit
|
239
|
+
"#{area}#{first}".strip
|
240
|
+
else
|
241
|
+
# Otherwise, we'll assume that we've got a two-digit district
|
242
|
+
"#{area}#{first}#{second}".strip
|
243
|
+
end
|
244
|
+
else
|
245
|
+
# The outcode is the area plus at most two digits following it
|
246
|
+
|
247
|
+
if /[A-Z]/.match?(third)
|
248
|
+
# Because third is a letter, second must be the sector, and the district must be a single digit
|
249
|
+
"#{area}#{first}"
|
250
|
+
else
|
251
|
+
"#{area}#{first}#{second}".strip
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
if /[0-9]/.match?(second) && !Worldwide::ExtantOutcodes.for_country(code: country_code).include?(candidate)
|
256
|
+
# We've guessed a two-digit district that does not actually exist, so we'll assume a single-digit district.
|
257
|
+
# For example, "GL71" can't be an outcode, so we'll assume the user meant outcode "GL7".
|
258
|
+
"#{area}#{first}"
|
259
|
+
else
|
260
|
+
candidate
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
198
264
|
private
|
199
265
|
|
200
266
|
# Countries that use GB-style postal code spacing, and should normalize the same way as GB
|
@@ -350,7 +416,7 @@ module Worldwide
|
|
350
416
|
GB_POSTAL_TOWN_WITH_SECOND_CHAR_OH = ["C", "S", "P", "Y"]
|
351
417
|
private_constant :GB_POSTAL_TOWN_WITH_SECOND_CHAR_OH
|
352
418
|
|
353
|
-
# Based on postal code formats here: https://en.wikipedia.org/wiki/
|
419
|
+
# Based on postal code formats here: https://en.wikipedia.org/wiki/List_of_zips
|
354
420
|
NUMERIC_ONLY_ZIP_COUNTRIES = Set.new([
|
355
421
|
"AF",
|
356
422
|
"AL",
|
@@ -528,6 +594,8 @@ module Worldwide
|
|
528
594
|
confidence = candidate_regex[1]
|
529
595
|
|
530
596
|
normalized = normalize(country_code: candidate_code, zip: zip, allow_autofill: false)
|
597
|
+
next unless /[A-Z]/.match?(normalized) # Numeric-only postal codes are insufficiently specific
|
598
|
+
|
531
599
|
if normalized.match(regex)
|
532
600
|
candidate = Worldwide.region(code: candidate_code)
|
533
601
|
suggestions.append([candidate, confidence]) if candidate.valid_zip?(normalized)
|
@@ -784,11 +852,22 @@ module Worldwide
|
|
784
852
|
return "#{postal_town}#{division}#{division_suffix} #{digit}#{alpha}"
|
785
853
|
end
|
786
854
|
|
787
|
-
#
|
788
|
-
|
789
|
-
|
855
|
+
# If the input is only the postcode area (one or two letters), return just that with no trailing space
|
856
|
+
return upcased.strip if /^[A-Z]{1,2}$/.match?(upcased.strip)
|
857
|
+
|
858
|
+
inferred_outcode = gb_style_outcode(country_code: "GB", input: upcased)
|
859
|
+
|
860
|
+
if inferred_outcode.strip == upcased.strip
|
790
861
|
# Note that we're intentionally appending a space, so that this outcode will work for prefix matching
|
791
|
-
"#{
|
862
|
+
return "#{inferred_outcode.strip} "
|
863
|
+
end
|
864
|
+
|
865
|
+
if inferred_outcode.nil?
|
866
|
+
# Fallback to returning the unmodified input if we weren't able to make sense of it
|
867
|
+
input
|
868
|
+
else
|
869
|
+
remainder = upcased[inferred_outcode.length..-1]
|
870
|
+
"#{inferred_outcode.strip} #{remainder.strip}"
|
792
871
|
end
|
793
872
|
end
|
794
873
|
|
data/lib/worldwide.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: worldwide
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-04-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -8170,6 +8170,7 @@ files:
|
|
8170
8170
|
- db/data/regions/_default/zh-CN.yml
|
8171
8171
|
- db/data/regions/_default/zh-TW.yml
|
8172
8172
|
- db/data/world.yml
|
8173
|
+
- db/extant_outcodes.yml
|
8173
8174
|
- formats.md
|
8174
8175
|
- lib/worldwide.rb
|
8175
8176
|
- lib/worldwide/address.rb
|
@@ -8185,6 +8186,7 @@ files:
|
|
8185
8186
|
- lib/worldwide/currency.rb
|
8186
8187
|
- lib/worldwide/deprecated_time_zone_mapper.rb
|
8187
8188
|
- lib/worldwide/discounts.rb
|
8189
|
+
- lib/worldwide/extant_outcodes.rb
|
8188
8190
|
- lib/worldwide/field.rb
|
8189
8191
|
- lib/worldwide/fields.rb
|
8190
8192
|
- lib/worldwide/i18n_exception_handler.rb
|
@@ -8231,7 +8233,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
8231
8233
|
- !ruby/object:Gem::Version
|
8232
8234
|
version: '0'
|
8233
8235
|
requirements: []
|
8234
|
-
rubygems_version: 3.5.
|
8236
|
+
rubygems_version: 3.5.7
|
8235
8237
|
signing_key:
|
8236
8238
|
specification_version: 4
|
8237
8239
|
summary: Internationalization and localization APIs
|