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