lib/geocoder/results/yandex.rb
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)
@data['GeoObject']['metaDataProperty']['GeocoderMetaData']['text']
end
def city
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
find_in_hash(@data, *COUNTRY_LEVEL, 'CountryName') || ""
end
def country_code
find_in_hash(@data, *COUNTRY_LEVEL, 'CountryNameCode') || ""
end
def state
find_in_hash(@data, *ADMIN_LEVEL, 'AdministrativeAreaName') || ""
end
def sub_state
return "" if state.empty?
find_in_hash(@data, *SUBADMIN_LEVEL, 'SubAdministrativeAreaName') || ""
end
def state_code
""
end
def street
thoroughfare_data.is_a?(Hash) ? thoroughfare_data['ThoroughfareName'] : ""
end
def street_number
premise.is_a?(Hash) ? premise.fetch('PremiseNumber', "") : ""
end
def premise_name
premise.is_a?(Hash) ? premise.fetch('PremiseName', "") : ""
end
def postal_code
return "" unless premise.is_a?(Hash)
find_in_hash(premise, 'PostalCode', 'PostalCodeNumber') || ""
end
def kind
@data['GeoObject']['metaDataProperty']['GeocoderMetaData']['kind']
end
def precision
@data['GeoObject']['metaDataProperty']['GeocoderMetaData']['precision']
end
def viewport
envelope = @data['GeoObject']['boundedBy']['Envelope'] || fail
east, north = envelope['upperCorner'].split(' ').map(&:to_f)
west, south = envelope['lowerCorner'].split(' ').map(&:to_f)
[south, west, north, east]
end
private # ----------------------------------------------------------------
def top_level_locality
find_in_hash(@data, *ADDRESS_DETAILS, 'Locality')
end
def country_level_locality
find_in_hash(@data, *COUNTRY_LEVEL, 'Locality')
end
def admin_locality
find_in_hash(@data, *ADMIN_LEVEL, 'Locality')
end
def subadmin_locality
find_in_hash(@data, *SUBADMIN_LEVEL, 'Locality')
end
def dependent_locality
find_in_hash(@data, *DEPENDENT_LOCALITY_1) ||
find_in_hash(@data, *DEPENDENT_LOCALITY_2)
end
def locality_data
dependent_locality || subadmin_locality || admin_locality ||
country_level_locality || top_level_locality
end
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