atlas_engine 0.1.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 (298) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +123 -0
  3. data/Rakefile +20 -0
  4. data/app/assets/config/atlas_engine_manifest.js +3 -0
  5. data/app/assets/stylesheets/atlas_engine/application.css +15 -0
  6. data/app/concerns/atlas_engine/handles_blob.rb +26 -0
  7. data/app/concerns/atlas_engine/handles_interruption.rb +22 -0
  8. data/app/controllers/atlas_engine/application_controller.rb +7 -0
  9. data/app/controllers/atlas_engine/connectivity_controller.rb +21 -0
  10. data/app/controllers/atlas_engine/country_imports_controller.rb +73 -0
  11. data/app/controllers/atlas_engine/graphql_controller.rb +59 -0
  12. data/app/countries/atlas_engine/ar/country_profile.yml +9 -0
  13. data/app/countries/atlas_engine/at/address_importer/corrections/open_address/city_corrector.rb +23 -0
  14. data/app/countries/atlas_engine/at/country_profile.yml +24 -0
  15. data/app/countries/atlas_engine/at/index_configuration.yml +63 -0
  16. data/app/countries/atlas_engine/at/synonyms.yml +6 -0
  17. data/app/countries/atlas_engine/at/validation_transcriber/address_parser.rb +58 -0
  18. data/app/countries/atlas_engine/au/address_importer/open_address/filter.rb +26 -0
  19. data/app/countries/atlas_engine/au/address_importer/open_address/mapper.rb +41 -0
  20. data/app/countries/atlas_engine/au/country_profile.yml +13 -0
  21. data/app/countries/atlas_engine/au/synonyms.yml +209 -0
  22. data/app/countries/atlas_engine/au/validation_transcriber/address_parser.rb +121 -0
  23. data/app/countries/atlas_engine/be/country_profile.yml +12 -0
  24. data/app/countries/atlas_engine/bm/address_importer/corrections/open_address/city_alias_corrector.rb +38 -0
  25. data/app/countries/atlas_engine/bm/address_importer/open_address/mapper.rb +40 -0
  26. data/app/countries/atlas_engine/bm/country_profile.yml +12 -0
  27. data/app/countries/atlas_engine/br/country_profile.yml +4 -0
  28. data/app/countries/atlas_engine/ca/country_profile.yml +7 -0
  29. data/app/countries/atlas_engine/ca/synonyms.yml +1615 -0
  30. data/app/countries/atlas_engine/ch/address_importer/corrections/open_address/city_corrector.rb +29 -0
  31. data/app/countries/atlas_engine/ch/address_importer/corrections/open_address/locale_corrector.rb +74 -0
  32. data/app/countries/atlas_engine/ch/address_importer/open_address/mapper.rb +40 -0
  33. data/app/countries/atlas_engine/ch/country_profile.yml +15 -0
  34. data/app/countries/atlas_engine/ch/locales/de/country_profile.yml +15 -0
  35. data/app/countries/atlas_engine/ch/locales/de/index_configuration.yml +63 -0
  36. data/app/countries/atlas_engine/ch/locales/de/synonyms.yml +7 -0
  37. data/app/countries/atlas_engine/ch/locales/fr/synonyms.yml +21 -0
  38. data/app/countries/atlas_engine/cz/country_profile.yml +6 -0
  39. data/app/countries/atlas_engine/de/country_profile.yml +19 -0
  40. data/app/countries/atlas_engine/de/index_configuration.yml +64 -0
  41. data/app/countries/atlas_engine/de/synonyms.yml +2 -0
  42. data/app/countries/atlas_engine/de/validation_transcriber/address_parser.rb +19 -0
  43. data/app/countries/atlas_engine/dk/country_profile.yml +6 -0
  44. data/app/countries/atlas_engine/dk/synonyms.yml +3 -0
  45. data/app/countries/atlas_engine/dk/validation_transcriber/address_parser.rb +21 -0
  46. data/app/countries/atlas_engine/fo/country_profile.yml +5 -0
  47. data/app/countries/atlas_engine/fr/address_importer/corrections/open_address/city_corrector.rb +28 -0
  48. data/app/countries/atlas_engine/fr/country_profile.yml +13 -0
  49. data/app/countries/atlas_engine/fr/synonyms.yml +21 -0
  50. data/app/countries/atlas_engine/fr/validation_transcriber/address_parser.rb +34 -0
  51. data/app/countries/atlas_engine/gb/address_validation/es/query_builder.rb +98 -0
  52. data/app/countries/atlas_engine/gb/country_profile.yml +10 -0
  53. data/app/countries/atlas_engine/gb/validation_transcriber/full_address_parser.rb +164 -0
  54. data/app/countries/atlas_engine/gb/validation_transcriber/parsed_address.rb +120 -0
  55. data/app/countries/atlas_engine/gg/address_validation/validators/full_address/restrictions/unsupported_city.rb +39 -0
  56. data/app/countries/atlas_engine/gg/country_profile.yml +7 -0
  57. data/app/countries/atlas_engine/ie/country_profile.yml +3 -0
  58. data/app/countries/atlas_engine/it/address_importer/corrections/open_address/city_corrector.rb +27 -0
  59. data/app/countries/atlas_engine/it/address_importer/corrections/open_address/province_corrector.rb +29 -0
  60. data/app/countries/atlas_engine/it/address_importer/open_address/mapper.rb +42 -0
  61. data/app/countries/atlas_engine/it/country_profile.yml +11 -0
  62. data/app/countries/atlas_engine/jp/address_validation/es/data_mapper.rb +63 -0
  63. data/app/countries/atlas_engine/jp/country_profile.yml +6 -0
  64. data/app/countries/atlas_engine/kr/address_importer/open_address/mapper.rb +41 -0
  65. data/app/countries/atlas_engine/kr/country_profile.yml +11 -0
  66. data/app/countries/atlas_engine/li/address_importer/corrections/open_address/city_corrector.rb +25 -0
  67. data/app/countries/atlas_engine/li/country_profile.yml +21 -0
  68. data/app/countries/atlas_engine/li/index_configuration.yml +63 -0
  69. data/app/countries/atlas_engine/li/synonyms.yml +6 -0
  70. data/app/countries/atlas_engine/lt/country_profile.yml +6 -0
  71. data/app/countries/atlas_engine/lt/synonyms.yml +7 -0
  72. data/app/countries/atlas_engine/lt/validation_transcriber/address_parser.rb +24 -0
  73. data/app/countries/atlas_engine/lu/address_importer/corrections/open_address/locale_corrector.rb +54 -0
  74. data/app/countries/atlas_engine/lu/country_profile.yml +12 -0
  75. data/app/countries/atlas_engine/nl/address_importer/corrections/open_address/city_corrector.rb +25 -0
  76. data/app/countries/atlas_engine/nl/country_profile.yml +18 -0
  77. data/app/countries/atlas_engine/nl/index_configuration.yml +52 -0
  78. data/app/countries/atlas_engine/nl/synonyms.yml +92 -0
  79. data/app/countries/atlas_engine/nl/validation_transcriber/address_parser.rb +85 -0
  80. data/app/countries/atlas_engine/no/country_profile.yml +5 -0
  81. data/app/countries/atlas_engine/nz/country_profile.yml +3 -0
  82. data/app/countries/atlas_engine/pl/country_profile.yml +5 -0
  83. data/app/countries/atlas_engine/pl/validation_transcriber/address_parser.rb +19 -0
  84. data/app/countries/atlas_engine/pt/address_importer/corrections/open_address/city_corrector.rb +32 -0
  85. data/app/countries/atlas_engine/pt/address_importer/open_address/mapper.rb +39 -0
  86. data/app/countries/atlas_engine/pt/country_profile.yml +10 -0
  87. data/app/countries/atlas_engine/pt/synonyms.yml +7 -0
  88. data/app/countries/atlas_engine/sa/country_profile.yml +10 -0
  89. data/app/countries/atlas_engine/se/country_profile.yml +5 -0
  90. data/app/countries/atlas_engine/tt/address_importer/open_address/mapper.rb +38 -0
  91. data/app/countries/atlas_engine/tt/country_profile.yml +7 -0
  92. data/app/countries/atlas_engine/us/country_profile.yml +12 -0
  93. data/app/countries/atlas_engine/us/synonyms.yml +350 -0
  94. data/app/graphql/atlas_engine/errors/locale_unsupported_error.rb +17 -0
  95. data/app/graphql/atlas_engine/schema.graphql +1293 -0
  96. data/app/graphql/atlas_engine/schema.rb +23 -0
  97. data/app/graphql/atlas_engine/types/address_validation/address_input.rb +51 -0
  98. data/app/graphql/atlas_engine/types/address_validation/concern_type.rb +20 -0
  99. data/app/graphql/atlas_engine/types/address_validation/enums/concern_enum.rb +15 -0
  100. data/app/graphql/atlas_engine/types/address_validation/field_type.rb +15 -0
  101. data/app/graphql/atlas_engine/types/address_validation/suggestion_type.rb +21 -0
  102. data/app/graphql/atlas_engine/types/base_argument.rb +9 -0
  103. data/app/graphql/atlas_engine/types/base_enum.rb +9 -0
  104. data/app/graphql/atlas_engine/types/base_field.rb +10 -0
  105. data/app/graphql/atlas_engine/types/base_input_object.rb +9 -0
  106. data/app/graphql/atlas_engine/types/base_interface.rb +10 -0
  107. data/app/graphql/atlas_engine/types/base_object.rb +9 -0
  108. data/app/graphql/atlas_engine/types/base_scalar.rb +9 -0
  109. data/app/graphql/atlas_engine/types/base_union.rb +9 -0
  110. data/app/graphql/atlas_engine/types/matching_strategy_type.rb +12 -0
  111. data/app/graphql/atlas_engine/types/mutation_type.rb +9 -0
  112. data/app/graphql/atlas_engine/types/query_type.rb +61 -0
  113. data/app/graphql/atlas_engine/types/validation_supported_country.rb +12 -0
  114. data/app/graphql/atlas_engine/types/validation_type.rb +22 -0
  115. data/app/helpers/atlas_engine/address_importer/import_log_helper.rb +66 -0
  116. data/app/helpers/atlas_engine/application_helper.rb +7 -0
  117. data/app/helpers/atlas_engine/locale_format_helper.rb +40 -0
  118. data/app/helpers/atlas_engine/log_base.rb +32 -0
  119. data/app/helpers/atlas_engine/log_helper.rb +24 -0
  120. data/app/helpers/atlas_engine/metrics_helper.rb +25 -0
  121. data/app/jobs/atlas_engine/address_importer/clear_records_job.rb +39 -0
  122. data/app/jobs/atlas_engine/address_importer/open_address/geo_json_import_job.rb +212 -0
  123. data/app/jobs/atlas_engine/address_importer/open_address/geo_json_import_launcher_job.rb +67 -0
  124. data/app/jobs/atlas_engine/address_importer/open_address/prepares_geo_json_file.rb +41 -0
  125. data/app/jobs/atlas_engine/address_importer/resumable_import_job.rb +49 -0
  126. data/app/jobs/atlas_engine/address_importer/street_backfill_job.rb +63 -0
  127. data/app/jobs/atlas_engine/application_job.rb +10 -0
  128. data/app/jobs/atlas_engine/concerns/address_importer/handles_errors.rb +43 -0
  129. data/app/lib/atlas_engine/concern_formatter.rb +40 -0
  130. data/app/lib/atlas_engine/restrictions/base.rb +20 -0
  131. data/app/lib/atlas_engine/restrictions/unsupported_script.rb +31 -0
  132. data/app/lib/atlas_engine/validation_transcriber/address_parser_base.rb +201 -0
  133. data/app/lib/atlas_engine/validation_transcriber/address_parser_factory.rb +27 -0
  134. data/app/lib/atlas_engine/validation_transcriber/address_parser_north_america.rb +39 -0
  135. data/app/lib/atlas_engine/validation_transcriber/address_parser_oceanic.rb +17 -0
  136. data/app/lib/atlas_engine/validation_transcriber/address_parser_preprocessor.rb +132 -0
  137. data/app/lib/atlas_engine/validation_transcriber/address_parsing_helper.rb +38 -0
  138. data/app/lib/atlas_engine/validation_transcriber/address_parsings.rb +54 -0
  139. data/app/lib/atlas_engine/validation_transcriber/constants.rb +50 -0
  140. data/app/lib/atlas_engine/validation_transcriber/english_street_parser.rb +59 -0
  141. data/app/lib/atlas_engine/validation_transcriber/formatter.rb +46 -0
  142. data/app/lib/atlas_engine/validation_transcriber/french_street_parser.rb +50 -0
  143. data/app/lib/atlas_engine/validation_transcriber/province_code_normalizer.rb +45 -0
  144. data/app/lib/atlas_engine/validation_transcriber/street_parser.rb +18 -0
  145. data/app/lib/atlas_engine/validation_transcriber/zip_normalizer.rb +23 -0
  146. data/app/mailers/atlas_engine/application_mailer.rb +9 -0
  147. data/app/models/atlas_engine/address_importer/corrections/corrector.rb +33 -0
  148. data/app/models/atlas_engine/address_importer/import_events_notifier/base.rb +35 -0
  149. data/app/models/atlas_engine/address_importer/import_events_notifier/notifier.rb +26 -0
  150. data/app/models/atlas_engine/address_importer/open_address/default_mapper.rb +46 -0
  151. data/app/models/atlas_engine/address_importer/open_address/feature_helper.rb +110 -0
  152. data/app/models/atlas_engine/address_importer/open_address/filter.rb +17 -0
  153. data/app/models/atlas_engine/address_importer/open_address/loader.rb +27 -0
  154. data/app/models/atlas_engine/address_importer/open_address/transformer.rb +39 -0
  155. data/app/models/atlas_engine/address_importer/open_address.rb +10 -0
  156. data/app/models/atlas_engine/address_importer/validation/base_validator.rb +86 -0
  157. data/app/models/atlas_engine/address_importer/validation/default_validator.rb +27 -0
  158. data/app/models/atlas_engine/address_importer/validation/field_validations/city.rb +47 -0
  159. data/app/models/atlas_engine/address_importer/validation/field_validations/interface.rb +29 -0
  160. data/app/models/atlas_engine/address_importer/validation/field_validations/province.rb +73 -0
  161. data/app/models/atlas_engine/address_importer/validation/field_validations/zip.rb +84 -0
  162. data/app/models/atlas_engine/address_importer/validation/validator.rb +17 -0
  163. data/app/models/atlas_engine/address_importer/validation/wrapper.rb +70 -0
  164. data/app/models/atlas_engine/address_number.rb +36 -0
  165. data/app/models/atlas_engine/address_number_range.rb +200 -0
  166. data/app/models/atlas_engine/address_validation/abstract_address.rb +49 -0
  167. data/app/models/atlas_engine/address_validation/address.rb +47 -0
  168. data/app/models/atlas_engine/address_validation/candidate.rb +109 -0
  169. data/app/models/atlas_engine/address_validation/candidate_tuple.rb +15 -0
  170. data/app/models/atlas_engine/address_validation/concern.rb +74 -0
  171. data/app/models/atlas_engine/address_validation/concern_producer.rb +19 -0
  172. data/app/models/atlas_engine/address_validation/concern_queue.rb +20 -0
  173. data/app/models/atlas_engine/address_validation/concern_record.rb +122 -0
  174. data/app/models/atlas_engine/address_validation/datastore_base.rb +27 -0
  175. data/app/models/atlas_engine/address_validation/errors.rb +13 -0
  176. data/app/models/atlas_engine/address_validation/es/candidate_selector.rb +70 -0
  177. data/app/models/atlas_engine/address_validation/es/data_mappers/decompounding_data_mapper.rb +39 -0
  178. data/app/models/atlas_engine/address_validation/es/data_mappers/default_data_mapper.rb +110 -0
  179. data/app/models/atlas_engine/address_validation/es/datastore.rb +229 -0
  180. data/app/models/atlas_engine/address_validation/es/default_query_builder.rb +30 -0
  181. data/app/models/atlas_engine/address_validation/es/query_builder.rb +160 -0
  182. data/app/models/atlas_engine/address_validation/es/term_vectors.rb +78 -0
  183. data/app/models/atlas_engine/address_validation/es/validators/full_address.rb +123 -0
  184. data/app/models/atlas_engine/address_validation/es/validators/full_address_street.rb +18 -0
  185. data/app/models/atlas_engine/address_validation/es/validators/restriction_evaluator.rb +37 -0
  186. data/app/models/atlas_engine/address_validation/field.rb +30 -0
  187. data/app/models/atlas_engine/address_validation/full_address_validator_base.rb +27 -0
  188. data/app/models/atlas_engine/address_validation/log_emitter.rb +66 -0
  189. data/app/models/atlas_engine/address_validation/matching_strategies.rb +16 -0
  190. data/app/models/atlas_engine/address_validation/normalizer.rb +38 -0
  191. data/app/models/atlas_engine/address_validation/predicate_pipeline.rb +80 -0
  192. data/app/models/atlas_engine/address_validation/request.rb +12 -0
  193. data/app/models/atlas_engine/address_validation/result.rb +154 -0
  194. data/app/models/atlas_engine/address_validation/runs_validation.rb +16 -0
  195. data/app/models/atlas_engine/address_validation/session.rb +47 -0
  196. data/app/models/atlas_engine/address_validation/statsd_emitter.rb +72 -0
  197. data/app/models/atlas_engine/address_validation/strategies.rb +10 -0
  198. data/app/models/atlas_engine/address_validation/suggestion.rb +97 -0
  199. data/app/models/atlas_engine/address_validation/token/comparator.rb +44 -0
  200. data/app/models/atlas_engine/address_validation/token/comparison.rb +76 -0
  201. data/app/models/atlas_engine/address_validation/token/sequence/comparator.rb +158 -0
  202. data/app/models/atlas_engine/address_validation/token/sequence/comparison.rb +166 -0
  203. data/app/models/atlas_engine/address_validation/token/sequence.rb +147 -0
  204. data/app/models/atlas_engine/address_validation/token/synonyms.rb +77 -0
  205. data/app/models/atlas_engine/address_validation/token.rb +113 -0
  206. data/app/models/atlas_engine/address_validation/validator.rb +147 -0
  207. data/app/models/atlas_engine/address_validation/validators/full_address/address_comparison.rb +97 -0
  208. data/app/models/atlas_engine/address_validation/validators/full_address/candidate_result.rb +164 -0
  209. data/app/models/atlas_engine/address_validation/validators/full_address/candidate_result_base.rb +46 -0
  210. data/app/models/atlas_engine/address_validation/validators/full_address/comparison_helper.rb +135 -0
  211. data/app/models/atlas_engine/address_validation/validators/full_address/components_to_validate.rb +88 -0
  212. data/app/models/atlas_engine/address_validation/validators/full_address/concern_builder.rb +127 -0
  213. data/app/models/atlas_engine/address_validation/validators/full_address/exclusions/exclusion_base.rb +23 -0
  214. data/app/models/atlas_engine/address_validation/validators/full_address/invalid_zip_concern_builder.rb +42 -0
  215. data/app/models/atlas_engine/address_validation/validators/full_address/invalid_zip_for_country_concern.rb +37 -0
  216. data/app/models/atlas_engine/address_validation/validators/full_address/invalid_zip_for_province_concern.rb +37 -0
  217. data/app/models/atlas_engine/address_validation/validators/full_address/no_candidate_result.rb +26 -0
  218. data/app/models/atlas_engine/address_validation/validators/full_address/number_comparison.rb +31 -0
  219. data/app/models/atlas_engine/address_validation/validators/full_address/postal_code_matcher.rb +60 -0
  220. data/app/models/atlas_engine/address_validation/validators/full_address/result_updater.rb +42 -0
  221. data/app/models/atlas_engine/address_validation/validators/full_address/suggestion_builder.rb +140 -0
  222. data/app/models/atlas_engine/address_validation/validators/full_address/unknown_address_concern.rb +30 -0
  223. data/app/models/atlas_engine/address_validation/validators/full_address/unknown_province_concern.rb +38 -0
  224. data/app/models/atlas_engine/address_validation/validators/full_address/unknown_zip_for_address_concern.rb +32 -0
  225. data/app/models/atlas_engine/address_validation/validators/full_address/unmatched_field_concern.rb +84 -0
  226. data/app/models/atlas_engine/address_validation/validators/full_address/unsupported_script_result.rb +22 -0
  227. data/app/models/atlas_engine/address_validation/validators/predicates/cache.rb +38 -0
  228. data/app/models/atlas_engine/address_validation/validators/predicates/city/present.rb +36 -0
  229. data/app/models/atlas_engine/address_validation/validators/predicates/country/exists.rb +34 -0
  230. data/app/models/atlas_engine/address_validation/validators/predicates/country/valid_for_zip.rb +60 -0
  231. data/app/models/atlas_engine/address_validation/validators/predicates/no_emojis.rb +38 -0
  232. data/app/models/atlas_engine/address_validation/validators/predicates/no_html_tags.rb +39 -0
  233. data/app/models/atlas_engine/address_validation/validators/predicates/no_url.rb +38 -0
  234. data/app/models/atlas_engine/address_validation/validators/predicates/not_exceed_max_length.rb +34 -0
  235. data/app/models/atlas_engine/address_validation/validators/predicates/not_exceed_max_token_count.rb +63 -0
  236. data/app/models/atlas_engine/address_validation/validators/predicates/phone/valid.rb +41 -0
  237. data/app/models/atlas_engine/address_validation/validators/predicates/predicate.rb +37 -0
  238. data/app/models/atlas_engine/address_validation/validators/predicates/province/exists.rb +43 -0
  239. data/app/models/atlas_engine/address_validation/validators/predicates/province/valid_for_country.rb +48 -0
  240. data/app/models/atlas_engine/address_validation/validators/predicates/street/building_number_in_address1.rb +45 -0
  241. data/app/models/atlas_engine/address_validation/validators/predicates/street/building_number_in_address1_or_address2.rb +43 -0
  242. data/app/models/atlas_engine/address_validation/validators/predicates/street/present.rb +35 -0
  243. data/app/models/atlas_engine/address_validation/validators/predicates/zip/present.rb +58 -0
  244. data/app/models/atlas_engine/address_validation/validators/predicates/zip/valid_for_country.rb +45 -0
  245. data/app/models/atlas_engine/address_validation/validators/predicates/zip/valid_for_province.rb +55 -0
  246. data/app/models/atlas_engine/address_validation/validators/predicates/zip/zip_base.rb +25 -0
  247. data/app/models/atlas_engine/address_validation/zip_truncator.rb +32 -0
  248. data/app/models/atlas_engine/application_record.rb +8 -0
  249. data/app/models/atlas_engine/coded_error.rb +18 -0
  250. data/app/models/atlas_engine/coded_errors.rb +17 -0
  251. data/app/models/atlas_engine/country_import.rb +44 -0
  252. data/app/models/atlas_engine/country_profile.rb +270 -0
  253. data/app/models/atlas_engine/country_profile_ingestion_subset.rb +42 -0
  254. data/app/models/atlas_engine/country_profile_subset_base.rb +22 -0
  255. data/app/models/atlas_engine/country_profile_validation_subset.rb +48 -0
  256. data/app/models/atlas_engine/country_repository.rb +110 -0
  257. data/app/models/atlas_engine/elasticsearch/client.rb +116 -0
  258. data/app/models/atlas_engine/elasticsearch/client_interface.rb +89 -0
  259. data/app/models/atlas_engine/elasticsearch/repository.rb +246 -0
  260. data/app/models/atlas_engine/elasticsearch/repository_interface.rb +82 -0
  261. data/app/models/atlas_engine/elasticsearch/response.rb +20 -0
  262. data/app/models/atlas_engine/event.rb +12 -0
  263. data/app/models/atlas_engine/field_decompounder.rb +36 -0
  264. data/app/models/atlas_engine/index_configuration_factory.rb +188 -0
  265. data/app/models/atlas_engine/post_address.rb +114 -0
  266. data/app/models/atlas_engine/post_address_importer.rb +34 -0
  267. data/app/models/atlas_engine/services/service_helper.rb +21 -0
  268. data/app/models/atlas_engine/services/validation.rb +65 -0
  269. data/app/models/atlas_engine/services/validation_eligibility.rb +18 -0
  270. data/app/models/atlas_engine/street.rb +34 -0
  271. data/app/tasks/maintenance/atlas_engine/elasticsearch_index_create_task.rb +106 -0
  272. data/app/tasks/maintenance/atlas_engine/geo_json_import_task.rb +29 -0
  273. data/app/views/atlas_engine/connectivity/index.html.erb +50 -0
  274. data/app/views/atlas_engine/country_imports/index.html.erb +49 -0
  275. data/app/views/atlas_engine/country_imports/show.html.erb +73 -0
  276. data/app/views/layouts/atlas_engine/application.html.erb +15 -0
  277. data/config/initializers/1.ruby_patches.rb +18 -0
  278. data/config/initializers/sorbet.rb +5 -0
  279. data/config/initializers/worldwide.rb +5 -0
  280. data/config/locales/internal/en.yml +14 -0
  281. data/config/routes.rb +17 -0
  282. data/db/data/address_synonyms/index_configurations/default.yml +141 -0
  283. data/db/data/country_profiles/default.yml +23 -0
  284. data/db/data/transcriber.yml +760 -0
  285. data/db/data/validation_pipelines/es.yml +58 -0
  286. data/db/data/validation_pipelines/es_street.yml +58 -0
  287. data/db/data/validation_pipelines/local.yml +60 -0
  288. data/db/migrate/20230919173037_create_atlas_engine_post_addresses.rb +25 -0
  289. data/db/migrate/20231117142735_add_building_and_unit_ranges_column.rb +7 -0
  290. data/db/migrate/20231117143536_create_atlas_engine_country_imports.rb +11 -0
  291. data/db/migrate/20231117145844_create_atlas_engine_events_table.rb +13 -0
  292. data/db/migrate/20231123153554_add_unique_index_to_atlas_engine_post_addresses.rb +14 -0
  293. data/db/migrate/20231123154658_add_index_to_post_addresses_on_source_id_locale_country_code.rb +12 -0
  294. data/lib/atlas_engine/engine.rb +10 -0
  295. data/lib/atlas_engine/version.rb +6 -0
  296. data/lib/atlas_engine.rb +66 -0
  297. data/lib/tasks/atlas_engine/address_importer.rake +20 -0
  298. metadata +553 -0
