Skip to content

Commit

Permalink
Merge pull request #93 from qpowell/detailed-spots
Browse files Browse the repository at this point in the history
Allow all collections of spots to include full spot detail
  • Loading branch information
edwinwills committed Jun 7, 2017
2 parents ba697a2 + 4e6c899 commit e209f3f
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 56 deletions.
14 changes: 14 additions & 0 deletions README.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,20 @@ Search by multiple types and exclude multiple types

@client.spots_by_query('Pizza near Miami Florida', :types => ['restaurant', 'food'], :exclude => ['cafe', 'establishment'])

=== Retrieving a collection of spots with complete details

Google limits the details that are returned in any API calls for a collection,
so you'll often find that details such as phone numbers are missing in a
collection of spots, but are filled in when retrieving a single spot.

If you require these extra details to be completed when retrieving a number of
results, you can pass in the <tt>detail: true</tt> option to any method that returns
a collection of spots.

This option should be used with care, as it adds an additional API call
for EACH spot in the collection. E.g. a spots collection of 100 spots
will use 101 API calls when the <tt>detail: true</tt> option is set.

=== Retrieving a single spot

First register a new Client:
Expand Down
61 changes: 49 additions & 12 deletions lib/google_places/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,11 @@ def initialize(api_key = @api_key, options = {})
# @see http://spreadsheets.google.com/pub?key=p9pdwsai2hDMsLkXsoM05KQ&gid=1 List of supported languages
# @see https://developers.google.com/maps/documentation/places/supported_types List of supported types
def spots(lat, lng, options = {})
detail_spot = options.delete(:detail)
spots = Spot.list(lat, lng, @api_key, @options.merge(options))

if detail_spot
spots.map {|spot| Spot.find(spot.place_id, @api_key, @options.merge(options))}
else
spots
end
detail = @options.merge!(options).delete(:detail)
collection_detail_level(
Spot.list(lat, lng, @api_key, @options),
detail
)
end

# Search for a Spot with a reference key
Expand Down Expand Up @@ -153,11 +150,18 @@ def spot(place_id, options = {})
# @option options [Object] :retry_options[:status] ([])
# @option options [Integer] :retry_options[:max] (0) the maximum retries
# @option options [Integer] :retry_options[:delay] (5) the delay between each retry in seconds
# @option options [Boolean] :detail
# A boolean to return spots with full detail information(its complete address, phone number, user rating, reviews, etc)
# Note) This makes an extra call for each spot for more information.
#
# @see http://spreadsheets.google.com/pub?key=p9pdwsai2hDMsLkXsoM05KQ&gid=1 List of supported languages
# @see https://developers.google.com/maps/documentation/places/supported_types List of supported types
def spots_by_query(query, options = {})
Spot.list_by_query(query, @api_key, @options.merge(options))
detail = @options.merge!(options).delete(:detail)
collection_detail_level(
Spot.list_by_query(query, @api_key, @options),
detail
)
end
# Search for Spots within a give SW|NE bounds with query
#
Expand Down Expand Up @@ -190,10 +194,17 @@ def spots_by_query(query, options = {})
# @option options [Object] :retry_options[:status] ([])
# @option options [Integer] :retry_options[:max] (0) the maximum retries
# @option options [Integer] :retry_options[:delay] (5) the delay between each retry in seconds
# @option options [Boolean] :detail
# A boolean to return spots with full detail information(its complete address, phone number, user rating, reviews, etc)
# Note) This makes an extra call for each spot for more information.
#
# @see https://developers.google.com/maps/documentation/places/supported_types List of supported types
def spots_by_bounds(bounds, options = {})
Spot.list_by_bounds(bounds, @api_key, @options.merge(options))
detail = @options.merge!(options).delete(:detail)
collection_detail_level(
Spot.list_by_bounds(bounds, @api_key, @options),
detail
)
end
# Search for Spots with a pagetoken
#
Expand All @@ -207,10 +218,17 @@ def spots_by_bounds(bounds, options = {})
# @option options [Object] :retry_options[:status] ([])
# @option options [Integer] :retry_options[:max] (0) the maximum retries
# @option options [Integer] :retry_options[:delay] (5) the delay between each retry in seconds
# @option options [Boolean] :detail
# A boolean to return spots with full detail information(its complete address, phone number, user rating, reviews, etc)
# Note) This makes an extra call for each spot for more information.
#
# @see https://developers.google.com/maps/documentation/places/supported_types List of supported types
def spots_by_pagetoken(pagetoken, options = {})
Spot.list_by_pagetoken(pagetoken, @api_key, @options.merge(options))
detail = @options.merge!(options).delete(:detail)
collection_detail_level(
Spot.list_by_pagetoken(pagetoken, @api_key, @options),
detail
)
end

# Radar Search Service allows you to search for up to 200 Places at once, but with less detail than is typically returned from a Text Search or Nearby Search request. The search response will include up to 200 Places, identified only by their geographic coordinates and reference. You can send a Place Details request for more information about any of them.
Expand Down Expand Up @@ -244,10 +262,17 @@ def spots_by_pagetoken(pagetoken, options = {})
# Restrict your search to only those locations that are Zagat selected businesses.
# This parameter does not require a true or false value, simply including the parameter in the request is sufficient to restrict your search.
# The zagatselected parameter is experimental, and only available to Places API enterprise customers.
# @option options [Boolean] :detail
# A boolean to return spots with full detail information(its complete address, phone number, user rating, reviews, etc)
# Note) This makes an extra call for each spot for more information.
#
# @see https://developers.google.com/places/documentation/search#RadarSearchRequests
def spots_by_radar(lat, lng, options = {})
Spot.list_by_radar(lat, lng, @api_key, @options.merge(options))
detail = @options.merge!(options).delete(:detail)
collection_detail_level(
Spot.list_by_radar(lat, lng, @api_key, @options),
detail
)
end

# Query for Place Predictions
Expand All @@ -272,5 +297,17 @@ def spots_by_radar(lat, lng, options = {})
def predictions_by_input(input, options = {})
Prediction.list_by_input(input, @api_key, @options.merge(options))
end

private

def collection_detail_level(spots, detail = false)
if detail
spots.map do |spot|
Spot.find(spot.place_id, @api_key, @options)
end
else
spots
end
end
end
end
184 changes: 140 additions & 44 deletions spec/google_places/client_spec.rb
Original file line number Diff line number Diff line change
@@ -1,69 +1,165 @@
require 'spec_helper'

describe GooglePlaces::Client do
let(:client) { GooglePlaces::Client.new(api_key) }
let(:fake_spot) { Object.new }

before do
allow(fake_spot).to receive(:place_id) { 1 }
end

it 'should initialize with an api_key' do
@client = GooglePlaces::Client.new(api_key)
expect(@client.api_key).to eq(api_key)
expect(client.api_key).to eq(api_key)
end

it 'should request spots' do
lat, lng = '-33.8670522', '151.1957362'
@client = GooglePlaces::Client.new(api_key)
expect(GooglePlaces::Spot).to receive(:list).with(lat, lng, api_key, {})
describe '::spots' do
let(:lat) { '-33.8670522' }
let(:lng) { '151.1957362' }
it 'should request spots' do
expect(GooglePlaces::Spot).to receive(:list).with(lat, lng, api_key, {})
client.spots(lat, lng)
end

@client.spots(lat, lng)
end
it 'does not call find on GooglePlces::Spot' do
allow(GooglePlaces::Spot).to receive(:list) { [fake_spot] }
expect(GooglePlaces::Spot).not_to receive(:find)
client.spots(lat, lng)
end

it 'should request a single spot by place_id' do
place_id = 'ChIJu46S-ZZhLxMROG5lkwZ3D7k'
@client = GooglePlaces::Client.new(api_key)
expect(GooglePlaces::Spot).to receive(:find).with(place_id, api_key, {})
context 'with detail set to true' do
it 'calls find on GooglePlaces::Spot' do
allow(GooglePlaces::Spot).to receive(:list) { [fake_spot] }
expect(GooglePlaces::Spot).to receive(:find)
client.spots(lat, lng, detail: true)
end
end
end

@client.spot(place_id)
describe '::spot' do
let(:place_id) { 'ChIJu46S-ZZhLxMROG5lkwZ3D7k' }
it 'should request a single spot by place_id' do
expect(GooglePlaces::Spot).to receive(:find).with(place_id, api_key, {})
client.spot(place_id)
end
end

it 'should request spots by query' do
query = 'Statue of liberty, New York'
@client = GooglePlaces::Client.new(api_key)
expect(GooglePlaces::Spot).to receive(:list_by_query).with(query, api_key, {})
describe '::spots_by_query' do
let(:query) { 'Statue of liberty, New York' }
it 'should request spots by query' do
expect(GooglePlaces::Spot).to receive(:list_by_query).with(
query,
api_key,
{}
)
client.spots_by_query(query)
end

it 'does not call find on GooglePlces::Spot' do
allow(GooglePlaces::Spot).to receive(:list_by_query) { [fake_spot] }
expect(GooglePlaces::Spot).not_to receive(:find)
client.spots_by_query(query)
end

