worldwide 0.2.0 → 0.4.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/Gemfile.lock +1 -1
- data/db/data/regions/IT.yml +1 -0
- data/db/data/regions/US.yml +2 -0
- data/lib/worldwide/region.rb +53 -7
- data/lib/worldwide/regions.rb +3 -11
- data/lib/worldwide/regions_loader.rb +36 -4
- data/lib/worldwide/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4dca8f095b6020792ecd6186606db9cd6159d03414b735b0c2d4b30f0746b680
|
4
|
+
data.tar.gz: 7e40cbbd862960354faf241a3320c03b1a081fa005f42063bf27951ca94f3c1d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1c385197a1a3239d1d1251a0cb7b45fe3f04f4d9e75dc3ed02227fe9692184b12dc5754c4c5292bfbd24e4a079df48b2ea63689e63b11511ec1f7017627ac15a
|
7
|
+
data.tar.gz: 666f0e760f82cfab270d47328a9600204e7c93c04bd16106b5f6d46cadefcd15f90dc64ea5663f0eeefc2827458aa2b47147468b45da059a57c37dd146893444
|
data/CHANGELOG.md
CHANGED
@@ -28,6 +28,21 @@ Nil.
|
|
28
28
|
|
29
29
|
---
|
30
30
|
|
31
|
+
[0.4.0] - 2023-11-08
|
32
|
+
- Add region name alternates [#32](https://github.com/Shopify/worldwide/pull/32)
|
33
|
+
- Cache `Region#parent_name` [#33](https://github.com/Shopify/worldwide/pull/33)
|
34
|
+
- Use hash tables to look up regions by code [#36](https://github.com/Shopify/worldwide/pull/36)
|
35
|
+
|
36
|
+
[0.3.0] - 2023-11-03
|
37
|
+
- Add code alternates for Japan [#23](https://github.com/Shopify/worldwide/pull/23)
|
38
|
+
- Add code alternates for Puerto Rico [#24](https://github.com/Shopify/worldwide/pull/24)
|
39
|
+
- Record multiple parents per region [#27](https://github.com/Shopify/worldwide/pull/27)
|
40
|
+
- Add region.building_number_may_be_in_address2 [#28](https://github.com/Shopify/worldwide/pull/28)
|
41
|
+
- Lookup by parent-child ISO and CLDR codes for dual-status territories
|
42
|
+
[#29](https://github.com/Shopify/worldwide/pull/29)
|
43
|
+
- Handle ISO_CODE only zones lookup [#26](https://github.com/Shopify/worldwide/pull/26)
|
44
|
+
|
45
|
+
|
31
46
|
[0.2.0] - 2023-11-01
|
32
47
|
|
33
48
|
- Add Region#group and Region#group_name [#15](https://github.com/Shopify/worldwide/pull/15)
|
data/Gemfile.lock
CHANGED
data/db/data/regions/IT.yml
CHANGED
data/db/data/regions/US.yml
CHANGED
@@ -7,6 +7,8 @@ unit_system: imperial
|
|
7
7
|
tax_name: Federal Tax
|
8
8
|
group: North American Countries
|
9
9
|
group_name: North America
|
10
|
+
name_alternates:
|
11
|
+
- United States of America
|
10
12
|
zip_label: Zip code
|
11
13
|
zip_regex: "(?-mix:\\A\\d{5}(-\\d{4})?\\z)|(?i-mx:\\AFPO\\s*A[A-Z]\\s*\\d{5}-\\d{4}\\z)"
|
12
14
|
zip_example: '90210'
|
data/lib/worldwide/region.rb
CHANGED
@@ -34,7 +34,9 @@ module Worldwide
|
|
34
34
|
:zip_requirement,
|
35
35
|
]
|
36
36
|
|
37
|
-
|
37
|
+
# A region may have more than one parent.
|
38
|
+
# For example, Puerto Rico (PR/US-PR) is associated with both the US and the Caribbean (029)
|
39
|
+
attr_accessor :parents
|
38
40
|
|
39
41
|
# ISO-3166 three-letter code for this region, if there is one.
|
40
42
|
# Otherwise, nil.
|
@@ -45,6 +47,10 @@ module Worldwide
|
|
45
47
|
# If we require a building number in an address, then this will be true.
|
46
48
|
attr_accessor :building_number_required
|
47
49
|
|
50
|
+
# In some countries, an address may have the building number in address2.
|
51
|
+
# If we are allowed to have a building number in address2, then this will be true.
|
52
|
+
attr_accessor :building_number_may_be_in_address2
|
53
|
+
|
48
54
|
# Alternate codes which may be used to designate this region
|
49
55
|
attr_accessor :code_alternates
|
50
56
|
|
@@ -104,6 +110,10 @@ module Worldwide
|
|
104
110
|
# This name is the name that was traditionally returned by "country_db".
|
105
111
|
attr_reader :legacy_name
|
106
112
|
|
113
|
+
# Other names that may be used to refer to this region.
|
114
|
+
# E.g., "Czech Republic" is also known as "Czechia".
|
115
|
+
attr_accessor :name_alternates
|
116
|
+
|
107
117
|
# iso_code values of regions (subdivisions) within the same country that border this region.
|
108
118
|
# E.g., for CA-ON, the neighbouring zones are CA-MB, CA-NU and CA-QC.
|
109
119
|
attr_accessor :neighbours
|
@@ -217,6 +227,7 @@ module Worldwide
|
|
217
227
|
@use_zone_code_as_short_name = use_zone_code_as_short_name
|
218
228
|
|
219
229
|
@building_number_required = false
|
230
|
+
@building_number_may_be_in_address2 = false
|
220
231
|
@currency = nil
|
221
232
|
@flag = nil
|
222
233
|
@format = {}
|
@@ -236,7 +247,7 @@ module Worldwide
|
|
236
247
|
@zip_prefixes = []
|
237
248
|
@zip_regex = nil
|
238
249
|
|
239
|
-
@
|
250
|
+
@parents = [].to_set
|
240
251
|
@zones = []
|
241
252
|
end
|
242
253
|
|
@@ -249,12 +260,18 @@ module Worldwide
|
|
249
260
|
def add_zone(region)
|
250
261
|
return if @zones.include?(region)
|
251
262
|
|
252
|
-
region.
|
263
|
+
region.parents << self
|
253
264
|
@zones.append(region)
|
254
265
|
end
|
255
266
|
|
256
267
|
# Attributes
|
257
268
|
|
269
|
+
def associated_country
|
270
|
+
return self if country?
|
271
|
+
|
272
|
+
parent_country
|
273
|
+
end
|
274
|
+
|
258
275
|
# The value with which to autofill the zip, if this region has zip autofill active;
|
259
276
|
# otherwise, nil.
|
260
277
|
def autofill_zip
|
@@ -333,7 +350,8 @@ module Worldwide
|
|
333
350
|
|
334
351
|
zones.find do |region|
|
335
352
|
[search_code, alt_search_code].any? do |candidate|
|
336
|
-
candidate == region.
|
353
|
+
candidate == subdivision_code(region.iso_code) ||
|
354
|
+
candidate == region.alpha_three ||
|
337
355
|
candidate == region.iso_code ||
|
338
356
|
candidate == region.legacy_code ||
|
339
357
|
candidate == region.numeric_three ||
|
@@ -371,7 +389,7 @@ module Worldwide
|
|
371
389
|
# is the given postal code value valid for this region?
|
372
390
|
def valid_zip?(zip, partial_match: false)
|
373
391
|
normalized = Zip.normalize(
|
374
|
-
country_code: province? &&
|
392
|
+
country_code: province? && associated_country.iso_code ? associated_country.iso_code : iso_code,
|
375
393
|
zip: zip,
|
376
394
|
)
|
377
395
|
valid_normalized_zip?(normalized, partial_match: partial_match)
|
@@ -384,6 +402,21 @@ module Worldwide
|
|
384
402
|
|
385
403
|
private
|
386
404
|
|
405
|
+
def answers_to_cldr_code(search_code)
|
406
|
+
return false if Util.blank?(search_code) || Util.blank?(cldr_code)
|
407
|
+
return true if search_code.casecmp(cldr_code).zero?
|
408
|
+
|
409
|
+
pc = parent_country
|
410
|
+
"#{pc&.cldr_code&.downcase}#{cldr_code.downcase}" == search_code.downcase
|
411
|
+
end
|
412
|
+
|
413
|
+
def answers_to_iso_code(search_code)
|
414
|
+
return true if search_code == iso_code
|
415
|
+
|
416
|
+
pc = parent_country
|
417
|
+
"#{pc&.iso_code}-#{iso_code}" == search_code
|
418
|
+
end
|
419
|
+
|
387
420
|
def cross_border_zip_includes_province?(zip:, province_code:)
|
388
421
|
return false unless country?
|
389
422
|
|
@@ -408,11 +441,17 @@ module Worldwide
|
|
408
441
|
INSPECTION_FIELDS.map { |field_name| "@#{field_name}=#{send(field_name).inspect}" }.join(", ")
|
409
442
|
end
|
410
443
|
|
444
|
+
def parent_country
|
445
|
+
@parent_country ||= parents.find(&:country?)
|
446
|
+
end
|
447
|
+
|
411
448
|
# Checks whether the given value is acceptable according to the regular expression defined for the country.
|
412
449
|
# @param value [String] for the postal code
|
413
450
|
# @return [Boolean]
|
414
451
|
def passes_country_zip_regexp?(value:, partial_match: false)
|
415
|
-
|
452
|
+
if province?
|
453
|
+
return associated_country.send(:passes_country_zip_regexp?, value: value, partial_match: partial_match)
|
454
|
+
end
|
416
455
|
|
417
456
|
return false if partial_match && partial_zip_regex.nil?
|
418
457
|
|
@@ -445,11 +484,18 @@ module Worldwide
|
|
445
484
|
end&.first
|
446
485
|
end
|
447
486
|
|
487
|
+
def subdivision_code(iso_code)
|
488
|
+
return iso_code if iso_code.nil? || iso_code.length < 3
|
489
|
+
|
490
|
+
country_code, subdivision_code = iso_code.split("-")
|
491
|
+
return subdivision_code if country_code.casecmp(associated_country.iso_code).zero?
|
492
|
+
end
|
493
|
+
|
448
494
|
def valid_normalized_zip?(normalized, province_code: nil, partial_match: false)
|
449
495
|
if country?
|
450
496
|
country = self
|
451
497
|
elsif province?
|
452
|
-
country =
|
498
|
+
country = associated_country
|
453
499
|
province_code ||= legacy_code
|
454
500
|
end
|
455
501
|
|
data/lib/worldwide/regions.rb
CHANGED
@@ -16,7 +16,7 @@ module Worldwide
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def initialize
|
19
|
-
@regions = RegionsLoader.new.load_regions
|
19
|
+
@regions, @regions_by_cldr_code, @regions_by_iso_code = RegionsLoader.new.load_regions
|
20
20
|
end
|
21
21
|
|
22
22
|
def all
|
@@ -29,17 +29,9 @@ module Worldwide
|
|
29
29
|
end
|
30
30
|
|
31
31
|
result = if cldr
|
32
|
-
|
33
|
-
|
34
|
-
@regions.find do |r|
|
35
|
-
r.cldr_code.upcase == search_code
|
36
|
-
end
|
32
|
+
@regions_by_cldr_code[cldr.to_s.upcase]
|
37
33
|
elsif code
|
38
|
-
|
39
|
-
|
40
|
-
@regions.find do |r|
|
41
|
-
r.iso_code == search_code || r.alpha_three == search_code || r.numeric_three == search_code
|
42
|
-
end
|
34
|
+
@regions_by_iso_code[code.to_s.upcase]
|
43
35
|
else # search by name
|
44
36
|
search_name = name.upcase
|
45
37
|
|
@@ -9,6 +9,9 @@ module Worldwide
|
|
9
9
|
WORLD_CODE = "001" # UN code for the whole world
|
10
10
|
|
11
11
|
def load_regions
|
12
|
+
@regions_by_cldr_code = {}
|
13
|
+
@regions_by_iso_code = {}
|
14
|
+
|
12
15
|
# Load country/region definitions out of the db/data/regions/??.yml files
|
13
16
|
@regions = Dir["#{Worldwide::Paths::REGIONS_ROOT}/*.yml"].map do |filename|
|
14
17
|
load_territory(filename)
|
@@ -25,11 +28,39 @@ module Worldwide
|
|
25
28
|
|
26
29
|
construct_unknown
|
27
30
|
|
28
|
-
@regions.
|
31
|
+
@regions.each do |region|
|
32
|
+
construct_lookup_info(region)
|
33
|
+
end
|
34
|
+
|
35
|
+
[@regions.freeze, @regions_by_cldr_code, @regions_by_iso_code]
|
29
36
|
end
|
30
37
|
|
31
38
|
private
|
32
39
|
|
40
|
+
def construct_lookup_info(region)
|
41
|
+
pc = region.send(:parent_country)
|
42
|
+
|
43
|
+
# Remember CLDR code(s) for later use during lookup
|
44
|
+
|
45
|
+
search_code = region.cldr_code.to_s.upcase
|
46
|
+
@regions_by_cldr_code[search_code] = region if Util.present?(search_code)
|
47
|
+
|
48
|
+
@regions_by_cldr_code["#{pc.cldr_code.upcase}#{search_code}"] = region if Util.present?(pc&.cldr_code)
|
49
|
+
|
50
|
+
# Remember ISO 3166 code(s) for later use during lookup
|
51
|
+
|
52
|
+
iso_code = region.iso_code
|
53
|
+
@regions_by_iso_code[iso_code] = region if Util.present?(iso_code)
|
54
|
+
|
55
|
+
@regions_by_iso_code["#{pc.iso_code}-#{iso_code}"] = region if Util.present?(pc)
|
56
|
+
|
57
|
+
alpha_three = region.alpha_three
|
58
|
+
@regions_by_iso_code[alpha_three] = region if Util.present?(alpha_three)
|
59
|
+
|
60
|
+
numeric_three = region.numeric_three
|
61
|
+
@regions_by_iso_code[numeric_three] = region if Util.present?(numeric_three)
|
62
|
+
end
|
63
|
+
|
33
64
|
def apply_hierarchy(parent:, code:, children:)
|
34
65
|
current_region = find_region(code: code)
|
35
66
|
if current_region.nil?
|
@@ -46,9 +77,7 @@ module Worldwide
|
|
46
77
|
@regions << current_region
|
47
78
|
end
|
48
79
|
|
49
|
-
|
50
|
-
current_region.parent = parent
|
51
|
-
end
|
80
|
+
current_region.parents << parent if Util.present?(parent)
|
52
81
|
parent&.add_zone(current_region)
|
53
82
|
return current_region if children.nil?
|
54
83
|
|
@@ -61,6 +90,7 @@ module Worldwide
|
|
61
90
|
|
62
91
|
def apply_territory_attributes(region, spec)
|
63
92
|
region.building_number_required = spec["building_number_required"] || true
|
93
|
+
region.building_number_may_be_in_address2 = spec["building_number_may_be_in_address2"] || false
|
64
94
|
currency_code = spec["currency"]
|
65
95
|
region.currency = Worldwide.currency(code: currency_code) unless currency_code.nil?
|
66
96
|
region.flag = spec["emoji"]
|
@@ -83,10 +113,12 @@ module Worldwide
|
|
83
113
|
region.zip_requirement = spec["zip_requirement"]
|
84
114
|
region.zip_regex = spec["zip_regex"]
|
85
115
|
region.zips_crossing_provinces = spec["zips_crossing_provinces"]
|
116
|
+
region.name_alternates = spec["name_alternates"] || []
|
86
117
|
end
|
87
118
|
|
88
119
|
def apply_zone_attributes(region, zone)
|
89
120
|
region.code_alternates = zone["code_alternates"] || []
|
121
|
+
region.name_alternates = zone["name_alternates"] || []
|
90
122
|
region.example_city = zone["example_city"]
|
91
123
|
region.neighbours = zone["neighboring_zones"]
|
92
124
|
region.zip_prefixes = zone["zip_prefixes"] || []
|
data/lib/worldwide/version.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.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-11-
|
11
|
+
date: 2023-11-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|