atlas_engine 0.6.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (21) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +38 -4
  3. data/app/countries/atlas_engine/gg/address_importer/corrections/open_address/city_corrector.rb +38 -0
  4. data/app/countries/atlas_engine/gg/address_validation/validators/full_address/exclusions/city.rb +32 -0
  5. data/app/countries/atlas_engine/gg/country_profile.yml +8 -0
  6. data/app/countries/atlas_engine/gg/synonyms.yml +3 -0
  7. data/app/countries/atlas_engine/gg/validation_transcriber/address_parser.rb +57 -0
  8. data/app/models/atlas_engine/address_validation/es/datastore.rb +23 -0
  9. data/app/models/atlas_engine/address_validation/validators/full_address/concern_builder.rb +0 -4
  10. data/app/models/atlas_engine/address_validation/validators/full_address/unmatched_field_concern_builder.rb +1 -1
  11. data/app/models/atlas_engine/address_validation/validators/predicates/country/valid_for_zip.rb +1 -1
  12. data/app/models/atlas_engine/address_validation/validators/predicates/province/valid_for_country.rb +1 -1
  13. data/app/models/atlas_engine/address_validation/validators/predicates/street/building_number_in_address1.rb +1 -1
  14. data/app/models/atlas_engine/address_validation/validators/predicates/street/building_number_in_address1_or_address2.rb +1 -1
  15. data/app/models/atlas_engine/address_validation/validators/predicates/zip/valid_for_country.rb +1 -1
  16. data/app/models/atlas_engine/address_validation/validators/predicates/zip/valid_for_province.rb +1 -1
  17. data/app/models/atlas_engine/elasticsearch/error.rb +19 -0
  18. data/app/models/atlas_engine/elasticsearch/repository.rb +8 -8
  19. data/lib/atlas_engine/version.rb +1 -1
  20. metadata +8 -4
  21. data/app/models/atlas_engine/address_validation/validators/full_address/unknown_zip_for_address_concern_builder.rb +0 -34
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 56b5b41a624c3481954aadfa0101c9883dfe3479a3cdec373f8ecccab8bae879
4
- data.tar.gz: 73ee021ecf5d8357ae8f000df7e963e7504153fdc3b7bb98f188445aa8cd7989
3
+ metadata.gz: 1bdadba3857324dae37bf4c22aa4078b4f565876c0f865a4d3b99db69d0eaa41
4
+ data.tar.gz: 4004ade11bd387145ed6b82cb8b5df9a99989b3d1869cc1d40fd7fb310e3fc7c
5
5
  SHA512:
6
- metadata.gz: b93dee8561c73619222ca4a4e803fb2f911b3149955c5b1af7803990318a7ebd36e781c41643cf3076197f579833e9c2d361e8e4550a9d2d3de628d8e7819ef7
7
- data.tar.gz: f2f593c6e2a7849dae6dce6a52d9402ce7d907a90511664d1218133b5d4a501b5ae98a26e54a06412c3fb37e3dc74c75ae17c575ae24fa4805c02ad888467d21
6
+ metadata.gz: 846730be55864274ddd3d61e90ffd970102ea54d25221e411cee78c91daaa974a1159d0c976cde708ac6ea355815deb9c1d91230ef9c4eb49dcf38fe59e4be27
7
+ data.tar.gz: 791c4a0050adab0b39092b660c56968d7f6862a1387914f50341f940153963487f9fc8ec8533ee6519fd8569bd69022c8cb7ce181c3017a14313fd32a49879a7
data/README.md CHANGED
@@ -290,12 +290,46 @@ level address validation, your app must have a populated elasticsearch index per
290
290
  to query.
291
291
 