@@ -0,0 +1,164 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AtlasEngine
5
+ module Gb
6
+ module ValidationTranscriber
7
+ class FullAddressParser
8
+ extend T::Sig
9
+ include AtlasEngine::ValidationTranscriber::Formatter
10
+
11
+ sig { params(address: AtlasEngine::AddressValidation::AbstractAddress).void }
12
+ def initialize(address:)
13
+ @address = address
14
+ end
15
+
16
+ # Note that parse() returns an array of possible interpretations, because it's sometimes
17
+ # impossible to be sure how to classify some parts of an address without more context.
18
+ #
19
+ # Consider the following two examples.
20
+ #
21
+ # Example 1:
22
+ # 2 Elm Avenue [building_num] [dependent_street]
23
+ # Runcorn Road [street]
24
+ # BIRMINGHAM [post_town]
25
+ # B12 8QX [zip]
26
+ #
27
+ # Example 2:
28
+ # 1 Liechrhyd Terrace [building_num] [street]
29
+ # Builth Road [dependent_locality]
30
+ # BUILTH WELLS [post_town]
31
+ # LD2 3PY [zip]
32
+ #
33
+ # In the first example, "Runcorn Road" is thoroughfare, and "Elm Avenue" is a dependent thoroughfare.
34
+ # In the second example, "Builth Road" is a dependent locality (hamlet), not a thoroughfare.
35
+ #
36
+ sig { returns(T::Array[ValidationTranscriber::ParsedAddress]) }
37
+ def parse
38
+ city = @address.city
39
+ if city.present?
40
+ city_parts = city.split(",").map(&:strip)
41
+ post_town = city_parts.first
42
+ if city_parts.count > 1
43
+ county = city_parts[1..-1]&.join(", ")
44
+ end
45
+ end
46
+
47
+ parsed_address = ValidationTranscriber::ParsedAddress.new(
48
+ zip: @address.zip,
49
+ province_code: @address.province_code,
50
+ country_code: @address.country_code || "GB",
51
+ post_town: post_town,
52
+ county: county,
53
+ )
54
+
55
+ # Split address1 and address2 on both commas and newlines
56
+ components = split_into_components(@address)
57
+
58
+ pivot = components.count > 3 ? 3 : components.length
59
+ pivot.downto(1).map do |pivot_value|
60
+ street_components, locality_components = components.partition.with_index do |_, index|
61
+ index <= components.count - pivot_value
62
+ end
63
+ hypothesize(
64
+ street_components: street_components,
65
+ locality_components: locality_components,
66
+ parsed_fields: parsed_address,
67
+ )
68
+ end.flatten
69
+ end
70
+
71
+ private
72
+
73
+ sig do
74
+ params(
75
+ conjecture: T::Hash[Symbol, String],
76
+ double_dependent_locality: T.nilable(String),
77
+ dependent_locality: T.nilable(String),
78
+ parsed_fields: ValidationTranscriber::ParsedAddress,
79
+ ).returns(ValidationTranscriber::ParsedAddress)
80
+ end
81
+ def address_from_conjecture(
82
+ conjecture:,
83
+ double_dependent_locality:,
84
+ dependent_locality:,
85
+ parsed_fields:
86
+ )
87
+ building_num = conjecture[:building_num]
88
+ unit_type = conjecture[:unit_type]
89
+ unit_num = conjecture[:unit_num]
90
+
91
+ if conjecture[:street].present?
92
+ street_parts = T.must(conjecture[:street]).split(",").map(&:strip)
93
+ if street_parts.count >= 2
94
+ dependent_street = street_parts.first
95
+ street = T.must(street_parts[1..-1]).join(", ")
96
+ else
97
+ street = street_parts.first
98
+ end
99
+ end
100
+
101
+ candidate = parsed_fields.dup
102
+
103
+ candidate.building_num = building_num if building_num.present?
104
+ candidate.dependent_street = dependent_street if dependent_street.present?
105
+ candidate.street = street if street.present?
106
+ candidate.unit_type = unit_type if unit_type.present?
107
+ candidate.unit_num = unit_num if unit_num.present?
108
+ candidate.double_dependent_locality = double_dependent_locality if double_dependent_locality.present?
109
+ candidate.dependent_locality = dependent_locality if dependent_locality.present?
110
+
111
+ candidate
112
+ end
113
+
114
+ sig do
115
+ params(
116
+ street_components: T::Array[String],
117
+ locality_components: T::Array[String],
118
+ parsed_fields: ValidationTranscriber::ParsedAddress,
119
+ ).returns(T::Array[ValidationTranscriber::ParsedAddress])
120
+ end
121
+ def hypothesize(street_components:, locality_components:, parsed_fields:)
122
+ double_dependent_locality = locality_components.first if locality_components.count >= 2
123
+ dependent_locality = locality_components.last if locality_components.count >= 1
124
+
125
+ address_line = street_components.join(", ")
126
+ conjectures = if parsed_fields.country_code.present?
127
+ AtlasEngine::ValidationTranscriber::AddressParserFactory.create(
128
+ address: build_address(
129
+ address1: address_line,
130
+ country_code: parsed_fields.country_code.to_s,
131
+ ),
132
+ ).parse
133
+ end
134
+
135
+ if conjectures.blank?
136
+ conjectures = [{ street: address_line }]
137
+ end
138
+
139
+ conjectures.map do |conjecture|
140
+ address_from_conjecture(
141
+ conjecture: conjecture,
142
+ double_dependent_locality: double_dependent_locality,
143
+ dependent_locality: dependent_locality,
144
+ parsed_fields: parsed_fields,
145
+ )
146
+ end
147
+ end
148
+
149
+ # Identify and return the "components" of the address
150
+ # These are portions of the address1 and/or address2 lines that have been separated by
151
+ # line break and/or by commas.
152
+ # For example,
153
+ # 123 High Street, Flat 4
154
+ # Lower Hangleton, Swindon
155
+ # will return 4 components:
156
+ # ["123 High Street", "Flat 4", "Lower Hangleton", "Swindon"]
157
+ sig { params(address: AtlasEngine::AddressValidation::AbstractAddress).returns(T::Array[String]) }
158
+ def split_into_components(address)
159
+ [address.address1&.split(","), address.address2&.split(",")].flatten.compact.map(&:strip)
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,120 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AtlasEngine
5
+ module Gb
6
+ module ValidationTranscriber
7
+ class ParsedAddress
8
+ extend T::Sig
9
+
10
+ sig { returns(T.nilable(String)) }
11
+ attr_accessor :building_num # may be alphanumeric, e.g. "2A"
12
+
13
+ sig { returns(T.nilable(String)) }
14
+ attr_accessor :dependent_street # what Royal Mail calls a dependent thoroughfare
15
+
16
+ sig { returns(T.nilable(String)) }
17
+ attr_accessor :street # what Royal Mail calls a thoroughfare
18
+
19
+ sig { returns(T.nilable(String)) }
20
+ attr_accessor :unit_type
21
+
22
+ sig { returns(T.nilable(String)) }
23
+ attr_accessor :unit_num
24
+
25
+ sig { returns(T.nilable(String)) }
26
+ attr_accessor :double_dependent_locality
27
+
28
+ sig { returns(T.nilable(String)) }
29
+ attr_accessor :dependent_locality
30
+
31
+ sig { returns(T.nilable(String)) }
32
+ attr_accessor :post_town # the :city field may contain "{post_town}, {county}"
33
+
34
+ sig { returns(T.nilable(String)) }
35
+ attr_accessor :county # deprecated in 1996, but still permitted
36
+
37
+ sig { returns(T.nilable(String)) }
38
+ attr_accessor :province_code
39
+
40
+ sig { returns(T.any(Symbol, String)) }
41
+ attr_accessor :country_code
42
+
43
+ sig { returns(T.nilable(String)) }
44
+ attr_accessor :zip
45
+
46
+ sig do
47
+ params(
48
+ country_code: T.any(Symbol, String),
49
+ building_num: T.nilable(String),
50
+ dependent_street: T.nilable(String),
51
+ street: T.nilable(String),
52
+ unit_type: T.nilable(String),
53
+ unit_num: T.nilable(String),
54
+ double_dependent_locality: T.nilable(String),
55
+ dependent_locality: T.nilable(String),
56
+ post_town: T.nilable(String),
57
+ county: T.nilable(String),
58
+ province_code: T.nilable(String),
59
+ zip: T.nilable(String),
60
+ ).void
61
+ end
62
+ def initialize(
63
+ country_code:,
64
+ building_num: nil,
65
+ dependent_street: nil,
66
+ street: nil,
67
+ unit_type: nil,
68
+ unit_num: nil,
69
+ double_dependent_locality: nil,
70
+ dependent_locality: nil,
71
+ post_town: nil,
72
+ county: nil,
73
+ province_code: nil,
74
+ zip: nil
75
+ )
76
+ @building_num = building_num
77
+ @dependent_street = dependent_street
78
+ @street = street
79
+ @unit_type = unit_type
80
+ @unit_num = unit_num
81
+ @double_dependent_locality = double_dependent_locality
82
+ @dependent_locality = dependent_locality
83
+ @post_town = post_town
84
+ @county = county
85
+ @province_code = province_code
86
+ @country_code = country_code
87
+ @zip = zip
88
+ end
89
+
90
+ sig { params(other: ParsedAddress).returns(T::Boolean) }
91
+ def ==(other)
92
+ @country_code.presence == other.country_code.presence &&
93
+ @building_num.presence == other.building_num.presence &&
94
+ @dependent_street.presence == other.dependent_street.presence &&
95
+ @street.presence == other.street.presence &&
96
+ @unit_type.presence == other.unit_type.presence &&
97
+ @unit_num.presence == other.unit_num.presence &&
98
+ @double_dependent_locality.presence == other.double_dependent_locality.presence &&
99
+ @dependent_locality.presence == other.dependent_locality.presence &&
100
+ @post_town.presence == other.post_town.presence &&
101
+ @county.presence == other.county.presence &&
102
+ @zip.presence == other.zip.presence &&
103
+
104
+ # If no province is given in GB, we'll infer it with a postcode lookup
105
+ (
106
+ @province_code.presence == other.province_code.presence ||
107
+ inferred_province_code == other.send(:inferred_province_code)
108
+ )
109
+ end
110
+
111
+ private
112
+
113
+ sig { returns(T.nilable(String)) }
114
+ def inferred_province_code
115
+ @province_code.presence || Worldwide.region(code: @country_code)&.zone(zip: @zip)&.legacy_code
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,39 @@
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 Restrictions
10
+ class UnsupportedCity
11
+ UNSUPPORTED_CITY_ZIP_MAPPING = {
12
+ "SARK" => "GY9",
13
+ "ALDERNEY" => "GY10",
14
+ }.freeze
15
+
16
+ class << self
17
+ extend T::Sig
18
+ include AtlasEngine::Restrictions::Base
19
+
20
+ sig do
21
+ override.params(
22
+ address: AtlasEngine::AddressValidation::AbstractAddress,
23
+ params: T.untyped,
24
+ ).returns(T::Boolean)
25
+ end
26
+ def apply?(address:, params: nil)
27
+ zip_prefix = UNSUPPORTED_CITY_ZIP_MAPPING[address.city&.upcase]
28
+ return false if zip_prefix.nil?
29
+
30
+ address.zip&.start_with?(zip_prefix).present?
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,7 @@
1
+ id: GG
2
+ validation:
3
+ enabled: true
4
+ default_matching_strategy: es
5
+ has_provinces: false
6
+ restrictions:
7
+ - class: AtlasEngine::Gg::AddressValidation::Validators::FullAddress::Restrictions::UnsupportedCity
@@ -0,0 +1,3 @@
1
+ id: IE
2
+ ingestion:
3
+ allow_partial_zip?: true
@@ -0,0 +1,27 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module AtlasEngine
5
+ module It
6
+ module AddressImporter
7
+ module Corrections
8
+ module OpenAddress
9
+ class CityCorrector
10
+ class << self
11
+ extend T::Sig
12
+
13
+ sig { params(address: Hash).void }
14
+ def apply(address)
15
+ if address[:city] == ["Sissa"]
16
+ address[:city] = ["Sissa Trecasali"]
17
+ elsif address[:city] == ["Reggio Nell'emilia"]
18
+ address[:city] << "Reggio Emilia"
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,29 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module AtlasEngine
5
+ module It
6
+ module AddressImporter
7
+ module Corrections
8
+ module OpenAddress
9
+ class ProvinceCorrector
10
+ class << self
11
+ extend T::Sig
12
+
13
+ sig { params(address: Hash).void }
14
+ def apply(address)
15
+ if address[:region2] == "BOLZANO/BOZEN"
16
+ address[:province_code] = "BZ"
17
+ elsif address[:region2] == "FORLI'-CESENA"
18
+ address[:province_code] = "FC"
19
+ elsif address[:region2] == "REGGIO DI CALABRIA"
20
+ address[:province_code] = "RC"
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,42 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module AtlasEngine
5
+ module It
6
+ module AddressImporter
7
+ module OpenAddress
8
+ class Mapper < AtlasEngine::AddressImporter::OpenAddress::DefaultMapper
9
+ sig do
10
+ params(feature: AtlasEngine::AddressImporter::OpenAddress::Feature).returns(T::Hash[Symbol, T.untyped])
11
+ end
12
+ def map(feature)
13
+ region, district, city, street, number, unit, postcode = feature["properties"].values_at(
14
+ "region",
15
+ "district",
16
+ "city",
17
+ "street",
18
+ "number",
19
+ "unit",
20
+ "postcode",
21
+ )
22
+ {
23
+ source_id: openaddress_source_id(feature),
24
+ locale: @locale,
25
+ country_code: "IT",
26
+ province_code: province_code_from_name(district),
27
+ region1: region,
28
+ region2: district,
29
+ city: [city.titleize],
30
+ suburb: nil,
31
+ zip: postcode,
32
+ street: street.titleize,
33
+ building_and_unit_ranges: housenumber_and_unit(number, unit),
34
+ latitude: geometry(feature)&.at(1),
35
+ longitude: geometry(feature)&.at(0),
36
+ }
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,11 @@
1
+ id: IT
2
+ validation:
3
+ enabled: true
4
+ default_matching_strategy: es
5
+ ingestion:
6
+ open_address:
7
+ feature_mapper: AtlasEngine::It::AddressImporter::OpenAddress::Mapper
8
+ correctors:
9
+ open_address:
10
+ - AtlasEngine::It::AddressImporter::Corrections::OpenAddress::CityCorrector
11
+ - AtlasEngine::It::AddressImporter::Corrections::OpenAddress::ProvinceCorrector
@@ -0,0 +1,63 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AtlasEngine
5
+ module Jp
6
+ module AddressValidation
7
+ module Es
8
+ class DataMapper < AtlasEngine::AddressValidation::Es::DataMappers::DefaultDataMapper
9
+ sig do
10
+ returns(T::Hash[Symbol, T.untyped])
11
+ end
12
+ def map_data
13
+ if T.must(locale_language_code.casecmp("en")).zero?
14
+ super.merge(en_modifications)
15
+ else
16
+ super.merge(ja_modifications)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ sig { returns(T::Hash[T.untyped, T.untyped]) }
23
+ def en_modifications
24
+ {
25
+ region3: mapped_region_3,
26
+ city_aliases: city_aliases(mapped_cities),
27
+ street: format_en_street(
28
+ components: [
29
+ mapped_region_3.gsub("Others", ""),
30
+ post_address[:region4],
31
+ ],
32
+ ),
33
+ }
34
+ end
35
+
36
+ sig { returns(T::Hash[T.untyped, T.untyped]) }
37
+ def ja_modifications
38
+ {
39
+ region3: mapped_region_3,
40
+ city_aliases: city_aliases(mapped_cities),
41
+ street: "#{post_address[:region4]}#{mapped_region_3.gsub("その他", "")}",
42
+ }
43
+ end
44
+
45
+ sig { returns(String) }
46
+ def mapped_region_3
47
+ post_address[:city].first
48
+ end
49
+
50
+ sig { returns(T::Array[String]) }
51
+ def mapped_cities
52
+ [post_address[:region3]]
53
+ end
54
+
55
+ sig { params(components: T::Array[T.nilable(String)]).returns(T.nilable(String)) }
56
+ def format_en_street(components:)
57
+ Worldwide.lists.format(components.compact.reject(&:empty?), join: :narrow)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,6 @@
1
+ id: JP
2
+ ingestion:
3
+ data_mapper: AtlasEngine::Jp::AddressValidation::Es::DataMapper
4
+ settings:
5
+ min_zip_edge_ngram: "3"
6
+ max_zip_edge_ngram: "8"
@@ -0,0 +1,41 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module AtlasEngine
5
+ module Kr
6
+ module AddressImporter
7
+ module OpenAddress
8
+ class Mapper < AtlasEngine::AddressImporter::OpenAddress::DefaultMapper
9
+ sig do
10
+ params(feature: AtlasEngine::AddressImporter::OpenAddress::Feature).returns(T::Hash[Symbol, T.untyped])
11
+ end
12
+ def map(feature)
13
+ region, district, city, street, number, unit, postcode = feature["properties"].values_at(
14
+ "region",
15
+ "district",
16
+ "city",
17
+ "street",
18
+ "number",
19
+ "unit",
20
+ "postcode",
21
+ )
22
+ {
23
+ source_id: openaddress_source_id(feature),
24
+ locale: @locale,
25
+ country_code: "KR",
26
+ province_code: province_code_from_name(region),
27
+ region1: region,
28
+ city: [city],
29
+ suburb: district,
30
+ zip: postcode,
31
+ street: street,
32
+ building_and_unit_ranges: housenumber_and_unit(number, unit),
33
+ latitude: geometry(feature)&.at(1),
34
+ longitude: geometry(feature)&.at(0),
35
+ }
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,11 @@
1
+ id: KR
2
+ ingestion:
3
+ open_address:
4
+ feature_mapper: AtlasEngine::Kr::AddressImporter::OpenAddress::Mapper
5
+ validation:
6
+ enabled: true
7
+ default_matching_strategy: es
8
+ restrictions:
9
+ - class: AtlasEngine::Restrictions::UnsupportedScript
10
+ params:
11
+ supported_script: :Hangul
@@ -0,0 +1,25 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module AtlasEngine
5
+ module Li
6
+ module AddressImporter
7
+ module Corrections
8
+ module OpenAddress
9
+ class CityCorrector
10
+ class << self
11
+ extend T::Sig
12
+
13
+ sig { params(address: Hash).void }
14
+ def apply(address)
15
+ if address[:city].include?("Gamprin-Bendern")
16
+ address[:city] += ["Gamprin", "Bendern"]
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,21 @@
1
+ id: LI
2
+ ingestion:
3
+ correctors:
4
+ open_address:
5
+ - AtlasEngine::Li::AddressImporter::Corrections::OpenAddress::CityCorrector
6
+ data_mapper: AtlasEngine::AddressValidation::Es::DataMappers::DecompoundingDataMapper
7
+ validation:
8
+ enabled: true
9
+ has_provinces: true
10
+ default_matching_strategy: es
11
+ address_parser: AtlasEngine::At::ValidationTranscriber::AddressParser
12
+ normalized_components:
13
+ - region2
14
+ - region3
15
+ - region4
16
+ - city_aliases.alias
17
+ - suburb
18
+ - street_decompounded
19
+ decompounding_patterns:
20
+ street:
21
+ - (?<name>\w+)(?<suffix>allee|gasse|kai|lande|pfad|platz|pl|ring|strasse|str|weg|zeile)(?:\b)
@@ -0,0 +1,63 @@
1
+ mappings:
2
+ properties:
3
+ street:
4
+ analyzer: street_indexing_analyzer
5
+ search_analyzer: street_decompounding_analyzer
6
+ street_stripped:
7
+ analyzer: street_indexing_analyzer
8
+ search_analyzer: street_decompounding_analyzer
9
+ street_decompounded:
10
+ type: text
11
+ analyzer: text_analyzer
12
+ fields:
13
+ keyword:
14
+ type: keyword
15
+ settings:
16
+ index:
17
+ analysis:
18
+ analyzer:
19
+ text_analyzer:
20
+ filter:
21
+ - lowercase
22
+ - german_normalization
23
+ - icu_folding
24
+ - strip_special_characters
25
+ street_indexing_analyzer:
26
+ tokenizer: standard
27
+ filter:
28
+ - lowercase
29
+ - german_normalization
30
+ - icu_folding
31
+ - strip_special_characters
32
+ - street_suffix_decompounder
33
+ street_decompounding_analyzer:
34
+ tokenizer: standard
35
+ filter:
36
+ - lowercase
37
+ - german_normalization
38
+ - icu_folding
39
+ - strip_special_characters
40
+ - street_suffix_decompounder
41
+ - street_synonyms
42
+ street_analyzer:
43
+ filter:
44
+ - lowercase
45
+ - german_normalization
46
+ - icu_folding
47
+ - strip_special_characters
48
+ - street_synonyms
49
+ city_analyzer:
50
+ filter:
51
+ - lowercase
52
+ - german_normalization
53
+ - icu_folding
54
+ - strip_special_characters
55
+ - city_synonyms
56
+ filter:
57
+ street_suffix_decompounder:
58
+ type: pattern_capture
59
+ preserve_original: "false"
60
+ patterns:
61
+ <% country_profile.decompounding_patterns(:street).each do |pattern| %>
62
+ - <%= pattern %>
63
+ <% end %>