atlas_engine 0.1.1 → 0.2.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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +498 -34
  3. data/app/countries/atlas_engine/be/country_profile.yml +2 -0
  4. data/app/countries/atlas_engine/be/validation_transcriber/address_parser.rb +84 -0
  5. data/app/countries/atlas_engine/bm/address_importer/corrections/open_address/city_alias_corrector.rb +12 -11
  6. data/app/countries/atlas_engine/bm/synonyms.yml +6 -0
  7. data/app/countries/atlas_engine/ch/country_profile.yml +2 -0
  8. data/app/countries/atlas_engine/ch/locales/de/country_profile.yml +0 -1
  9. data/app/countries/atlas_engine/ch/locales/fr/country_profile.yml +3 -0
  10. data/app/countries/atlas_engine/ch/locales/fr/validation_transcriber/address_parser.rb +29 -0
  11. data/app/countries/atlas_engine/cz/address_validation/es/query_builder.rb +43 -0
  12. data/app/countries/atlas_engine/cz/country_profile.yml +2 -1
  13. data/app/countries/atlas_engine/cz/validation_transcriber/address_parser.rb +26 -0
  14. data/app/countries/atlas_engine/it/address_importer/open_address/mapper.rb +1 -1
  15. data/app/countries/atlas_engine/it/country_profile.yml +1 -0
  16. data/app/countries/atlas_engine/sa/country_profile.yml +4 -1
  17. data/app/countries/atlas_engine/us/country_profile.yml +0 -2
  18. data/app/lib/atlas_engine/validation_transcriber/address_parsings.rb +1 -1
  19. data/app/lib/atlas_engine/validation_transcriber/formatter.rb +2 -2
  20. data/app/models/atlas_engine/address_validation/datastore_base.rb +3 -0
  21. data/app/models/atlas_engine/address_validation/es/datastore.rb +11 -6
  22. data/app/models/atlas_engine/address_validation/es/query_builder.rb +40 -29
  23. data/app/models/atlas_engine/address_validation/es/validators/full_address.rb +1 -1
  24. data/app/models/atlas_engine/address_validation/log_emitter.rb +1 -0
  25. data/app/models/atlas_engine/address_validation/normalizer.rb +0 -9
  26. data/app/models/atlas_engine/address_validation/validators/full_address/address_comparison.rb +7 -23
  27. data/app/models/atlas_engine/address_validation/validators/full_address/candidate_result.rb +42 -16
  28. data/app/models/atlas_engine/address_validation/validators/full_address/comparison_helper.rb +109 -109
  29. data/app/models/atlas_engine/address_validation/validators/full_address/{components_to_validate.rb → relevant_components.rb} +26 -18
  30. data/app/models/atlas_engine/country_profile_validation_subset.rb +5 -0
  31. data/app/tasks/maintenance/atlas_engine/elasticsearch_index_create_task.rb +1 -1
  32. data/db/data/country_profiles/default.yml +0 -2
  33. data/lib/atlas_engine/version.rb +1 -1
  34. metadata +15 -9
@@ -11,22 +11,23 @@ module AtlasEngine
11
11
  extend T::Sig
12
12
 
13
13
  BM_PARISH_AND_CITY_NAMES = {
14
- "Devonshire" => "Devonshire Parish",
15
- "Hamilton" => "Hamilton Parish",
16
- "Paget" => "Paget Parish",
17
- "Pembroke" => "Pembroke Parish",
18
- "Sandys" => "Sandys Parish",
19
- "Smiths" => "Smiths Parish",
20
- "Southampton" => "Southampton Parish",
21
- "St. George's" => "St. George's Parish",
22
- "Town of St. George" => "St. George",
23
- "Warwick" => "Warwick Parish",
14
+ "City of Hamilton" => ["City of Hamilton", "Hamilton"],
15
+ "Devonshire" => ["Devonshire Parish", "Devonshire"],
16
+ "Hamilton" => ["Hamilton Parish", "Hamilton"],
17
+ "Paget" => ["Paget Parish", "Paget"],
18
+ "Pembroke" => ["Pembroke Parish", "Pembroke"],
19
+ "Sandys" => ["Sandys Parish", "Sandys"],
20
+ "Smiths" => ["Smiths Parish", "Smiths"],
21
+ "Southampton" => ["Southampton Parish", "Southampton"],
22
+ "St. George's" => ["St. George's Parish", "St. George's"],
23
+ "Town of St. George" => ["Town of St. George", "St. George"],
24
+ "Warwick" => ["Warwick Parish", "Warwick"],
24
25
  }.freeze
