lib/geokit/geocoders/google.rb in geokit-1.9.0 vs lib/geokit/geocoders/google.rb in geokit-1.10.0
- old
+ new
@@ -35,34 +35,34 @@
# Geokit::Geocoders::GoogleGeocoder.geocode('Winnetka').state # => 'IL'
# # When biased to an bounding box around California, it will now return the Winnetka neighbourhood, CA
# bounds = Geokit::Bounds.normalize([34.074081, -118.694401], [34.321129, -118.399487])
# Geokit::Geocoders::GoogleGeocoder.geocode('Winnetka', :bias => bounds).state # => 'CA'
def self.do_geocode(address, options = {})
- bias_str = options[:bias] ? construct_bias_string_from_options(options[:bias]) : ''
+ bias_str = options[:bias] ? construct_bias_string_from_options(options[:bias]) : ""
address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
url = submit_url("address=#{Geokit::Inflector.url_escape(address_str)}#{bias_str}", options)
process :json, url
end
# This code comes from Googles Examples
# http://gmaps-samples.googlecode.com/svn/trunk/urlsigning/urlsigner.rb
def self.sign_gmap_bus_api_url(urlToSign, google_cryptographic_key)
- require 'base64'
- require 'openssl'
+ require "base64"
+ require "openssl"
# Decode the private key
- rawKey = Base64.decode64(google_cryptographic_key.tr('-_', '+/'))
+ rawKey = Base64.decode64(google_cryptographic_key.tr("-_", "+/"))
# create a signature using the private key and the URL
- rawSignature = OpenSSL::HMAC.digest('sha1', rawKey, urlToSign)
+ rawSignature = OpenSSL::HMAC.digest("sha1", rawKey, urlToSign)
# encode the signature into base64 for url use form.
- Base64.encode64(rawSignature).tr('+/', '-_').gsub(/\n/, '')
+ Base64.encode64(rawSignature).tr("+/", "-_").gsub(/\n/, "")
end
def self.submit_url(query_string, options = {})
- language_str = options[:language] ? "&language=#{options[:language]}" : ''
+ language_str = options[:language] ? "&language=#{options[:language]}" : ""
query_string = "/maps/api/geocode/json?sensor=false&#{query_string}#{language_str}"
if client_id && cryptographic_key
- channel_string = channel ? "&channel=#{channel}" : ''
+ channel_string = channel ? "&channel=#{channel}" : ""
urlToSign = query_string + "&client=#{client_id}" + channel_string
signature = sign_gmap_bus_api_url(urlToSign, cryptographic_key)
"#{protocol}://maps.googleapis.com" + urlToSign + "&signature=#{signature}"
elsif api_key
url_with_key = query_string + "&key=#{api_key}"
@@ -83,24 +83,28 @@
"&bounds=#{url_escaped_string}"
end
end
def self.parse_json(results)
- case results['status']
- when 'OVER_QUERY_LIMIT' then raise Geokit::Geocoders::TooManyQueriesError
- when 'ZERO_RESULTS' then return GeoLoc.new
+ case results["status"]
+ when "OVER_QUERY_LIMIT"
+ raise Geokit::Geocoders::TooManyQueriesError, results["error_message"]
+ when "REQUEST_DENIED"
+ raise Geokit::Geocoders::AccessDeniedError, results["error_message"]
+ when "ZERO_RESULTS"
+ return GeoLoc.new
+ when "OK"
+ # all good
+ else
+ raise Geokit::Geocoders::GeocodeError, results["error_message"]
end
- # this should probably be smarter.
- if results['status'] != 'OK'
- raise Geokit::Geocoders::GeocodeError
- end
- unsorted = results['results'].map do |addr|
+ unsorted = results["results"].map do |addr|
single_json_to_geoloc(addr)
end
- all = unsorted.sort {|a, b| b.accuracy <=> a.accuracy }
+ all = unsorted.sort { |a, b| b.accuracy <=> a.accuracy }
encoded = all.first
encoded.all = all
encoded
end
@@ -119,84 +123,96 @@
# "APPROXIMATE" indicates that the returned result is approximate
# these do not map well. Perhaps we should guess better based on size
# of bounding box where it exists? Does it really matter?
ACCURACY = {
- 'ROOFTOP' => 9,
- 'RANGE_INTERPOLATED' => 8,
- 'GEOMETRIC_CENTER' => 5,
- 'APPROXIMATE' => 4
+ "ROOFTOP" => 9,
+ "RANGE_INTERPOLATED" => 8,
+ "GEOMETRIC_CENTER" => 5,
+ "APPROXIMATE" => 4,
}
+ PRECISIONS = %w(unknown country state state city zip zip+4 street address building)
+
def self.single_json_to_geoloc(addr)
loc = new_loc
loc.success = true
- loc.full_address = addr['formatted_address']
+ loc.full_address = addr["formatted_address"]
set_address_components(loc, addr)
set_precision(loc, addr)
if loc.street_name
- loc.street_address = [loc.street_number, loc.street_name].join(' ').strip
+ loc.street_address = [loc.street_number, loc.street_name].join(" ").strip
end
- ll = addr['geometry']['location']
- loc.lat = ll['lat'].to_f
- loc.lng = ll['lng'].to_f
+ ll = addr["geometry"]["location"]
+ loc.lat = ll["lat"].to_f
+ loc.lng = ll["lng"].to_f
set_bounds(loc, addr)
+ loc.place_id = addr['place_id']
+ loc.formatted_address = addr['formatted_address']
+
loc
end
def self.set_bounds(loc, addr)
- viewport = addr['geometry']['viewport']
- ne = Geokit::LatLng.from_json(viewport['northeast'])
- sw = Geokit::LatLng.from_json(viewport['southwest'])
+ viewport = addr["geometry"]["viewport"]
+ ne = Geokit::LatLng.from_json(viewport["northeast"])
+ sw = Geokit::LatLng.from_json(viewport["southwest"])
loc.suggested_bounds = Geokit::Bounds.new(sw, ne)
end
def self.set_address_components(loc, addr)
- addr['address_components'].each do |comp|
- types = comp['types']
+ addr["address_components"].each do |comp|
+ types = comp["types"]
case
- when types.include?('subpremise')
- loc.sub_premise = comp['short_name']
- when types.include?('street_number')
- loc.street_number = comp['short_name']
- when types.include?('route')
- loc.street_name = comp['long_name']
- when types.include?('locality')
- loc.city = comp['long_name']
- when types.include?('administrative_area_level_1')
- loc.state_code = comp['short_name']
- loc.state_name = comp['long_name']
- loc.province = comp['short_name']
- when types.include?('postal_code')
- loc.zip = comp['long_name']
- when types.include?('country')
- loc.country_code = comp['short_name']
- loc.country = comp['long_name']
- when types.include?('administrative_area_level_2')
- loc.district = comp['long_name']
- when types.include?('neighborhood')
- loc.neighborhood = comp['short_name']
- when types.include?('sublocality')
- loc.city = comp['long_name'] if loc.city.nil?
+ when types.include?("subpremise")
+ loc.sub_premise = comp["short_name"]
+ when types.include?("street_number")
+ loc.street_number = comp["short_name"]
+ when types.include?("route")
+ loc.street_name = comp["long_name"]
+ when types.include?("locality")
+ loc.city = comp["long_name"]
+ when types.include?("administrative_area_level_1")
+ loc.state_code = comp["short_name"]
+ loc.state_name = comp["long_name"]
+ loc.province = comp["short_name"]
+ when types.include?("postal_code")
+ loc.zip = comp["long_name"]
+ when types.include?("country")
+ loc.country_code = comp["short_name"]
+ loc.country = comp["long_name"]
+ when types.include?("administrative_area_level_2")
+ loc.district = comp["long_name"]
+ when types.include?("neighborhood")
+ loc.neighborhood = comp["short_name"]
+ # Use either sublocality or admin area level 3 if google does not return a city
+ when types.include?("sublocality")
+ loc.city = comp["long_name"] if loc.city.nil?
+ when types.include?("administrative_area_level_3")
+ loc.city = comp["long_name"] if loc.city.nil?
end
end
end
def self.set_precision(loc, addr)
- loc.accuracy = ACCURACY[addr['geometry']['location_type']]
- loc.precision = %w{unknown country state state city zip zip+4 street address building}[loc.accuracy]
+ loc.accuracy = ACCURACY[addr["geometry"]["location_type"]]
+ loc.precision = PRECISIONS[loc.accuracy]
# try a few overrides where we can
if loc.sub_premise
- loc.accuracy = 9
- loc.precision = 'building'
+ loc.precision = PRECISIONS[9]
+ loc.accuracy = 9
end
- if loc.street_name && loc.precision == 'city'
- loc.precision = 'street'
- loc.accuracy = 7
+ if loc.street_name && loc.precision == "city"
+ loc.precision = PRECISIONS[7]
+ loc.accuracy = 7
+ end
+ if addr["types"].include?("postal_code")
+ loc.precision = PRECISIONS[6]
+ loc.accuracy = 6
end
end
end
end
end