# encoding: UTF-8 module Graticule #:nodoc: module Geocoder #:nodoc: # Mapquest uses the Licenced Community API which requires an api key. You can sign up an account # and get an api key by registering at: http://developer.mapquest.com/ # # mq = Graticule.service(:mapquest).new(API_KEY) # location = gg.locate('44 Allen Rd., Lovell, ME 04051') # [42.78942, -86.104424] # class Mapquest < Base def initialize(api_key, open = false, restrict_to_country = nil) @api_key = api_key @url = if open URI.parse('http://open.mapquestapi.com/geocoding/v1/address') else URI.parse('http://www.mapquestapi.com/geocoding/v1/address') end @country_filter = restrict_to_country end # Locates +address+ returning a Location def locate(address) get :q => address.is_a?(String) ? address : location_from_params(address).to_s end protected def make_url(params) #:nodoc request = Mapquest::Request.new(params[:q], @api_key) url = @url.dup url.query = request.query url end class Request def initialize(address, api_key) @address = address @api_key = api_key end def query "key=#{URI.escape(@api_key)}&outFormat=xml&inFormat=kvp&location=#{URI.escape(@address)}" end end # See http://www.mapquestapi.com/geocoding/geocodequality.html#granularity PRECISION = { 'P1' => Precision::Point, 'L1' => Precision::Address, 'I1' => Precision::Street, 'B1' => Precision::Street, 'B2' => Precision::Street, 'B3' => Precision::Street, 'Z3' => Precision::PostalCode, 'Z4' => Precision::PostalCode, 'Z2' => Precision::PostalCode, 'Z1' => Precision::PostalCode, 'A5' => Precision::Locality, 'A4' => Precision::Region, 'A3' => Precision::Region, 'A1' => Precision::Country } class Address include HappyMapper tag 'location' element :latitude, Float, :tag => 'lat', :deep => true element :longitude, Float, :tag => 'lng', :deep => true element :street, String, :tag => 'street' element :locality, String, :tag => 'adminArea5' element :region, String, :tag => 'adminArea3' element :postal_code, String, :tag => 'postalCode' element :country, String, :tag => 'adminArea1' element :result_code, String, :tag => 'geocodeQualityCode' def precision PRECISION[result_code.to_s[0,2]] || :unknown end end class Locations include HappyMapper has_many :addresses, Address, :tag => "location" end class Result include HappyMapper has_one :locations, Locations, :tag => "locations" end class Response include HappyMapper has_one :result, Result, :deep => true end def prepare_response(xml) Response.parse(xml, :single => true) end # Extracts a location from +xml+. def parse_response(response) #:nodoc: if @country_filter addr = response.result.locations.addresses.select{|address| address.country == @country_filter}.first else addr = response.result.locations.addresses.first end Location.new( :latitude => addr.latitude, :longitude => addr.longitude, :street => addr.street, :locality => addr.locality, :region => addr.region, :postal_code => addr.postal_code, :country => addr.country, :precision => addr.precision ) end # Extracts and raises any errors in +xml+ def check_error(xml) #:nodoc end end end end