25
26
 
26
27
  sig { params(address: Hash).void }
27
28
  def apply(address)
28
29
  if BM_PARISH_AND_CITY_NAMES.key?(address[:city][0])
29
- address[:city] << BM_PARISH_AND_CITY_NAMES[address[:city][0]]
30
+ address[:city] = BM_PARISH_AND_CITY_NAMES[address[:city][0]]
30
31
  end
31
32
  end
32
33
  end
@@ -0,0 +1,6 @@
1
+ street_synonyms:
2
+ - lane, ln
3
+ - road, rd
4
+ - street, st
5
+ - avenue, ave
6
+ - drive, drv, dr
@@ -2,6 +2,8 @@ id: CH
2
2
  validation:
3
3
  enabled: true
4
4
  default_matching_strategy: local
5
+ has_provinces: false
6
+ address_parser: AtlasEngine::De::ValidationTranscriber::AddressParser
5
7
  index_locales:
6
8
  - de
7
9
  - fr
@@ -2,7 +2,6 @@ id: CH_DE
2
2
  ingestion:
3
3
  data_mapper: AtlasEngine::AddressValidation::Es::DataMappers::DecompoundingDataMapper
4
4
  validation:
5
- address_parser: AtlasEngine::De::ValidationTranscriber::AddressParser
6
5
  normalized_components:
7
6
  - region2
8
7
  - region3
@@ -0,0 +1,3 @@
1
+ id: CH_FR
2
+ validation:
3
+ address_parser: AtlasEngine::Ch::Locales::Fr::ValidationTranscriber::AddressParser
@@ -0,0 +1,29 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ # French address in Switzerland can be written in the following ways:
5
+ # 1. thoroughfare type[ ]Thoroughfare name[ ]number
6
+ # 2. number[ ]thoroughfare type[ ]Thoroughfare name
7
+
8
+ module AtlasEngine
9
+ module Ch
10
+ module Locales
11
+ module Fr
12
+ module ValidationTranscriber
13
+ class AddressParser < AtlasEngine::ValidationTranscriber::AddressParserBase
14
+ private
15
+
16
+ sig { returns(T::Array[Regexp]) }
17
+ def country_regex_formats
18
+ @country_regex_formats ||=
19
+ [
20
+ /^#{BUILDING_NUM}?\s*#{STREET_NO_COMMAS}$/o,
21
+ /^#{STREET_NO_COMMAS}?\s*#{BUILDING_NUM}$/o,
22
+ ]
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,43 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module AtlasEngine
5
+ module Cz
6
+ module AddressValidation
7
+ module Es
8
+ class QueryBuilder < AtlasEngine::AddressValidation::Es::DefaultQueryBuilder
9
+ private
10
+
11
+ sig { returns(Hash) }
12
+ def street_clause
13
+ street_queries = [build_street_queries, empty_street_clause]
14
+
15
+ {
16
+ "dis_max" => {
17
+ "queries" => street_queries.flatten,
18
+ },
19
+ }
20
+ end
21
+
22
+ sig { returns(Hash) }
23
+ def empty_street_clause
24
+ {
25
+ "bool" => {
26
+ "must_not" => {
27
+ "exists" => {
28
+ "field" => "street",
29
+ },
30
+ },
31
+ },
32
+ }
33
+ end
34
+
35
+ sig { returns(T::Array[String]) }
36
+ def street_query_values
37
+ street_names.presence || []
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -2,5 +2,6 @@ id: CZ
2
2
  validation:
