From 060c13f20db5a4aa4fde6742528c24ac1ab86c8c Mon Sep 17 00:00:00 2001 From: Alex Reisner <alex@alexreisner.com> Date: Thu, 21 Apr 2011 17:53:14 -0400 Subject: [PATCH] Add support for Yandex.ru geocoder. --- README.rdoc | 8 +++-- lib/geocoder.rb | 2 +- lib/geocoder/lookups/yandex.rb | 30 +++++++++++++++++ lib/geocoder/results/yandex.rb | 40 +++++++++++++++++++++++ test/fixtures/yandex_kremlin.json | 48 ++++++++++++++++++++++++++++ test/fixtures/yandex_no_results.json | 16 ++++++++++ test/test_helper.rb | 9 ++++++ 7 files changed, 149 insertions(+), 4 deletions(-) create mode 100644 lib/geocoder/lookups/yandex.rb create mode 100644 lib/geocoder/results/yandex.rb create mode 100644 test/fixtures/yandex_kremlin.json create mode 100644 test/fixtures/yandex_no_results.json diff --git a/README.rdoc b/README.rdoc index 551c363e..4c50d882 100644 --- a/README.rdoc +++ b/README.rdoc @@ -233,6 +233,7 @@ Note that the result objects returned by different geocoding services all implem * Google: http://code.google.com/apis/maps/documentation/geocoding/#JSON * Yahoo: http://developer.yahoo.com/geo/placefinder/guide/responses.html * Geocoder.ca: (???) +* Yandex: http://api.yandex.ru/maps/geocoder/doc/desc/concepts/response_structure.xml * FreeGeoIP: http://github.com/fiorix/freegeoip/blob/master/README.rst === API Keys @@ -241,10 +242,11 @@ To use your Google API key or Yahoo app ID: Geocoder::Configuration.api_key = "..." -To obtain an API key (not required): +To obtain an API key: -* Yahoo: https://developer.apps.yahoo.com/wsregapp -* Google: http://code.google.com/apis/maps/signup.html +* Yahoo: https://developer.apps.yahoo.com/wsregapp (not required) +* Google: http://code.google.com/apis/maps/signup.html (not required) +* Yandex: http://api.yandex.ru/maps/intro/concepts/intro.xml#apikey (required) === Timeout diff --git a/lib/geocoder.rb b/lib/geocoder.rb index ddca673d..33715dc0 100644 --- a/lib/geocoder.rb +++ b/lib/geocoder.rb @@ -125,7 +125,7 @@ module Geocoder # Array of valid Lookup names. # def valid_lookups - [:google, :yahoo, :geocoder_ca, :freegeoip] + [:google, :yahoo, :geocoder_ca, :yandex, :freegeoip] end ## diff --git a/lib/geocoder/lookups/yandex.rb b/lib/geocoder/lookups/yandex.rb new file mode 100644 index 00000000..66d14f5c --- /dev/null +++ b/lib/geocoder/lookups/yandex.rb @@ -0,0 +1,30 @@ +require 'geocoder/lookups/base' +require "geocoder/results/yandex" + +module Geocoder::Lookup + class Yandex < Base + + private # --------------------------------------------------------------- + + def results(query, reverse = false) + return [] unless doc = fetch_data(query, reverse) + if doc = doc['response']['GeoObjectCollection'] + meta = doc['metaDataProperty']['GeocoderResponseMetaData'] + return meta['found'].to_i > 0 ? doc['featureMember'] : [] + else + warn "Yandex Geocoding API error: unexpected response format." + return [] + end + end + + def query_url(query, reverse = false) + params = { + :geocode => query, + :format => "json", + :plng => "#{Geocoder::Configuration.language}", # supports ru, uk, be + :key => Geocoder::Configuration.api_key + } + "http://geocode-maps.yandex.ru/1.x/?" + hash_to_query(params) + end + end +end diff --git a/lib/geocoder/results/yandex.rb b/lib/geocoder/results/yandex.rb new file mode 100644 index 00000000..7f6f3281 --- /dev/null +++ b/lib/geocoder/results/yandex.rb @@ -0,0 +1,40 @@ +require 'geocoder/results/base' + +module Geocoder::Result + class Yandex < Base + + def coordinates + @data['GeoObject']['Point']['pos'].split(' ').map(&:to_f) + end + + def address(format = :full) + @data['GeoObject']['metaDataProperty']['GeocoderMetaData']['text'] + end + + def city + address_details['Locality']['LocalityName'] + end + + def country + address_details['CountryName'] + end + + def country_code + address_details['CountryNameCode'] + end + + def postal_code + "" + end + + def premise_name + address_details['Locality']['Premise']['PremiseName'] + end + + private # ---------------------------------------------------------------- + + def address_details + @data['GeoObject']['metaDataProperty']['GeocoderMetaData']['AddressDetails']['Country'] + end + end +end diff --git a/test/fixtures/yandex_kremlin.json b/test/fixtures/yandex_kremlin.json new file mode 100644 index 00000000..f08b6ea3 --- /dev/null +++ b/test/fixtures/yandex_kremlin.json @@ -0,0 +1,48 @@ +{ + "response": { + "GeoObjectCollection": { + "metaDataProperty": { + "GeocoderResponseMetaData": { + "request": "Кремль, Moscow, Russia", + "found": "1", + "results": "10" + } + }, + "featureMember": [ + { + "GeoObject": { + "metaDataProperty": { + "GeocoderMetaData": { + "kind": "vegetation", + "text": "РоÑÑиÑ, МоÑква, МоÑковÑкий Кремль", + "precision": "other", + "AddressDetails": { + "Country": { + "CountryNameCode": "RU", + "CountryName": "РоÑÑиÑ", + "Locality": { + "LocalityName": "МоÑква", + "Premise": { + "PremiseName": "МоÑковÑкий Кремль" + } + } + } + } + } + }, + "name": "МоÑковÑкий Кремль", + "boundedBy": { + "Envelope": { + "lowerCorner": "37.584182 55.733361", + "upperCorner": "37.650064 55.770517" + } + }, + "Point": { + "pos": "37.617123 55.751943" + } + } + } + ] + } + } +} diff --git a/test/fixtures/yandex_no_results.json b/test/fixtures/yandex_no_results.json new file mode 100644 index 00000000..66456115 --- /dev/null +++ b/test/fixtures/yandex_no_results.json @@ -0,0 +1,16 @@ +{ + "response": { + "GeoObjectCollection": { + "metaDataProperty": { + "GeocoderResponseMetaData": { + "request": "blah", + "found": "0", + "results": "10" + } + }, + "featureMember": [ + + ] + } + } +} diff --git a/test/test_helper.rb b/test/test_helper.rb index d2a6e51b..9e48f988 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -80,6 +80,15 @@ module Geocoder end end + class Yandex < Base + private #----------------------------------------------------------------- + def fetch_raw_data(query, reverse = false) + raise TimeoutError if query == "timeout" + file = query == "no results" ? :no_results : :kremlin + read_fixture "yandex_#{file}.json" + end + end + class GeocoderCa < Base private #----------------------------------------------------------------- def fetch_raw_data(query, reverse = false) -- GitLab