Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add lookup for Google Places Details API (New) #1637

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/geocoder/lookup.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def street_services
:google_premier,
:google_places_details,
:google_places_search,
:google_places_details_new,
:bing,
:geocoder_ca,
:yandex,
Expand Down
24 changes: 2 additions & 22 deletions lib/geocoder/lookups/google.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
require 'geocoder/lookups/base'
require 'geocoder/lookups/google_base'
require "geocoder/results/google"

module Geocoder::Lookup
class Google < Base
class Google < GoogleBase

def name
"Google"
Expand All @@ -12,32 +12,12 @@ def map_link_url(coordinates)
"http://maps.google.com/maps?q=#{coordinates.join(',')}"
end

def supported_protocols
# Google requires HTTPS if an API key is used.
if configuration.api_key
[:https]
else
[:http, :https]
end
end

private # ---------------------------------------------------------------

def base_query_url(query)
"#{protocol}://maps.googleapis.com/maps/api/geocode/json?"
end

def configure_ssl!(client)
client.instance_eval {
@ssl_context = OpenSSL::SSL::SSLContext.new
options = OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3
if OpenSSL::SSL.const_defined?('OP_NO_COMPRESSION')
options |= OpenSSL::SSL::OP_NO_COMPRESSION
end
@ssl_context.set_params({options: options})
}
end

def valid_response?(response)
json = parse_json(response.body)
status = json["status"] if json
Expand Down
28 changes: 28 additions & 0 deletions lib/geocoder/lookups/google_base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require 'geocoder/lookups/base'

module Geocoder::Lookup
class GoogleBase < Base
def supported_protocols
# Google requires HTTPS if an API key is used.
if configuration.api_key
[:https]
else
[:http, :https]
end
end

private # ---------------------------------------------------------------

def configure_ssl!(client)
client.instance_eval {
@ssl_context = OpenSSL::SSL::SSLContext.new
options = OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3
if OpenSSL::SSL.const_defined?('OP_NO_COMPRESSION')
options |= OpenSSL::SSL::OP_NO_COMPRESSION
end
@ssl_context.set_params({options: options})
}
end
end
end

52 changes: 52 additions & 0 deletions lib/geocoder/lookups/google_new.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
require 'geocoder/lookups/google_base'
require 'geocoder/results/google_new'

module Geocoder::Lookup
class GoogleNew < GoogleBase
def required_api_key_parts
["key"]
end

private

def base_url
"#{protocol}://places.googleapis.com/v1/places"
end

def valid_response?(response)
json = parse_json(response.body)
error_status = json.dig('errpr', 'status') if json

super(response) and error_status.nil?
end

def results(query)
return [] unless doc = fetch_data(query)

error = doc['error']
return doc if error.nil?

case error['status']
when 'PERMISSION_DENIED'
raise_error(Geocoder::RequestDenied, error['message']) ||
Geocoder.log(:warn, "#{name} API error: request denied (#{error['message']}).")
when 'INVALID_ARGUMENT'
raise_error(Geocoder::InvalidRequest, error['message']) ||
Geocoder.log(:warn, "#{name} API error: invalid request (#{error['message']}).")
end

return []
end

def query_url_google_params(query)
{}
end

def query_url_params(query)
query_url_google_params(query).merge(
:key => configuration.api_key
).merge(super)
end
end
end

50 changes: 50 additions & 0 deletions lib/geocoder/lookups/google_places_details_new.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
require 'geocoder/lookups/google_new'
require 'geocoder/results/google_places_details_new'

module Geocoder::Lookup
class GooglePlacesDetailsNew < GoogleNew
def name
'Google Placees Details (New)'
end

private

def base_query_url(query)
"#{base_url}/#{query.text}?"
end

def results(query)
result = super(query)
return [result] unless result.is_a? Array

result
end

def fields(query)
if query.options.has_key?(:fields)
return format_fields(query.options[:fields])
end

if configuration.has_key?(:fields)
return format_fields(configuration[:fields])
end

# Google discourage the use of the wildcard field mask so you probably do NOT want to use it
'*'
end

def format_fields(*fields)
flattened = fields.flatten.compact
return if flattened.empty?

flattened.join(',')
end

def query_url_google_params(query)
{
fields: fields(query),
languageCode: query.language || configuration.language
}.merge(super)
end
end
end
122 changes: 122 additions & 0 deletions lib/geocoder/results/google_new.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
require 'geocoder/results/base'

module Geocoder::Result
class GoogleNew < Base

def coordinates
['latitude', 'longitude'].map{ |i| @data['location'][i] }
end

def address(format = :full)
formatted_address
end

def neighborhood
if neighborhood = address_components_of_type(:neighborhood).first
neighborhood['longText']
end
end

def city
fields = [:locality, :sublocality,
:administrative_area_level_3,
:administrative_area_level_2]
fields.each do |f|
if entity = address_components_of_type(f).first
return entity['longText']
end
end

return nil # no appropriate components found
end

def state
if state = address_components_of_type(:administrative_area_level_1).first
state['longText']
end
end

def state_code
if state = address_components_of_type(:administrative_area_level_1).first
state['shortText']
end
end

def sub_state
if state = address_components_of_type(:administrative_area_level_2).first
state['longText']
end
end

def sub_state_code
if state = address_components_of_type(:administrative_area_level_2).first
state['shortText']
end
end

def country
if country = address_components_of_type(:country).first
country['longText']
end
end

def country_code
if country = address_components_of_type(:country).first
country['shortText']
end
end

def postal_code
if postal = address_components_of_type(:postal_code).first
postal['longText']
end
end

def route
if route = address_components_of_type(:route).first
route['longText']
end
end

def street_number
if street_number = address_components_of_type(:street_number).first
street_number['longText']
end
end

def street_address
[street_number, route].compact.join(' ')
end

def types
@data['types']
end

def formatted_address
@data['formattedAddress']
end

def address_components
@data['addressComponents']
end

##
# Get address components of a given type. Valid types are defined in
# Google's Geocoding API documentation and include (among others):
#
# :street_number
# :locality
# :neighborhood
# :route
# :postal_code
#
def address_components_of_type(type)
address_components.select{ |c| c['types'].include?(type.to_s) }
end

def place_id
@data['id']
end
end
end

38 changes: 38 additions & 0 deletions lib/geocoder/results/google_places_details_new.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
require 'geocoder/results/google_new'

module Geocoder::Result
class GooglePlacesDetailsNew < GoogleNew
def types
@data['types'] || []
end

def primary_type
@data['primaryType']
end

def reviews
@data['reviews'] || []
end

def rating
@data['rating']
end

def rating_count
@data['userRatingCount']
end

def phone_number
@data['internationalPhoneNumber']
end

def website
@data['websiteUri']
end

def photos
@data['photos'] || []
end
end
end

6 changes: 6 additions & 0 deletions test/fixtures/google_places_details_new_invalid_request
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"error" : {
"code": 400,
"status": "INVALID_ARGUMENT"
}
}
Loading