worldwide 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2c3c323e57e56b609ebdc7fe5d7965a2d5348fede9b72110627528529b3b7ab5
4
- data.tar.gz: f4007e0986bc9702af7d95f3c352a11937292d9f6fbbd8c21e8a1a635fcc7993
3
+ metadata.gz: 4dca8f095b6020792ecd6186606db9cd6159d03414b735b0c2d4b30f0746b680
4
+ data.tar.gz: 7e40cbbd862960354faf241a3320c03b1a081fa005f42063bf27951ca94f3c1d
5
5
  SHA512:
6
- metadata.gz: 333628df88179b5d2696634f3dadec1a548a5a2ef4baebcac86832077565f5f826036da107cdf8d5d4ed84323563235265df4b0bf37648f7d7691ef120e81216
7
- data.tar.gz: cdbad17228b52fc39d188fdbf2e13800aa4015caf18cd314d9cdfcd7f3a7b63f585c2cbd69eec36bb8c450dae83e649c35a0c661c651e55293c626582e03a785
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
@@ -13,7 +13,7 @@ GIT
13
13
  PATH
14
14
  remote: .
15
15
  specs:
16
- worldwide (0.2.0)
16
+ worldwide (0.4.0)
17
17
  activesupport (~> 7.0)
18
18
  i18n (~> 1.12.0)
19
19
  phonelib (~> 0.8)
@@ -14,6 +14,7 @@ zip_regex: "^(IT?-?)?\\d{5}$"
14
14
  zip_example: '00144'
15
15
  phone_number_prefix: 39
16
16
  building_number_required: true
17
+ building_number_may_be_in_address2: true
17
18
  week_start_day: monday
18
19
  languages:
19
20
  - it
@@ -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'
@@ -34,7 +34,9 @@ module Worldwide
34
34
  :zip_requirement,
35
35
  ]
36
36
 
37
- attr_accessor :parent
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
- @parent = nil
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.parent = self
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.alpha_three ||
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? && parent.iso_code ? parent.iso_code : iso_code,
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
- return parent.send(:passes_country_zip_regexp?, value: value, partial_match: partial_match) if province?
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 = parent
498
+ country = associated_country
453
499
  province_code ||= legacy_code
454
500
  end
455
501
 
@@ -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
- search_code = cldr.to_s.upcase
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
- search_code = code.to_s.upcase
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.freeze
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
- if parent.present? && current_region.parent != parent
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"] || []
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Worldwide
4
- VERSION = "0.2.0"
4
+ VERSION = "0.4.0"
5
5
  end
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.2.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-01 00:00:00.000000000 Z
11
+ date: 2023-11-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport