lib/geocoder/results/yandex.rb in geocoder-1.6.1 vs lib/geocoder/results/yandex.rb in geocoder-1.6.2

- old
+ new

@@ -1,81 +1,226 @@ require 'geocoder/results/base' module Geocoder::Result class Yandex < Base + # Yandex result has difficult tree structure, + # and presence of some nodes depends on exact search case. + # Also Yandex lacks documentation about it. + # See https://tech.yandex.com/maps/doc/geocoder/desc/concepts/response_structure-docpage/ + + # Ultimatly, we need to find Locality and/or Thoroughfare data. + + # It may resides on the top (ADDRESS_DETAILS) level. + # example: 'Baltic Sea' + # "AddressDetails": { + # "Locality": { + # "Premise": { + # "PremiseName": "Baltic Sea" + # } + # } + # } + + ADDRESS_DETAILS = %w[ + GeoObject metaDataProperty GeocoderMetaData + AddressDetails + ].freeze + + # On COUNTRY_LEVEL. + # example: 'Potomak' + # "AddressDetails": { + # "Country": { + # "AddressLine": "reka Potomak", + # "CountryNameCode": "US", + # "CountryName": "United States of America", + # "Locality": { + # "Premise": { + # "PremiseName": "reka Potomak" + # } + # } + # } + # } + + COUNTRY_LEVEL = %w[ + GeoObject metaDataProperty GeocoderMetaData + AddressDetails Country + ].freeze + + # On ADMIN_LEVEL (usually state or city) + # example: 'Moscow, Tverskaya' + # "AddressDetails": { + # "Country": { + # "AddressLine": "Moscow, Tverskaya Street", + # "CountryNameCode": "RU", + # "CountryName": "Russia", + # "AdministrativeArea": { + # "AdministrativeAreaName": "Moscow", + # "Locality": { + # "LocalityName": "Moscow", + # "Thoroughfare": { + # "ThoroughfareName": "Tverskaya Street" + # } + # } + # } + # } + # } + + ADMIN_LEVEL = %w[ + GeoObject metaDataProperty GeocoderMetaData + AddressDetails Country + AdministrativeArea + ].freeze + + # On SUBADMIN_LEVEL (may refer to urban district) + # example: 'Moscow Region, Krasnogorsk' + # "AddressDetails": { + # "Country": { + # "AddressLine": "Moscow Region, Krasnogorsk", + # "CountryNameCode": "RU", + # "CountryName": "Russia", + # "AdministrativeArea": { + # "AdministrativeAreaName": "Moscow Region", + # "SubAdministrativeArea": { + # "SubAdministrativeAreaName": "gorodskoy okrug Krasnogorsk", + # "Locality": { + # "LocalityName": "Krasnogorsk" + # } + # } + # } + # } + # } + + SUBADMIN_LEVEL = %w[ + GeoObject metaDataProperty GeocoderMetaData + AddressDetails Country + AdministrativeArea + SubAdministrativeArea + ].freeze + + # On DEPENDENT_LOCALITY_1 (may refer to district of city) + # example: 'Paris, Etienne Marcel' + # "AddressDetails": { + # "Country": { + # "AddressLine": "Île-de-France, Paris, 1er Arrondissement, Rue Étienne Marcel", + # "CountryNameCode": "FR", + # "CountryName": "France", + # "AdministrativeArea": { + # "AdministrativeAreaName": "Île-de-France", + # "Locality": { + # "LocalityName": "Paris", + # "DependentLocality": { + # "DependentLocalityName": "1er Arrondissement", + # "Thoroughfare": { + # "ThoroughfareName": "Rue Étienne Marcel" + # } + # } + # } + # } + # } + # } + + DEPENDENT_LOCALITY_1 = %w[ + GeoObject metaDataProperty GeocoderMetaData + AddressDetails Country + AdministrativeArea Locality + DependentLocality + ].freeze + + # On DEPENDENT_LOCALITY_2 (for special cases like turkish "mahalle") + # https://en.wikipedia.org/wiki/Mahalle + # example: 'Istanbul Mabeyinci Yokuşu 17' + + # "AddressDetails": { + # "Country": { + # "AddressLine": "İstanbul, Fatih, Saraç İshak Mah., Mabeyinci Yokuşu, 17", + # "CountryNameCode": "TR", + # "CountryName": "Turkey", + # "AdministrativeArea": { + # "AdministrativeAreaName": "İstanbul", + # "SubAdministrativeArea": { + # "SubAdministrativeAreaName": "Fatih", + # "Locality": { + # "DependentLocality": { + # "DependentLocalityName": "Saraç İshak Mah.", + # "Thoroughfare": { + # "ThoroughfareName": "Mabeyinci Yokuşu", + # "Premise": { + # "PremiseNumber": "17" + # } + # } + # } + # } + # } + # } + # } + # } + + DEPENDENT_LOCALITY_2 = %w[ + GeoObject metaDataProperty GeocoderMetaData + AddressDetails Country + AdministrativeArea + SubAdministrativeArea Locality + DependentLocality + ].freeze + def coordinates @data['GeoObject']['Point']['pos'].split(' ').reverse.map(&:to_f) end - def address(format = :full) + def address(_format = :full) @data['GeoObject']['metaDataProperty']['GeocoderMetaData']['text'] end def city - if state.empty? and address_details and address_details.has_key? 'Locality' - address_details['Locality']['LocalityName'] - elsif sub_state.empty? and address_details and address_details.has_key? 'AdministrativeArea' and - address_details['AdministrativeArea'].has_key? 'Locality' - address_details['AdministrativeArea']['Locality']['LocalityName'] - elsif not sub_state_city.empty? - sub_state_city - else - "" - end + result = + if state.empty? + find_in_hash(@data, *COUNTRY_LEVEL, 'Locality', 'LocalityName') + elsif sub_state.empty? + find_in_hash(@data, *ADMIN_LEVEL, 'Locality', 'LocalityName') + else + find_in_hash(@data, *SUBADMIN_LEVEL, 'Locality', 'LocalityName') + end + + result || "" end def country - if address_details - address_details['CountryName'] - else - "" - end + find_in_hash(@data, *COUNTRY_LEVEL, 'CountryName') || "" end def country_code - if address_details - address_details['CountryNameCode'] - else - "" - end + find_in_hash(@data, *COUNTRY_LEVEL, 'CountryNameCode') || "" end def state - if address_details and address_details['AdministrativeArea'] - address_details['AdministrativeArea']['AdministrativeAreaName'] - else - "" - end + find_in_hash(@data, *ADMIN_LEVEL, 'AdministrativeAreaName') || "" end def sub_state - if !state.empty? and address_details and address_details['AdministrativeArea']['SubAdministrativeArea'] - address_details['AdministrativeArea']['SubAdministrativeArea']['SubAdministrativeAreaName'] - else - "" - end + return "" if state.empty? + find_in_hash(@data, *SUBADMIN_LEVEL, 'SubAdministrativeAreaName') || "" end def state_code "" end - def postal_code - "" + def street + thoroughfare_data.is_a?(Hash) ? thoroughfare_data['ThoroughfareName'] : "" end - def premise_name - address_details['Locality']['Premise']['PremiseName'] + def street_number + premise.is_a?(Hash) ? premise.fetch('PremiseNumber', "") : "" end - def street - thoroughfare_data && thoroughfare_data['ThoroughfareName'] + def premise_name + premise.is_a?(Hash) ? premise.fetch('PremiseName', "") : "" end - def street_number - thoroughfare_data && thoroughfare_data['Premise'] && thoroughfare_data['Premise']['PremiseNumber'] + def postal_code + return "" unless premise.is_a?(Hash) + find_in_hash(premise, 'PostalCode', 'PostalCodeNumber') || "" end def kind @data['GeoObject']['metaDataProperty']['GeocoderMetaData']['kind'] end @@ -91,44 +236,57 @@ [south, west, north, east] end private # ---------------------------------------------------------------- - def thoroughfare_data - locality_data && locality_data['Thoroughfare'] + def top_level_locality + find_in_hash(@data, *ADDRESS_DETAILS, 'Locality') end - def locality_data - dependent_locality && subadmin_locality && admin_locality + def country_level_locality + find_in_hash(@data, *COUNTRY_LEVEL, 'Locality') end def admin_locality - address_details && address_details['AdministrativeArea'] && - address_details['AdministrativeArea']['Locality'] + find_in_hash(@data, *ADMIN_LEVEL, 'Locality') end def subadmin_locality - address_details && address_details['AdministrativeArea'] && - address_details['AdministrativeArea']['SubAdministrativeArea'] && - address_details['AdministrativeArea']['SubAdministrativeArea']['Locality'] + find_in_hash(@data, *SUBADMIN_LEVEL, 'Locality') end def dependent_locality - address_details && address_details['AdministrativeArea'] && - address_details['AdministrativeArea']['SubAdministrativeArea'] && - address_details['AdministrativeArea']['SubAdministrativeArea']['Locality'] && - address_details['AdministrativeArea']['SubAdministrativeArea']['Locality']['DependentLocality'] + find_in_hash(@data, *DEPENDENT_LOCALITY_1) || + find_in_hash(@data, *DEPENDENT_LOCALITY_2) end - def address_details - @data['GeoObject']['metaDataProperty']['GeocoderMetaData']['AddressDetails']['Country'] + def locality_data + dependent_locality || subadmin_locality || admin_locality || + country_level_locality || top_level_locality end - def sub_state_city - if !sub_state.empty? and address_details and address_details['AdministrativeArea']['SubAdministrativeArea'].has_key? 'Locality' - address_details['AdministrativeArea']['SubAdministrativeArea']['Locality']['LocalityName'] || "" - else - "" + def thoroughfare_data + locality_data['Thoroughfare'] if locality_data.is_a?(Hash) + end + + def premise + if thoroughfare_data.is_a?(Hash) + thoroughfare_data['Premise'] + elsif locality_data.is_a?(Hash) + locality_data['Premise'] end + end + + def find_in_hash(source, *keys) + key = keys.shift + result = source[key] + + if keys.empty? + return result + elsif !result.is_a?(Hash) + return nil + end + + find_in_hash(result, *keys) end end end