@client.spots_by_query(query)
context 'with detail set to true' do
it 'calls find on GooglePlaces::Spot' do
allow(GooglePlaces::Spot).to receive(:list_by_query) { [fake_spot] }
expect(GooglePlaces::Spot).to receive(:find)
client.spots_by_query(query, detail: true)
end
end
end
it 'should request spots by bounds' do
query = 'pizza'
bounds = {:start_point => {:lat => '36.06686213257888', :lng => '-86.94168090820312'},
:end_point => {:lat => '36.268635800737876', :lng => '-86.66152954101562'}}
@client = GooglePlaces::Client.new(api_key)
expect(GooglePlaces::Spot).to receive(:list_by_bounds).with(bounds, api_key, {:query => query})
res = @client.spots_by_bounds(bounds, :query => query)

describe '::spots_by_bounds' do
let(:query) { 'pizza' }
let(:bounds) do
{
start_point: { lat: '36.06686213257888', lng: '-86.94168090820312' },
end_point: { lat: '36.268635800737876', lng: '-86.66152954101562' }
}
end

it 'should request spots by bounds' do
expect(GooglePlaces::Spot).to receive(:list_by_bounds).with(
bounds, api_key,
query: query
)
client.spots_by_bounds(bounds, query: query)
end

it 'does not call find on GooglePlces::Spot' do
allow(GooglePlaces::Spot).to receive(:list_by_bounds) { [fake_spot] }
expect(GooglePlaces::Spot).not_to receive(:find)
client.spots_by_bounds(bounds, query: query)
end

context 'with detail set to true' do
it 'calls find on GooglePlaces::Spot' do
allow(GooglePlaces::Spot).to receive(:list_by_bounds) { [fake_spot] }
expect(GooglePlaces::Spot).to receive(:find)
client.spots_by_bounds(bounds, query: query, detail: true)
end
end
end
it 'should request spots by radar' do
keywords = 'landmarks'
lat, lng = '51.511627', '-0.183778'
radius = 5000
@client = GooglePlaces::Client.new(api_key)
expect(GooglePlaces::Spot).to receive(:list_by_radar).with(lat, lng, api_key, {:radius=> radius, :keyword => keywords})

@client.spots_by_radar(lat, lng, :radius => radius, :keyword => keywords)

describe '::spots_by_radar' do
let(:keywords) { 'landmarks' }
let(:lat) { '51.511627' }
let(:lng) { '-0.183778' }
let(:radius) { 5000 }

it 'should request spots by radar' do
expect(GooglePlaces::Spot).to receive(:list_by_radar).with(
lat,
lng,
api_key,
radius: radius,
keyword: keywords
)
client.spots_by_radar(lat, lng, radius: radius, keyword: keywords)
end

it 'does not call find on GooglePlces::Spot' do
allow(GooglePlaces::Spot).to receive(:list_by_radar) { [fake_spot] }
expect(GooglePlaces::Spot).not_to receive(:find)
client.spots_by_radar(lat, lng, radius: radius, keyword: keywords)
end

context 'with detail set to true' do
it 'calls find on GooglePlaces::Spot' do
allow(GooglePlaces::Spot).to receive(:list_by_radar) { [fake_spot] }
expect(GooglePlaces::Spot).to receive(:find)
client.spots_by_radar(
lat,
lng,
radius: radius,
keyword: keywords,
detail: true
)
end
end
end

it 'should request predictions by input' do
input = 'Atlanta'
@client = GooglePlaces::Client.new(api_key)
expect(GooglePlaces::Prediction).to receive(:list_by_input).with(input, api_key, {})
describe '::predictions_by_input' do
let(:input) { 'Atlanta' }

@client.predictions_by_input(input)
it 'should request predictions by input' do
expect(GooglePlaces::Prediction).to receive(:list_by_input).with(
input,
api_key,
{}
)
client.predictions_by_input(input)
end
end

context 'List detailed spots', vcr: { cassette_name: 'list_spots_with_detail' } do
describe 'detailed spots', vcr: { cassette_name: 'list_spots_with_detail' } do
let(:lat) { '28.3852377' }
let(:lng) { '-81.566068' }
it 'should return spots with detail information' do
lat, lng = '28.3852377', '-81.566068'
@client = GooglePlaces::Client.new(api_key)

spots = @client.spots(lat, lng, detail: true)
spots = client.spots(lat, lng, detail: true)
expect(spots).to_not be_nil

for spot in spots
spots.each do |spot|
expect(spot.address_components).not_to be_nil
expect(spot.city).not_to be_nil
expect(spot.country).not_to be_nil
Expand Down

0 comments on commit e209f3f

Please sign in to comment.