3
3
  enabled: true
4
4
  default_matching_strategy: es
5
- address_parser: AtlasEngine::Dk::ValidationTranscriber::AddressParser
5
+ address_parser: AtlasEngine::Cz::ValidationTranscriber::AddressParser
6
+ query_builder: AtlasEngine::Cz::AddressValidation::Es::QueryBuilder
6
7
  has_provinces: false
@@ -0,0 +1,26 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module AtlasEngine
5
+ module Cz
6
+ module ValidationTranscriber
7
+ class AddressParser < AtlasEngine::ValidationTranscriber::AddressParserBase
8
+ private
9
+
10
+ sig { returns(T::Array[Regexp]) }
11
+ def country_regex_formats
12
+ @country_regex_formats ||= [
13
+ /^#{BUILDING_NUM}$/,
14
+ /^#{STREET_NO_COMMAS}\s+#{BUILDING_NUM}?$/,
15
+ ]
16
+ end
17
+
18
+ def ridiculous?(captures, address)
19
+ return false if captures[:street].blank?
20
+
21
+ address.city == captures[:street]
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -29,7 +29,7 @@ module AtlasEngine
29
29
  city: [city.titleize],
30
30
  suburb: nil,
31
31
  zip: postcode,
32
- street: street.titleize,
32
+ street: street,
33
33
  building_and_unit_ranges: housenumber_and_unit(number, unit),
34
34
  latitude: geometry(feature)&.at(1),
35
35
  longitude: geometry(feature)&.at(0),
@@ -2,6 +2,7 @@ id: IT
2
2
  validation:
3
3
  enabled: true
4
4
  default_matching_strategy: es
5
+ address_parser: AtlasEngine::Dk::ValidationTranscriber::AddressParser
5
6
  ingestion:
6
7
  open_address:
7
8
  feature_mapper: AtlasEngine::It::AddressImporter::OpenAddress::Mapper
@@ -3,7 +3,10 @@ validation:
3
3
  enabled: false
4
4
  default_matching_strategy: es
5
5
  has_provinces: false
6
- restrictions:
6
+ normalized_components:
7
+ - region1
8
+ - city_aliases.alias
9
+ - street
7
10
  restrictions:
8
11
  - class: AtlasEngine::Restrictions::UnsupportedScript
9
12
  params:
@@ -2,8 +2,6 @@ id: US
2
2
  validation:
3
3
  enabled: true
4
4
  default_matching_strategy: es_street
5
- city_fields:
6
- - city_aliases
7
5
  address_parser: AtlasEngine::ValidationTranscriber::AddressParserNorthAmerica
8
6
  ingestion:
9
7
  settings:
@@ -42,7 +42,7 @@ module AtlasEngine
42
42
 
43
43
  sig { returns(T::Array[String]) }
44
44
  def potential_building_numbers
45
- parsings.pluck(:building_num).compact.uniq
45
+ parsings.pluck(:building_num).compact.uniq.reject { |n| n.match?(/\d{7,}/) }
46
46
  end
47
47
 
48
48
  sig { params(address_input: AddressValidation::AbstractAddress).void }
@@ -13,8 +13,8 @@ module AtlasEngine
13
13
 
14
14
  sig { params(haystack: String, needle: String).returns(String) }
15
15
  def strip_word(haystack, needle)