292
292
  The data we use to power atlas engine validation is free open source data from the [open addresses](https://openaddresses.io/)
293
- project. The following guide demostrates how to ingest data with the dummy app, but the process is the same with
293
+ project.
294
+
295
+ ### Supported countries
296
+ At the moment, `atlas_engine` supports advanced address validation for the following countries.
297
+
298
+ | Country/territory | Two-letter code | Locales | Street | City | Postal Code | Province/State |
299
+ |-------------------|-----------------|----------|--------|------|-------------|----------------|
300
+ | Australia | AU | | | x | x | x |
301
+ | Austria | AT | | | x | x | x |
302
+ | Belgium | BE | fr,nl,de | | x | x | |
303
+ | Bermuda | BM | | | x | x | x |
304
+ | Czechia | CZ | | | x | x | |
305
+ | Denmark | DK | | | x | x | |
306
+ | Faroe Islands | FO | | | x | x | |
307
+ | France | FR | | | x | x | |
308
+ | Italy | IT | | | | x | |
309
+ | Liechtenstein | LI | | | x | x | x |
310
+ | Luxembourg | LU | fr,lb | | x | x | |
311
+ | Netherlands | NL | nl | | x | x | x |
312
+ | Poland | PL | | | x | x | x |
313
+ | Portugal | PT | | | x | x | x |
314
+ | Slovenia | SI | | | x | x | x |
315
+ | South Korea | KR | | | x | x | x |
316
+ | Switzerland | CH | de,fr,it | | x | x | |
317
+
318
+ ### Downloading and indexing instructions
319
+
320
+
321
+ The following guide demonstrates how to ingest data with the dummy app, but the process is the same with
294
322
  the engine mounted into your own rails app.
295
323
 
296
324
  1. Go to the [open addresses](https://openaddresses.io/) download center, create an account, support the project, and
297
- download a GeoJSON+LD file for the country or region you wish to validate. For this example, we will be using the
298
- countrywide addresses data for Australia.
325
+ download a GeoJSON+LD file for the country or region you wish to validate.
326
+
327
+ Restrictions on the file:
328
+ - Must be an `addresses` file, as opposed to a `buildings` or `parcels` file.
329
+ - Must be gzipped (.gz format)
330
+ - Datasets listed under the _Individual Sources_ section work fine. Those under _Data Collections_ must first be unzipped. The `addresses` geojson files within may then be gzipped and imported.
331
+
332
+ For this example, we will be using the `au/countrywide` --> `addresses - country` data for Australia, in the GeoJSON+LD format.
299
333
 
300
334
  2. Once the file is downloaded, start your app with `rails s` and navigate to `http://localhost:3000/maintenance_tasks`
301
335
  (see [the github repo](https://github.com/Shopify/maintenance_tasks) for more information about maintenance_tasks).
@@ -309,7 +343,7 @@ records in our mysql database and has the following parameters:
309
343
  - **country_code: (required)** The ISO country code of the data we are ingesting.
310
344
  In this example, the country code of Australia is `AU`.
311
345
 
312
- - **geojson_file_path: (required)** The fully qualified path of the previously downloaded geojson data from open addresses.
346
+ - **geojson_file_path: (required)** The fully qualified path of the previously downloaded geojson data from OpenAddresses. A comma-delimited list of fully-qualified paths is also accepted.
313
347
 
314
348
  - **locale: (optional)** The language of the data in the open addresses file.
315
349
 
@@ -0,0 +1,38 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module AtlasEngine
5
+ module Gg
6
+ module AddressImporter
7
+ module Corrections
8
+ module OpenAddress
9
+ class CityCorrector
10
+ class << self
11
+ extend T::Sig
12
+
13
+ CITY_ALIASES_MAPPING = {
14
+ "St. Sampson" => ["Saint Samsaon"],
15
+ "St. Saviour" => ["Saint-Sauveur", "Saint Sauveux"],
16
+ "St. Peter Port" => ["Saint-Pierre Port"],
17
+ "St. Andrew" => ["Saint Andri", "Saint-André-de-la-Pommeraye"],
18
+ "St. Pierre Du Bois" => ["St. Peter's", "St. Pierre"],
19
+ "Castel" => ["Lé Casté", "Sainte-Marie-du-Câtel"],
20
+ "Forest" => ["Le Fôret", "La Fouarêt"],
21
+ "Torteval" => ["Tortévas"],
22
+ "Vale" => ["Lé Vale", "Le Valle"],
23
+ }
24
+
25
+ sig { params(address: Hash).void }
26
+ def apply(address)
27
+ city = address[:city].first
28
+ if CITY_ALIASES_MAPPING.include?(city)
29
+ address[:city] += CITY_ALIASES_MAPPING[city]
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,32 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module AtlasEngine
5
+ module Gg
6
+ module AddressValidation
7
+ module Validators
8
+ module FullAddress
9
+ module Exclusions
10
+ class City <
11
+ AtlasEngine::AddressValidation::Validators::FullAddress::Exclusions::ExclusionBase
12
+ extend T::Sig
13
+ class << self
14
+ sig do
15
+ override.params(
16
+ candidate: AtlasEngine::AddressValidation::Candidate,
17
+ address_comparison: AtlasEngine::AddressValidation::Validators::FullAddress::AddressComparison,
18
+ )
19
+ .returns(T::Boolean)
20
+ end
21
+ def apply?(candidate, address_comparison)
22
+ # If the candidate city is already present in the parsings
23
+ address_comparison.parsings.parsings.pluck(:city)&.include?(candidate.component(:city)&.value&.first)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -3,5 +3,13 @@ validation:
3
3
  enabled: true
4
4
  default_matching_strategy: es
5
5
  has_provinces: false
6
+ address_parser: AtlasEngine::Gg::ValidationTranscriber::AddressParser
6
7
  restrictions:
7
8
  - class: AtlasEngine::Gg::AddressValidation::Validators::FullAddress::Restrictions::UnsupportedCity
9
+ ingestion:
10
+ correctors:
11
+ open_address:
12
+ - AtlasEngine::Gg::AddressImporter::Corrections::OpenAddress::CityCorrector
13
+ exclusions:
14
+ city:
15
+ - AtlasEngine::Gg::AddressValidation::Validators::FullAddress::Exclusions::City
@@ -0,0 +1,3 @@
1
+ city_synonyms:
2
+ - st, saint
3
+ - ste, sainte
@@ -0,0 +1,57 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module AtlasEngine
5
+ module Gg
6
+ module ValidationTranscriber
7
+ class AddressParser < AtlasEngine::ValidationTranscriber::AddressParserBase
8
+ private
9
+
10
+ CITY = %r{
11
+ (?<city>
12
+ st\.?\s?saviour[']?[s]?|
13
+ saint[-|\s]sauveur|
14
+ saint\s?sauveux|
15
+ st\.?\s?sampson[']?[s]?|
16
+ saint\s?samsaon|
17
+ st\.?\s?andrew[']?[s]?|
18
+ saint\s?andri|
19
+ saint[-|\s]andr[é|e][-|\s]de[-|\s]la[-|\s]pommeraye|
20
+ st\.?\s?martin[']?[s]?|
21
+ st\.?\s?peter[']?[s]?\s?port|
22
+ saint[-|\s]pierre\s?port|
23
+ st\.?\s?peter[']?[s]?|
24
+ st\.?\s?pierre\s?du\s?bois|
25
+ st\.?\s?pierre|
26
+ vale|
27
+ l[é|e]\s?vale|
28
+ le\s?valle|
29
+ torteval|
30
+ tort[é|e]vas|
31
+ castel|
32
+ l[é|e]\s?cast[é|e]|
33
+ sainte[-|\s]marie[-|\s]du[-|\s]c[â|a]tel|
34
+ forest|
35
+ le\s?f[ô|o]ret|
36
+ la\s?fouar[ê|e]t
37
+ )
38
+ }ix
39
+
40
+ sig { returns(T::Array[Regexp]) }
41
+ def country_regex_formats
42
+ @country_regex_formats ||= [
43
+ /^#{BUILDING_NAME},\s+#{CITY}$/,
44
+ /^#{BUILDING_NAME},\s+#{STREET_NO_COMMAS},\s+#{CITY}$/,
45
+ /^#{BUILDING_NAME},\s+#{STREET_NO_COMMAS}$/,
46
+ /^#{NUMERIC_ONLY_BUILDING_NUM}?\s+#{STREET_NO_COMMAS},\s+#{CITY}$/,
47
+ /^#{UNIT_TYPE}\s+#{UNIT_NUM_NO_HYPHEN},\s+#{BUILDING_NAME},\s+#{CITY}$/,
48
+ /^#{CITY}$/,
49
+ /^#{NUMERIC_ONLY_BUILDING_NUM}?\s+#{STREET_NO_COMMAS}$/,
50
+ /^#{BUILDING_NAME}$/,
51
+ /^#{STREET_NO_COMMAS}$/,
52
+ ]
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -128,6 +128,9 @@ module AtlasEngine
128
128
  end
129
129
  Token::Sequence.new(tokens: tokens, raw_value: city_value)
130
130
  end
131
+ rescue Elasticsearch::Error => e
132
+ log_elasticsearch_error(error: e, method: "city_sequence")
133
+ Token::Sequence.new(tokens: [], raw_value: city_value)
131
134
  end
132
135
 
133
136
  sig { returns(T::Array[T::Hash[String, T.untyped]]) }
@@ -135,6 +138,9 @@ module AtlasEngine
135
138
  measure_es_validation_request_time(method: "full_address_candidates") do
136
139
  repository.search(query_builder.full_address_query)
137
140
  end
141
+ rescue Elasticsearch::Error => e
142
+ log_elasticsearch_error(error: e, method: "full_address_candidates")
143
+ []
138
144
  end
139
145
 
140
146
  sig { returns(T::Array[Token::Sequence]) }
@@ -154,6 +160,9 @@ module AtlasEngine
154
160
  end
155
161
  end
156
162
  end
163
+ rescue Elasticsearch::Error => e
164
+ log_elasticsearch_error(error: e, method: "street_sequence")
165
+ [Token::Sequence.new(tokens: [], raw_value: "")]
157
166
  end
158
167
 
159
168
  sig { params(candidates: T::Array[Candidate]).void }
@@ -165,6 +174,8 @@ module AtlasEngine
165
174
  end
166
175
 
167
176
  TermVectors.new(term_vectors_hashes: candidate_term_vectors, candidates: candidates).set_candidate_sequences
177
+ rescue Elasticsearch::Error => e
178
+ log_elasticsearch_error(error: e, method: "term_vectors")
168
179
  end
169
180
 
170
181
  sig { params(candidates: T::Array[Candidate]).returns(T::Hash[String, T.untyped]) }
@@ -190,6 +201,18 @@ module AtlasEngine
190
201
  )
191
202
  end
192
203
 
204
+ sig { params(error: Elasticsearch::Error, method: String).void }
205
+ def log_elasticsearch_error(error:, method:)
206
+ log_error("Elasticsearch error: #{error.message}")
207
+ StatsD.increment(
208
+ "AddressValidation.elasticsearch_error",
209
+ tags: {
210
+ country: country_code,
211
+ method:,
212
+ },
213
+ )
214
+ end
215
+
193
216
  sig { params(future: T.nilable(Concurrent::Promises::Future), method: String).void }
194
217
  def log_future_state_on_join(future:, method:)
195
218
  state = future&.state || :unsubmitted
@@ -109,10 +109,6 @@ module AtlasEngine
109
109
  concern = InvalidZipConcernBuilder.for(address, suggestion_ids)
110
110
  return concern if concern
111
111
 
112
- if :province_code.in?(matched_components) && :city.in?(matched_components)
113
- return UnknownZipForAddressConcernBuilder.new(address).build(suggestion_ids)
114
- end
115
-
116
112
  build_default_concern
117
113
  end
118
114
 
@@ -56,7 +56,7 @@ module AtlasEngine
56
56
 
57
57
  sig { returns(String) }
58
58
  def message
59
- "Enter a valid #{COMPONENTS_TO_LABELS[component]} for #{valid_address_component_values.join(", ")}"
59
+ country.field(key: field_name).error(code: :unknown_for_address).to_s
60
60
  end
61
61
 
62
62
  sig { returns(Symbol) }
@@ -28,7 +28,7 @@ module AtlasEngine
28
28
  sig { params(suggestion: Suggestion).returns(Concern) }
29
29
  def build_concern(suggestion)
30
30
  Concern.new(
31
- field_names: [:country, :zip],
31
+ field_names: [:country],
32
32
  code: :country_invalid_for_zip,
33
33
  type: T.must(Concern::TYPES[:error]),
34
34
  type_level: 1,
@@ -24,7 +24,7 @@ module AtlasEngine
24
24
  sig { returns(Concern) }
25
25
  def build_concern
26
26
  Concern.new(
27
- field_names: [:province, :country],
27
+ field_names: [:province],
28
28
  code: :province_invalid,
29
29
  type: T.must(Concern::TYPES[:error]),
30
30
  type_level: 3,
@@ -24,7 +24,7 @@ module AtlasEngine
24
24
  sig { returns(Concern) }
25
25
  def build_concern
26
26
  Concern.new(
27
- field_names: [:address1, :country],
27
+ field_names: [:address1],
28
28
  code: :missing_building_number,
29
29
  type: T.must(Concern::TYPES[:warning]),
30
30
  type_level: 1,
@@ -22,7 +22,7 @@ module AtlasEngine
22
22
  sig { returns(Concern) }
23
23
  def build_concern
24
24
  Concern.new(
25
- field_names: [:address1, :address2, :country],
25
+ field_names: [:address1, :address2],
26
26
  code: :missing_building_number,
27
27
  type: T.must(Concern::TYPES[:warning]),
28
28
  type_level: 3,
@@ -26,7 +26,7 @@ module AtlasEngine
26
26
  sig { returns(Concern) }
27
27
  def build_concern
28
28
  Concern.new(
29
- field_names: [:zip, :country],
29
+ field_names: [:zip],
30
30
  code: :zip_invalid_for_country,
31
31
  type: T.must(Concern::TYPES[:error]),
32
32
  type_level: 3,
@@ -29,7 +29,7 @@ module AtlasEngine
29
29
  sig { returns(Concern) }
30
30
  def build_concern
31
31
  Concern.new(
32
- field_names: [:zip, :country, :province],
32
+ field_names: [:zip],
33
33
  code: :zip_invalid_for_province,
34
34
  type: T.must(Concern::TYPES[:error]),
35
35
  type_level: 3,
@@ -0,0 +1,19 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AtlasEngine
5
+ module Elasticsearch
6
+ class Error < StandardError
7
+ extend T::Sig
8
+
9
+ sig { params(message: String, cause: T.nilable(Exception)).void }
10
+ def initialize(message, cause = nil)
11
+ super(message)
12
+ @cause = cause
13
+ end
14
+
15
+ sig { returns(T.nilable(Exception)) }
16
+ attr_reader :cause
17
+ end
18
+ end
19
+ end
@@ -133,8 +133,8 @@ module AtlasEngine
133
133
  response = client.post(path, query, {})
134
134
 
135
135
  response.body
136
- rescue ::Elastic::Transport::Transport::Error
137
- { "hits" => { "hits" => [] } }
136
+ rescue ::Elastic::Transport::Transport::Error => e
137
+ raise Elasticsearch::Error.new(e.message, e)
138
138
  end
139
139
 
140
140
  sig { override.params(query: T::Hash[String, T.untyped]).returns(T::Hash[String, T.untyped]) }
@@ -143,8 +143,8 @@ module AtlasEngine
143
143
  response = client.post(path, query, {})
144
144
 
145
145
  response.body
146
- rescue ::Elastic::Transport::Transport::Error
147
- { "tokens" => [] }
146
+ rescue ::Elastic::Transport::Transport::Error => e
147
+ raise Elasticsearch::Error.new(e.message, e)
148
148
  end
149
149
 
150
150
  sig { override.params(query: T::Hash[String, T.untyped]).returns(T::Hash[String, T.untyped]) }
@@ -153,8 +153,8 @@ module AtlasEngine
153
153
  response = client.post(path, query, {})
154
154
 
155
155
  response.body
156
- rescue ::Elastic::Transport::Transport::Error
157
- { "docs" => [] }
156
+ rescue ::Elastic::Transport::Transport::Error => e
157
+ raise Elasticsearch::Error.new(e.message, e)
158
158
  end
159
159
 
160
160
  sig { override.params(id: T.any(String, Integer)).returns(T::Hash[String, T.untyped]) }
@@ -163,8 +163,8 @@ module AtlasEngine
163
163
  response = client.get(path, nil, {})
164
164
 
165
165
  response.body["_source"]
166
- rescue ::Elastic::Transport::Transport::Error
167
- {}
166
+ rescue ::Elastic::Transport::Transport::Error => e
167
+ raise Elasticsearch::Error.new(e.message, e)
168
168
  end
169
169
 
170
170
  sig { override.params(post_address: PostAddressData).returns(T::Hash[Symbol, T.untyped]) }
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module AtlasEngine
5
- VERSION = "0.6.0"
5
+ VERSION = "0.8.0"
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: atlas_engine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-26 00:00:00.000000000 Z
11
+ date: 2024-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: annex_29
@@ -305,8 +305,12 @@ files:
305
305
  - app/countries/atlas_engine/gb/country_profile.yml
306
306
  - app/countries/atlas_engine/gb/validation_transcriber/full_address_parser.rb
307
307
  - app/countries/atlas_engine/gb/validation_transcriber/parsed_address.rb
308
+ - app/countries/atlas_engine/gg/address_importer/corrections/open_address/city_corrector.rb
309
+ - app/countries/atlas_engine/gg/address_validation/validators/full_address/exclusions/city.rb
308
310
  - app/countries/atlas_engine/gg/address_validation/validators/full_address/restrictions/unsupported_city.rb
309
311
  - app/countries/atlas_engine/gg/country_profile.yml
312
+ - app/countries/atlas_engine/gg/synonyms.yml
313
+ - app/countries/atlas_engine/gg/validation_transcriber/address_parser.rb
310
314
  - app/countries/atlas_engine/ie/country_profile.yml
311
315
  - app/countries/atlas_engine/it/address_importer/corrections/open_address/city_corrector.rb
312
316
  - app/countries/atlas_engine/it/address_importer/corrections/open_address/province_corrector.rb
@@ -494,7 +498,6 @@ files:
494
498
  - app/models/atlas_engine/address_validation/validators/full_address/suggestion_builder.rb
495
499
  - app/models/atlas_engine/address_validation/validators/full_address/unknown_address_concern_builder.rb
496
500
  - app/models/atlas_engine/address_validation/validators/full_address/unknown_province_concern_builder.rb
497
- - app/models/atlas_engine/address_validation/validators/full_address/unknown_zip_for_address_concern_builder.rb
498
501
  - app/models/atlas_engine/address_validation/validators/full_address/unmatched_field_concern_builder.rb
499
502
  - app/models/atlas_engine/address_validation/validators/full_address/unsupported_script_result.rb
500
503
  - app/models/atlas_engine/address_validation/validators/full_address/zip_comparison.rb
@@ -530,6 +533,7 @@ files:
530
533
  - app/models/atlas_engine/country_repository.rb
531
534
  - app/models/atlas_engine/elasticsearch/client.rb
532
535
  - app/models/atlas_engine/elasticsearch/client_interface.rb
536
+ - app/models/atlas_engine/elasticsearch/error.rb
533
537
  - app/models/atlas_engine/elasticsearch/repository.rb
534
538
  - app/models/atlas_engine/elasticsearch/repository_interface.rb
535
539
  - app/models/atlas_engine/elasticsearch/response.rb
@@ -593,7 +597,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
593
597
  - !ruby/object:Gem::Version
594
598
  version: '0'
595
599
  requirements: []
596
- rubygems_version: 3.5.6
600
+ rubygems_version: 3.5.7
597
601
  signing_key:
598
602
  specification_version: 4
599
603
  summary: Address Validation API
@@ -1,34 +0,0 @@
1
- # typed: true
2
- # frozen_string_literal: true
3
-
4
- module AtlasEngine
5
- module AddressValidation
6
- module Validators
7
- module FullAddress
8
- class UnknownZipForAddressConcernBuilder
9
- extend T::Sig
10
- attr_reader :address
11
-
12
- sig { params(address: AbstractAddress).void }
13
- def initialize(address)
14
- @address = address
15
- end
16
-
17
- sig { params(suggestion_ids: T::Array[String]).returns(Concern) }
18
- def build(suggestion_ids = [])
19
- message = "Enter a valid ZIP for #{address.address1}, #{address.city}"
20
-
21
- Concern.new(
22
- code: :zip_inconsistent,
23
- field_names: [:zip],
24
- message: message,
25
- type: T.must(Concern::TYPES[:warning]),
26
- type_level: 3,
27
- suggestion_ids: suggestion_ids,
28
- )
29
- end
30
- end
31
- end
32
- end
33
- end
34
- end