16
- string = haystack.sub(/[\s](#{Regexp.escape(needle)})([\s]|$)/i, " ").strip
17
- string = string.sub(/[\s,](#{Regexp.escape(needle)})([\s,]|$)/i, "").strip
16
+ string = haystack.sub(/([\s]|^)(#{Regexp.escape(needle)})([\s]|$)/i, " ").strip
17
+ string = string.sub(/([\s,]|^)(#{Regexp.escape(needle)})([\s,]|$)/i, "").strip
18
18
  string = strip_trailing_punctuation(string)
19
19
  string || ""
20
20
  end
@@ -20,6 +20,9 @@ module AtlasEngine
20
20
  sig { abstract.returns(T::Hash[T.untyped, T.untyped]) }
21
21
  def validation_response; end
22
22
 
23
+ sig { abstract.returns(CountryProfile) }
24
+ def country_profile; end
25
+
23
26
  sig { abstract.returns(ValidationTranscriber::AddressParsings) }
24
27
  def parsings; end
25
28
  end
@@ -10,7 +10,12 @@ module AtlasEngine
10
10
  include DatastoreBase
11
11
  extend T::Sig
12
12
 
13
+ sig { override.returns(CountryProfile) }
14
+ attr_reader :country_profile
15
+
16
+ sig { override.returns(ValidationTranscriber::AddressParsings) }
13
17
  attr_reader :parsings
18
+
14
19
  attr_writer :candidates # meant for test setup only
15
20
 
16
21
  sig { params(address: AbstractAddress, locale: T.nilable(String)).void }
@@ -21,9 +26,9 @@ module AtlasEngine
21
26
  raise ArgumentError, "address has no country_code" if address.country_code.blank?
22
27
 
23
28
  @country_code = T.must(address.country_code.to_s)
24
- @profile = CountryProfile.for(country_code.to_s.upcase)
29
+ @country_profile = CountryProfile.for(country_code.to_s.upcase, @locale)
25
30
 
26
- if locale.nil? && @profile.validation.multi_locale?
31
+ if locale.nil? && @country_profile.validation.multi_locale?
27
32
  raise ArgumentError, "#{country_code} is a multi-locale country and requires a locale"
28
33
  end
29
34
 
@@ -107,7 +112,7 @@ module AtlasEngine
107
112
 
108
113
  private
109
114
 
110
- attr_reader :address, :country_code, :locale, :profile, :query_builder
115
+ attr_reader :address, :country_code, :locale, :query_builder
111
116
 
112
117
  sig { returns(Token::Sequence) }
113
118
  def fetch_city_sequence_internal
@@ -153,7 +158,7 @@ module AtlasEngine
153
158
 
154
159
  sig { params(candidates: T::Array[Candidate]).void }
155
160
  def assign_term_vectors_to_candidates(candidates)
156
- return if profile.validation.normalized_components.blank?
161
+ return if country_profile.validation.normalized_components.blank?
157
162
 
158
163
  candidate_term_vectors = measure_es_validation_request_time(method: "term_vectors") do
159
164
  repository.term_vectors(term_vectors_query(candidates))
@@ -167,7 +172,7 @@ module AtlasEngine
167
172
  {
168
173
  ids: candidates.map(&:id),
169
174
  parameters: {
170
- fields: profile.validation.normalized_components,
175
+ fields: country_profile.validation.normalized_components,
171
176
  field_statistics: false,
172
177
  },
173
178
  }
@@ -219,7 +224,7 @@ module AtlasEngine
219
224
  FieldDecompounder.new(
220
225
  field: :street,
221
226
  value: street_value,
222
- country_profile: profile,
227
+ country_profile:,
223
228
  ).call,
224
229
  )
225
230
  end
@@ -37,22 +37,15 @@ module AtlasEngine
37
37
  sig { returns(CountryProfile) }
38
38
  attr_reader :profile
39
39
 
40
- sig { returns(Hash) }
40
+ sig { returns(T.nilable(Hash)) }
41
41
  def building_number_clause
42
- potential_building_numbers = @parsings.potential_building_numbers.filter_map do |n|
43
- AddressNumber.new(value: n).to_i
44
- end.uniq
42
+ building_number_clause = approx_building_clauses
45
43
 
46
- building_number_queries = [empty_approx_building_clause]
47
- building_number_queries.unshift(
48
- *T.unsafe(potential_building_numbers.map do |value|
49
- approx_building_clause(value)
50
- end),
51
- ) if potential_building_numbers.any?
44
+ return if building_number_clause.nil?
52
45
 
53
46
  {
54
47
  "dis_max" => {
55
- "queries" => building_number_queries,
48
+ "queries" => building_number_clause,
56
49
  },
57
50
  }
58
51
  end
@@ -68,6 +61,19 @@ module AtlasEngine
68
61
  }
69
62
  end
70
63
 
64
+ sig { returns(T.nilable(Array)) }
65
+ def approx_building_clauses
66
+ potential_building_numbers = @parsings.potential_building_numbers.filter_map do |n|
67
+ AddressNumber.new(value: n).to_i
68
+ end.uniq
69
+
70
+ if potential_building_numbers.any?
71
+ potential_building_numbers.map do |value|
72
+ approx_building_clause(value)
73
+ end
74
+ end
75
+ end
76
+
71
77
  sig { returns(Hash) }
72
78
  def empty_approx_building_clause
73
79
  {
@@ -85,25 +91,30 @@ module AtlasEngine
85
91
  def street_clause
86
92
  {
87
93
  "dis_max" => {
88
- "queries" => street_query_values.map do |value|
89
- {
90
- "match" => {
91
- "street" => { "query" => value, "fuzziness" => "auto" },
92
- },
93
- }
94
- end.union(
95
- stripped_street_query_values.map do |value|
96
- {
97
- "match" => {
98
- "street_stripped" => { "query" => value, "fuzziness" => "auto" },
99
- },
100
- }
101
- end,
102
- ),
94
+ "queries" => build_street_queries,
103
95
  },
104
96
  }
105
97
  end
106
98
 
99
+ sig { returns(Array) }
100
+ def build_street_queries
101
+ street_query_values.map do |value|
102
+ {
103
+ "match" => {
104
+ "street" => { "query" => value, "fuzziness" => "auto" },
105
+ },
106
+ }
107
+ end.union(
108
+ stripped_street_query_values.map do |value|
109
+ {
110
+ "match" => {
111
+ "street_stripped" => { "query" => value, "fuzziness" => "auto" },
112
+ },
113
+ }
114
+ end,
115
+ )
116
+ end
117
+
107
118
  sig { returns(T::Array[String]) }
108
119
  def street_query_values
109
120
  street_names.presence || [address.address1.to_s, address.address2.to_s].compact_blank.uniq
@@ -149,10 +160,10 @@ module AtlasEngine
149
160
  sig { returns(T.nilable(Hash)) }
150
161
  def province_clause
151
162
  {
152
- "term" => {
153
- "province_code" => { "value" => address.province_code.to_s.downcase },
163
+ "match" => {
164
+ "province_code" => { "query" => address.province_code.to_s.downcase },
154
165
  },
155
- } if profile.attributes.dig("validation", "has_provinces")
166
+ } if profile.attributes.dig("validation", "has_provinces") && address.province_code.present?
156
167
  end
157
168
  end
158
169
  end
@@ -80,7 +80,7 @@ module AtlasEngine
80
80
  .returns(T.untyped)
81
81
  end
82
82
  def publish_notification(candidate_result: nil)
83
- ActiveSupport::Notifications.instrument("atlas-engine.address_validation.validation_completed", {
83
+ ActiveSupport::Notifications.instrument("atlas_engine.address_validation.validation_completed", {
84
84
  candidate_result: candidate_result,
85
85
  result: result,
86
86
  }.compact)
@@ -35,6 +35,7 @@ module AtlasEngine
35
35
  end
36
36
  data = {
37
37
  country_code: address.country_code,
38
+ matching_strategy: result.matching_strategy,
38
39
  formatted_address: formatted_address,
39
40
  concerns: concern_codes,
40
41
  suggestions: result.suggestions.map(&:attributes),
@@ -18,15 +18,6 @@ module AtlasEngine
18
18
  .gsub("æ", "ae")
19
19
  .gsub("œ", "oe")
20
20
  .gsub(" ", " ")
21
- # normalizes Arabic characters
22
- .tr("آ", "ا")
23
- .tr("أ", "ا")
24
- .tr("إ", "ا")
25
- .tr("ئ", "ي")
26
- .tr("ة", "ه")
27
- .tr("ى", "ي")
28
- # removes Arabic stretching characters and diacritics
29
- .gsub(/[\u064B|\u064C|\u064D|\u064E|\u064F|\u0650|\u0651|\u0652|\u0640]/, "")
30
21
  # TODO: Strip hyphens for USPS not zip
31
22
  .gsub(/[!@%&"'*,.();:]/, "")
32
23
  .downcase
@@ -9,34 +9,18 @@ module AtlasEngine
9
9
  extend T::Sig
10
10
  include Comparable
11
11
 
12
- attr_reader :street_comparison,
12
+ attr_reader :comparison_helper
13
+
14
+ delegate :street_comparison,
13
15
  :city_comparison,
14
- :zip_comparison,
15
16
  :province_code_comparison,
16
- :building_comparison
17
+ :zip_comparison,
18
+ :building_comparison,
19
+ to: :comparison_helper
17
20
 
18
21
  sig { params(address: AbstractAddress, candidate: Candidate, datastore: DatastoreBase).void }
19
22
  def initialize(address:, candidate:, datastore:)
20
- @street_comparison = ComparisonHelper.street_comparison(
21
- datastore: datastore,
22
- candidate: candidate,
23
- )
24
- @city_comparison = ComparisonHelper.city_comparison(
25
- datastore: datastore,
26
- candidate: candidate,
27
- )
28
- @zip_comparison = ComparisonHelper.zip_comparison(
29
- address: address,
30
- candidate: candidate,
31
- )
32
- @province_code_comparison = ComparisonHelper.province_code_comparison(
33
- address: address,
34
- candidate: candidate,
35
- )
36
- @building_comparison = ComparisonHelper.building_comparison(
37
- datastore: datastore,
38
- candidate: candidate,
39
- )
23
+ @comparison_helper = ComparisonHelper.new(address:, candidate:, datastore:)
40
24
  end
41
25
 
42
26
  sig { params(other: AddressComparison).returns(Integer) }
@@ -9,6 +9,8 @@ module AtlasEngine
9
9
  extend T::Sig
10
10
  include LogHelper
11
11
 
12
+ delegate :street_comparison, to: :address_comparison
13
+
12
14
  sig do
13
15
  params(
14
16
  candidate: AddressValidation::CandidateTuple,
@@ -25,8 +27,8 @@ module AtlasEngine
25
27
 
26
28
  sig { override.void }
27
29
  def update_result
28
- result.candidate = candidate&.serialize
29
- return if unmatched_components.empty?
30
+ result.candidate = candidate.serialize
31
+ return if unmatched_components_to_validate.empty?
30
32
 
31
33
  update_concerns_and_suggestions
32
34
  update_result_scope
@@ -39,8 +41,12 @@ module AtlasEngine
39
41
 
40
42
  private
41
43
 
44
+ sig { returns(Candidate) }
42
45
  attr_reader :candidate
43
46
 
47
+ sig { returns(AddressComparison) }
48
+ attr_reader :address_comparison
49
+
44
50
  sig { void }
45
51
  def update_concerns_and_suggestions
46
52
  if suggestable?
@@ -62,7 +68,7 @@ module AtlasEngine
62
68
 
63
69
  sig { void }
64
70
  def add_concerns_with_suggestions
65
- unmatched_components.keys.each do |unmatched_component|
71
+ unmatched_components_to_validate.keys.each do |unmatched_component|
66
72
  field_name = unmatched_field_name(unmatched_component)
67
73
  if field_name.nil?
68
74
  log_unknown_field_name
@@ -72,7 +78,7 @@ module AtlasEngine
72
78
  concern = ConcernBuilder.new(
73
79
  unmatched_component: unmatched_component,
74
80
  unmatched_field: field_name,
75
- matched_components: matched_components.keys,
81
+ matched_components: matched_components_to_validate.keys,
76
82
  address: session.address,
77
83
  suggestion_ids: [suggestion.id].compact,
78
84
  ).build
@@ -87,7 +93,7 @@ module AtlasEngine
87
93
 
88
94
  @suggestion ||= SuggestionBuilder.from_comparisons(
89
95
  session.address.to_h,
90
- unmatched_components,
96
+ unmatched_components_to_validate,
91
97
  candidate,
92
98
  unmatched_fields,
93
99
  )
@@ -103,11 +109,25 @@ module AtlasEngine
103
109
  @unmatched_components || split_matched_and_unmatched_components.second
104
110
  end
105
111
 
112
+ sig { returns(T::Hash[Symbol, AtlasEngine::AddressValidation::Token::Sequence::Comparison]) }
113
+ def matched_components_to_validate
114
+ matched_components.select do |k, _v|
115
+ components_to_validate.include?(k)
116
+ end
117
+ end
118
+
119
+ sig { returns(T::Hash[Symbol, AtlasEngine::AddressValidation::Token::Sequence::Comparison]) }
120
+ def unmatched_components_to_validate
121
+ unmatched_components.select do |k, _v|
122
+ components_to_validate.include?(k)
123
+ end
124
+ end
125
+
106
126
  sig { returns(T::Hash[Symbol, T.nilable(AtlasEngine::AddressValidation::Token::Sequence::Comparison)]) }
107
127
  def matched_and_unmatched_components
108
128
  components = {}
109
129
  @matched_and_unmatched_components ||= begin
110
- components_to_validate.each do |field|
130
+ components_to_compare.each do |field|
111
131
  components[field] = @address_comparison.send(:"#{field}_comparison")
112
132
  end
113
133
  components
@@ -116,7 +136,17 @@ module AtlasEngine
116
136
 
117
137
  sig { returns(T::Array[Symbol]) }
118
138
  def components_to_validate
119
- ComponentsToValidate.new(session, candidate, street_comparison).run
139
+ relevant_components.components_to_validate
140
+ end
141
+
142
+ sig { returns(T::Array[Symbol]) }
143
+ def components_to_compare
144
+ relevant_components.components_to_compare
145
+ end
146
+
147
+ sig { returns(RelevantComponents) }
148
+ def relevant_components
149
+ @relevant_components ||= RelevantComponents.new(session, candidate, street_comparison)
120
150
  end
121
151
 
122
152
  sig do
@@ -124,24 +154,20 @@ module AtlasEngine
124
154
  T.nilable(AtlasEngine::AddressValidation::Token::Sequence::Comparison)]])
125
155
  end
126
156
  def split_matched_and_unmatched_components
157
+ return @matched_components, @unmatched_components if defined?(@matched_components) &&
158
+ defined?(@unmatched_components)
159
+
127
160
  @matched_components, @unmatched_components = matched_and_unmatched_components.partition do |_, comparison|
128
161
  comparison&.match?
129
162
  end.map(&:to_h)
130
163
  end
131
164
 
132
- sig { returns(T.nilable(AtlasEngine::AddressValidation::Token::Sequence::Comparison)) }
133
- def street_comparison
134
- return @street_comparison if defined?(@street_comparison)
135
-
136
- @street_comparison = @address_comparison.street_comparison
137
- end
138
-
139
165
  sig { params(component: Symbol).returns(T.nilable(Symbol)) }
140
166
  def unmatched_field_name(component)
141
167
  return component unless component == :street
142
- return if unmatched_components[:street].nil?
168
+ return if unmatched_components_to_validate[:street].nil?
143
169
 
144
- original_street = T.must(unmatched_components[:street]).left_sequence.raw_value
170
+ original_street = T.must(unmatched_components_to_validate[:street]).left_sequence.raw_value
145
171
 
146
172
  if session.address.address1.to_s.include?(original_street)
147
173
  :address1