googlemaps-services 1.2.0 → 1.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/googlemaps/services/client.rb +52 -55
- data/lib/googlemaps/services/directions.rb +22 -22
- data/lib/googlemaps/services/distancematrix.rb +17 -22
- data/lib/googlemaps/services/elevation.rb +10 -9
- data/lib/googlemaps/services/exceptions.rb +1 -1
- data/lib/googlemaps/services/geocoding.rb +15 -15
- data/lib/googlemaps/services/places.rb +41 -42
- data/lib/googlemaps/services/roads.rb +24 -24
- data/lib/googlemaps/services/timezone.rb +4 -4
- data/lib/googlemaps/services/util.rb +19 -18
- data/lib/googlemaps/services/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 18a00c19fa244488e45d19b1072506587f597e57
|
4
|
+
data.tar.gz: 1d4bf5cef38c7d6be03bd438d2e30278eef31ee3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 99aa38b29add2f487377ceef2a6cba9e9881defa8c2b6c3a0303a69bdbee8c2cfa4fd94414dda0d40fa2a4bd6b3f5a15b155dea9e66121862cd8d252a4aad270
|
7
|
+
data.tar.gz: da2efaedd9b47501bc815b005ae47e7a2f97552fcfba47bf61c89b84d5c8e64309ad4b99426cf6b30eedf6fbfc38b77cf8190a6e90abc3fc20b70c1b7b59f781
|
@@ -1,9 +1,9 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
1
|
+
require 'googlemaps/services/exceptions'
|
2
|
+
require 'googlemaps/services/version'
|
3
|
+
require 'googlemaps/services/util'
|
4
|
+
require 'nokogiri'
|
5
|
+
require 'net/http'
|
6
|
+
require 'json'
|
7
7
|
|
8
8
|
# Core functionality, common across all API requests.
|
9
9
|
#
|
@@ -13,9 +13,9 @@ module GoogleMaps
|
|
13
13
|
#
|
14
14
|
# @since 1.0.0
|
15
15
|
module Services
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
USER_AGENT = 'GoogleMapsRubyClient/' + VERSION
|
17
|
+
DEFAULT_BASE_URL = 'https://maps.googleapis.com'
|
18
|
+
RETRIABLE_STATUSES = [500, 503, 504]
|
19
19
|
|
20
20
|
# Performs requests to the Google Maps API web services.
|
21
21
|
class GoogleClient
|
@@ -43,30 +43,30 @@ module GoogleMaps
|
|
43
43
|
attr_accessor :response_format
|
44
44
|
|
45
45
|
def initialize(key:, client_id: nil, client_secret: nil, timeout: nil,
|
46
|
-
connect_timeout: nil, read_timeout: nil,retry_timeout: 60, request_opts:
|
46
|
+
connect_timeout: nil, read_timeout: nil,retry_timeout: 60, request_opts: {},
|
47
47
|
queries_per_second: 10, channel: nil, response_format: :json)
|
48
48
|
if !key && !(client_secret && client_id)
|
49
|
-
raise StandardError,
|
49
|
+
raise StandardError, 'Must provide API key or enterprise credentials when creationg client.'
|
50
50
|
end
|
51
51
|
|
52
|
-
if key && !key.start_with?(
|
53
|
-
raise StandardError,
|
52
|
+
if key && !key.start_with?('AIza')
|
53
|
+
raise StandardError, 'Invalid API key provided.'
|
54
54
|
end
|
55
55
|
|
56
56
|
if channel
|
57
|
-
|
58
|
-
raise StandardError,
|
57
|
+
unless client_id
|
58
|
+
raise StandardError, 'The channel argument must be used with a client ID.'
|
59
59
|
end
|
60
60
|
|
61
|
-
|
62
|
-
raise StandardError,
|
61
|
+
unless /^[a-zA-Z0-9._-]*$/.match(channel)
|
62
|
+
raise StandardError, 'The channel argument must be an ASCII alphanumeric string. The period (.), underscore (_) and hyphen (-) characters are allowed.'
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
66
|
self.key = key
|
67
67
|
|
68
68
|
if timeout && (connect_timeout || read_timeout)
|
69
|
-
raise StandardError,
|
69
|
+
raise StandardError, 'Specify either timeout, or connect_timeout and read_timeout.'
|
70
70
|
end
|
71
71
|
|
72
72
|
if connect_timeout && read_timeout
|
@@ -79,18 +79,16 @@ module GoogleMaps
|
|
79
79
|
self.client_secret = client_secret
|
80
80
|
self.channel = channel
|
81
81
|
self.retry_timeout = retry_timeout
|
82
|
-
self.request_opts = request_opts
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
})
|
88
|
-
|
82
|
+
self.request_opts = request_opts.merge({
|
83
|
+
:headers => {'User-Agent' => USER_AGENT},
|
84
|
+
:timeout => self.timeout,
|
85
|
+
:verify => true
|
86
|
+
})
|
89
87
|
self.queries_per_second = queries_per_second
|
90
88
|
self.sent_times = Array.new
|
91
89
|
|
92
90
|
if response_format
|
93
|
-
raise StandardError,
|
91
|
+
raise StandardError, 'Unsupported response format. Should be either :json or :xml.' unless [:json, :xml].include? response_format
|
94
92
|
self.response_format = response_format
|
95
93
|
end
|
96
94
|
end
|
@@ -108,9 +106,9 @@ module GoogleMaps
|
|
108
106
|
# @param [Hash] request_opts Additional options for the Net::HTTP client.
|
109
107
|
#
|
110
108
|
# @return [Hash, Array] response body, either in JSON or XML.
|
111
|
-
def get(url:, params:, first_request_time: nil, retry_counter: nil, base_url:
|
109
|
+
def get(url:, params:, first_request_time: nil, retry_counter: nil, base_url: DEFAULT_BASE_URL,
|
112
110
|
accepts_clientid: true, extract_body: nil, request_opts: nil)
|
113
|
-
|
111
|
+
unless first_request_time
|
114
112
|
first_request_time = Util.current_time
|
115
113
|
end
|
116
114
|
|
@@ -125,7 +123,7 @@ module GoogleMaps
|
|
125
123
|
# at 1, so subtract that first.
|
126
124
|
delay_seconds = 0.5 * 1.5 ** (retry_counter - 1)
|
127
125
|
# Jitter this value by 50% and pause.
|
128
|
-
sleep(delay_seconds * (random.random
|
126
|
+
sleep(delay_seconds * (random.random + 0.5))
|
129
127
|
end
|
130
128
|
|
131
129
|
authed_url = generate_auth_url(url, params, accepts_clientid)
|
@@ -143,7 +141,7 @@ module GoogleMaps
|
|
143
141
|
request_opts[:headers].each { |header,value| req.add_field(header, value) }
|
144
142
|
|
145
143
|
http = Net::HTTP.new(uri.host, uri.port)
|
146
|
-
http.use_ssl = (uri.scheme ==
|
144
|
+
http.use_ssl = (uri.scheme == 'https')
|
147
145
|
# Get HTTP response
|
148
146
|
resp = http.request(req)
|
149
147
|
|
@@ -152,10 +150,10 @@ module GoogleMaps
|
|
152
150
|
when Net::HTTPRequestTimeOut
|
153
151
|
raise Timeout
|
154
152
|
when Exception
|
155
|
-
raise TransportError,
|
153
|
+
raise TransportError, 'HTTP GET request failed.'
|
156
154
|
end
|
157
155
|
|
158
|
-
if
|
156
|
+
if RETRIABLE_STATUSES.include? resp.code.to_i
|
159
157
|
# Retry request
|
160
158
|
self.get(url, params, first_request_time, retry_counter + 1,
|
161
159
|
base_url, accepts_clientid, extract_body)
|
@@ -185,9 +183,8 @@ module GoogleMaps
|
|
185
183
|
self.sent_times.push(Util.current_time)
|
186
184
|
return result
|
187
185
|
rescue RetriableRequest
|
188
|
-
#
|
189
|
-
return self.get(url, params, first_request_time, retry_counter + 1,
|
190
|
-
base_url, accepts_clientid, extract_body)
|
186
|
+
# Retry request
|
187
|
+
return self.get(url, params, first_request_time, retry_counter + 1, base_url, accepts_clientid, extract_body)
|
191
188
|
end
|
192
189
|
end
|
193
190
|
|
@@ -201,7 +198,7 @@ module GoogleMaps
|
|
201
198
|
def get_json_body(resp)
|
202
199
|
status_code = resp.code.to_i
|
203
200
|
if status_code >= 300 && status_code < 400
|
204
|
-
return resp[
|
201
|
+
return resp['location']
|
205
202
|
end
|
206
203
|
|
207
204
|
if status_code != 200
|
@@ -212,20 +209,20 @@ module GoogleMaps
|
|
212
209
|
begin
|
213
210
|
body = JSON.parse(resp.body)
|
214
211
|
rescue JSON::ParserError
|
215
|
-
raise APIError.new(status_code),
|
212
|
+
raise APIError.new(status_code), 'Received a malformed JSON response.'
|
216
213
|
end
|
217
214
|
|
218
|
-
api_status = body[
|
219
|
-
if api_status ==
|
215
|
+
api_status = body['status']
|
216
|
+
if api_status == 'OK' || api_status == 'ZERO_RESULTS'
|
220
217
|
return body
|
221
218
|
end
|
222
219
|
|
223
|
-
if api_status ==
|
220
|
+
if api_status == 'OVER_QUERY_LIMIT'
|
224
221
|
raise RetriableRequest
|
225
222
|
end
|
226
223
|
|
227
|
-
if body.key?(
|
228
|
-
raise APIError.new(api_status), body[
|
224
|
+
if body.key?('error_message')
|
225
|
+
raise APIError.new(api_status), body['error_message']
|
229
226
|
else
|
230
227
|
raise APIError.new(api_status)
|
231
228
|
end
|
@@ -241,7 +238,7 @@ module GoogleMaps
|
|
241
238
|
def get_xml_body(resp)
|
242
239
|
status_code = resp.code.to_i
|
243
240
|
if status_code >= 300 && status_code < 400
|
244
|
-
return resp[
|
241
|
+
return resp['location']
|
245
242
|
end
|
246
243
|
|
247
244
|
if status_code != 200
|
@@ -251,19 +248,19 @@ module GoogleMaps
|
|
251
248
|
begin
|
252
249
|
doc = Nokogiri::XML.parse(resp.body)
|
253
250
|
rescue
|
254
|
-
raise APIError.new(status_code),
|
251
|
+
raise APIError.new(status_code), 'Received a malformed XML response.'
|
255
252
|
end
|
256
253
|
|
257
|
-
api_status = doc.xpath(
|
258
|
-
if api_status ==
|
254
|
+
api_status = doc.xpath('//status').first.text
|
255
|
+
if api_status == 'OK' || api_status == 'ZERO_RESULTS'
|
259
256
|
return doc
|
260
257
|
end
|
261
258
|
|
262
|
-
if api_status ==
|
259
|
+
if api_status == 'OVER_QUERY_LIMIT'
|
263
260
|
raise RetriableRequest
|
264
261
|
end
|
265
262
|
|
266
|
-
error_message = doc.xpath(
|
263
|
+
error_message = doc.xpath('//error_message')
|
267
264
|
if error_message
|
268
265
|
raise APIError.new(api_status), error_message.text
|
269
266
|
else
|
@@ -283,21 +280,21 @@ module GoogleMaps
|
|
283
280
|
def generate_auth_url(path, params={}, accepts_clientid)
|
284
281
|
if accepts_clientid && self.client_id && self.client_secret
|
285
282
|
if self.channel
|
286
|
-
params[
|
283
|
+
params['channel'] = self.channel
|
287
284
|
end
|
288
|
-
params[
|
285
|
+
params['client'] = self.client_id
|
289
286
|
|
290
|
-
path = [path, Util.urlencode_params(params)].join(
|
287
|
+
path = [path, Util.urlencode_params(params)].join('?')
|
291
288
|
sig = Util.sign_hmac(self.client_secret, path)
|
292
|
-
return path +
|
289
|
+
return path + '&signature=' + sig
|
293
290
|
end
|
294
291
|
|
295
292
|
if self.key
|
296
|
-
params[
|
297
|
-
return path +
|
293
|
+
params['key'] = self.key
|
294
|
+
return path + '?' + Util.urlencode_params(params)
|
298
295
|
end
|
299
296
|
|
300
|
-
raise StandardError,
|
297
|
+
raise StandardError, 'Must provide API key for this API. It does not accept enterprise credentials.'
|
301
298
|
end
|
302
299
|
|
303
300
|
private :get_json_body, :get_xml_body, :generate_auth_url
|
@@ -1,8 +1,8 @@
|
|
1
|
-
require
|
1
|
+
require 'googlemaps/services/util'
|
2
2
|
|
3
3
|
module GoogleMaps
|
4
4
|
module Services
|
5
|
-
|
5
|
+
TRAVEL_MODES = %w(driving walking bicycling transit)
|
6
6
|
|
7
7
|
# Performs requests to the Google Maps Directions API.
|
8
8
|
#
|
@@ -48,74 +48,74 @@ module GoogleMaps
|
|
48
48
|
arrival_time: nil, optimize_waypoints: false, transit_mode: nil,
|
49
49
|
transit_routing_preference: nil, traffic_model: nil)
|
50
50
|
params = {
|
51
|
-
|
52
|
-
|
51
|
+
'origin' => Convert.to_latlng(origin),
|
52
|
+
'destination' => Convert.to_latlng(destination)
|
53
53
|
}
|
54
54
|
|
55
55
|
if mode
|
56
|
-
|
57
|
-
raise StandardError,
|
56
|
+
unless TRAVEL_MODES.include? mode
|
57
|
+
raise StandardError, 'invalid travel mode.'
|
58
58
|
end
|
59
|
-
params[
|
59
|
+
params['mode'] = mode
|
60
60
|
end
|
61
61
|
|
62
62
|
if waypoints
|
63
63
|
waypoints = Convert.piped_location(waypoints)
|
64
64
|
if optimize_waypoints
|
65
|
-
waypoints =
|
65
|
+
waypoints = 'optimize:true|' + waypoints
|
66
66
|
end
|
67
|
-
params[
|
67
|
+
params['waypoints'] = waypoints
|
68
68
|
end
|
69
69
|
|
70
70
|
if alternatives
|
71
|
-
params[
|
71
|
+
params['alternatives'] = true
|
72
72
|
end
|
73
73
|
|
74
74
|
if avoid
|
75
|
-
params[
|
75
|
+
params['avoid'] = Convert.join_array('|', avoid)
|
76
76
|
end
|
77
77
|
|
78
78
|
if language
|
79
|
-
params[
|
79
|
+
params['language'] = language
|
80
80
|
end
|
81
81
|
|
82
82
|
if units
|
83
|
-
params[
|
83
|
+
params['units'] = units
|
84
84
|
end
|
85
85
|
|
86
86
|
if region
|
87
|
-
params[
|
87
|
+
params['region'] = region
|
88
88
|
end
|
89
89
|
|
90
90
|
if departure_time
|
91
|
-
params[
|
91
|
+
params['departure_time'] = Convert.unix_time(departure_time)
|
92
92
|
end
|
93
93
|
|
94
94
|
if arrival_time
|
95
|
-
params[
|
95
|
+
params['arrival_time'] = Convert.unix_time(arrival_time)
|
96
96
|
end
|
97
97
|
|
98
98
|
if departure_time && arrival_time
|
99
|
-
raise StandardError,
|
99
|
+
raise StandardError, 'should not specify both departure_time and arrival_time.'
|
100
100
|
end
|
101
101
|
|
102
102
|
if transit_mode
|
103
|
-
params[
|
103
|
+
params['transit_mode'] = Convert.join_array('|', transit_mode)
|
104
104
|
end
|
105
105
|
|
106
106
|
if transit_routing_preference
|
107
|
-
params[
|
107
|
+
params['transit_routing_preference'] = transit_routing_preference
|
108
108
|
end
|
109
109
|
|
110
110
|
if traffic_model
|
111
|
-
params[
|
111
|
+
params['traffic_model'] = traffic_model
|
112
112
|
end
|
113
113
|
|
114
114
|
case self.client.response_format
|
115
115
|
when :xml
|
116
|
-
self.client.get(url:
|
116
|
+
self.client.get(url: '/maps/api/directions/xml', params: params).xpath('//route')
|
117
117
|
else
|
118
|
-
self.client.get(url:
|
118
|
+
self.client.get(url: '/maps/api/directions/json', params: params)['routes']
|
119
119
|
end
|
120
120
|
end
|
121
121
|
end
|
@@ -1,9 +1,8 @@
|
|
1
|
-
require
|
1
|
+
require 'googlemaps/services/util'
|
2
2
|
|
3
3
|
module GoogleMaps
|
4
4
|
module Services
|
5
|
-
|
6
|
-
$AVOIDS = ["tolls", "highways", "ferries"]
|
5
|
+
AVOIDS = %w(tolls highways ferries)
|
7
6
|
|
8
7
|
# Performs requests to the Google Maps Distance Matrix API.
|
9
8
|
#
|
@@ -41,57 +40,53 @@ module GoogleMaps
|
|
41
40
|
units: nil, departure_time: nil, arrival_time: nil, transit_mode: nil,
|
42
41
|
transit_routing_preference: nil, traffic_model: nil)
|
43
42
|
params = {
|
44
|
-
|
45
|
-
|
43
|
+
'origins' => Convert.piped_location(origins),
|
44
|
+
'destinations' => Convert.piped_location(destinations)
|
46
45
|
}
|
47
46
|
|
48
47
|
if mode
|
49
|
-
|
50
|
-
|
51
|
-
end
|
52
|
-
params["mode"] = mode
|
48
|
+
raise StandardError, 'Invalid travel mode.' unless TRAVEL_MODES.include? mode
|
49
|
+
params['mode'] = mode
|
53
50
|
end
|
54
51
|
|
55
52
|
if language
|
56
|
-
params[
|
53
|
+
params['language'] = language
|
57
54
|
end
|
58
55
|
|
59
56
|
if avoid
|
60
|
-
|
61
|
-
|
62
|
-
end
|
63
|
-
params["avoid"] = avoid
|
57
|
+
raise StandardError, 'Invalid route restriction.' unless AVOIDS.include? avoid
|
58
|
+
params['avoid'] = avoid
|
64
59
|
end
|
65
60
|
|
66
61
|
if units
|
67
|
-
params[
|
62
|
+
params['units'] = units
|
68
63
|
end
|
69
64
|
|
70
65
|
if departure_time
|
71
|
-
params[
|
66
|
+
params['departure_time'] = Convert.unix_time(departure_time)
|
72
67
|
end
|
73
68
|
|
74
69
|
if arrival_time
|
75
|
-
params[
|
70
|
+
params['arrival_time'] = Convert.unix_time(arrival_time)
|
76
71
|
end
|
77
72
|
|
78
73
|
if departure_time && arrival_time
|
79
|
-
raise StandardError,
|
74
|
+
raise StandardError, 'Should not specify both departure_time and arrival_time.'
|
80
75
|
end
|
81
76
|
|
82
77
|
if transit_mode
|
83
|
-
params[
|
78
|
+
params['transit_mode'] = Convert.join_array('|', transit_mode)
|
84
79
|
end
|
85
80
|
|
86
81
|
if transit_routing_preference
|
87
|
-
params[
|
82
|
+
params['transit_routing_preference'] = transit_routing_preference
|
88
83
|
end
|
89
84
|
|
90
85
|
if traffic_model
|
91
|
-
params[
|
86
|
+
params['traffic_model'] = traffic_model
|
92
87
|
end
|
93
88
|
|
94
|
-
self.client.get(url: "/maps/api/distancematrix/#{self.client.response_format}", params: params)
|
89
|
+
self.client.get(url: "/maps/api/distancematrix/#{self.client.response_format}", params: params)
|
95
90
|
end
|
96
91
|
end
|
97
92
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'googlemaps/services/util'
|
2
2
|
|
3
3
|
|
4
4
|
module GoogleMaps
|
@@ -29,30 +29,31 @@ module GoogleMaps
|
|
29
29
|
params = {}
|
30
30
|
|
31
31
|
if path && locations
|
32
|
-
raise StandardError,
|
32
|
+
raise StandardError, 'Should not specify both path and locations.'
|
33
33
|
end
|
34
34
|
|
35
35
|
if locations
|
36
|
-
params[
|
36
|
+
params['locations'] = Convert.shortest_path(locations)
|
37
37
|
end
|
38
38
|
|
39
39
|
if path
|
40
|
-
|
40
|
+
case path.class
|
41
|
+
when String
|
41
42
|
path = "enc:#{path}"
|
42
|
-
|
43
|
+
when Array
|
43
44
|
path = Convert.shortest_path(path)
|
44
45
|
else
|
45
|
-
raise TypeError,
|
46
|
+
raise TypeError, 'Path should be either a String or an Array.'
|
46
47
|
end
|
47
48
|
|
48
|
-
params = {
|
49
|
+
params = {'path' => path, 'samples' => samples }
|
49
50
|
end
|
50
51
|
|
51
52
|
case self.client.response_format
|
52
53
|
when :xml
|
53
|
-
self.client.get(url:
|
54
|
+
self.client.get(url: '/maps/api/elevation/xml', params: params).xpath('//result')
|
54
55
|
else
|
55
|
-
self.client.get(url:
|
56
|
+
self.client.get(url: '/maps/api/elevation/json', params: params)['results']
|
56
57
|
end
|
57
58
|
end
|
58
59
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'googlemaps/services/util'
|
2
2
|
|
3
3
|
|
4
4
|
module GoogleMaps
|
@@ -34,30 +34,30 @@ module GoogleMaps
|
|
34
34
|
params = {}
|
35
35
|
|
36
36
|
if address
|
37
|
-
params[
|
37
|
+
params['address'] = address
|
38
38
|
end
|
39
39
|
|
40
40
|
if components
|
41
|
-
params[
|
41
|
+
params['components'] = Convert.components(components)
|
42
42
|
end
|
43
43
|
|
44
44
|
if bounds
|
45
|
-
params[
|
45
|
+
params['bounds'] = Convert.bounds(bounds)
|
46
46
|
end
|
47
47
|
|
48
48
|
if region
|
49
|
-
params[
|
49
|
+
params['region'] = region
|
50
50
|
end
|
51
51
|
|
52
52
|
if language
|
53
|
-
params[
|
53
|
+
params['language'] = language
|
54
54
|
end
|
55
55
|
|
56
56
|
case self.client.response_format
|
57
57
|
when :xml
|
58
|
-
self.client.get(url:
|
58
|
+
self.client.get(url: '/maps/api/geocode/xml', params: params).xpath('//result')
|
59
59
|
else
|
60
|
-
self.client.get(url:
|
60
|
+
self.client.get(url: '/maps/api/geocode/json', params: params)['results']
|
61
61
|
end
|
62
62
|
end
|
63
63
|
end
|
@@ -86,28 +86,28 @@ module GoogleMaps
|
|
86
86
|
# Check if latlng param is a place_id string.
|
87
87
|
# 'place_id' strings do not contain commas; latlng strings do.
|
88
88
|
if latlng.is_a?(String) && !latlng.include?("'")
|
89
|
-
params = {
|
89
|
+
params = {'place_id' => latlng}
|
90
90
|
else
|
91
|
-
params = {
|
91
|
+
params = {'latlng' => Convert.to_latlng(latlng)}
|
92
92
|
end
|
93
93
|
|
94
94
|
if result_type
|
95
|
-
params[
|
95
|
+
params['result_type'] = Convert.join_array('|', result_type)
|
96
96
|
end
|
97
97
|
|
98
98
|
if location_type
|
99
|
-
params[
|
99
|
+
params['location_type'] = Convert.join_array('|', location_type)
|
100
100
|
end
|
101
101
|
|
102
102
|
if language
|
103
|
-
params[
|
103
|
+
params['language'] = language
|
104
104
|
end
|
105
105
|
|
106
106
|
case self.client.response_format
|
107
107
|
when :xml
|
108
|
-
self.client.get(url:
|
108
|
+
self.client.get(url: '/maps/api/geocode/xml', params: params).xpath('//result')
|
109
109
|
else
|
110
|
-
self.client.get(url:
|
110
|
+
self.client.get(url: '/maps/api/geocode/json', params: params)['results']
|
111
111
|
end
|
112
112
|
end
|
113
113
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'googlemaps/services/util'
|
2
2
|
|
3
3
|
module GoogleMaps
|
4
4
|
module Services
|
@@ -27,8 +27,8 @@ module GoogleMaps
|
|
27
27
|
# @return [Hash, Nokogiri::XML::Document] Valid JSON or XML response.
|
28
28
|
def search(query:, location: nil, radius: nil, language: nil, min_price: nil,
|
29
29
|
max_price: nil, open_now: false, type: nil, page_token: nil)
|
30
|
-
_places(url_part:
|
31
|
-
language: language, min_price: min_price,
|
30
|
+
_places(url_part: 'text', query: query, location: location, radius: radius,
|
31
|
+
language: language, min_price: min_price, max_price: max_price,
|
32
32
|
open_now: open_now, type: type, page_token: page_token)
|
33
33
|
end
|
34
34
|
|
@@ -49,15 +49,15 @@ module GoogleMaps
|
|
49
49
|
# @return [Hash, Nokogiri::XML::Document] Valid JSON or XML response.
|
50
50
|
def nearby(location:, radius: nil, keyword: nil, language: nil, min_price: nil,
|
51
51
|
max_price: nil, name: nil, open_now: false, rank_by: nil, type: nil, page_token: nil)
|
52
|
-
if rank_by ==
|
52
|
+
if rank_by == 'distance'
|
53
53
|
if !(keyword || name || type)
|
54
|
-
raise StandardError,
|
54
|
+
raise StandardError, 'either a keyword, name or type arg is required when rank_by is set to distance.'
|
55
55
|
elsif radius
|
56
|
-
raise StandardError,
|
56
|
+
raise StandardError, 'radius cannot be specified when rank_by is set to distance.'
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
-
_places(url_part:
|
60
|
+
_places(url_part: 'nearby', location: location, radius: radius, keyword: keyword, language: language,
|
61
61
|
min_price: min_price, max_price: max_price, name: name, open_now: open_now, rank_by: rank_by,
|
62
62
|
type: type, page_token: page_token)
|
63
63
|
end
|
@@ -76,13 +76,13 @@ module GoogleMaps
|
|
76
76
|
# @return [Hash, Nokogiri::XML::Document] Valid JSON or XML response.
|
77
77
|
def radar(location:, radius:, keyword: nil, min_price: nil,
|
78
78
|
max_price: nil, name: nil, open_now: false, type: nil)
|
79
|
-
|
80
|
-
raise StandardError,
|
79
|
+
unless keyword || name || type
|
80
|
+
raise StandardError, 'either a keyword, name, or type arg is required.'
|
81
81
|
end
|
82
82
|
|
83
|
-
_places(url_part:
|
84
|
-
|
85
|
-
|
83
|
+
_places(url_part: 'radar', location: location, radius: radius,
|
84
|
+
keyword: keyword, min_price: min_price, max_price: max_price,
|
85
|
+
name: name, open_now: open_now, type: type)
|
86
86
|
end
|
87
87
|
|
88
88
|
# Handler for "places", "places_nearby" and "places_radar" queries.
|
@@ -90,52 +90,51 @@ module GoogleMaps
|
|
90
90
|
def _places(url_part:, query: nil, location: nil, radius: nil, keyword: nil, language: nil,
|
91
91
|
min_price: 0, max_price: 4, name: nil, open_now: false, rank_by: nil, type: nil,
|
92
92
|
page_token: nil)
|
93
|
-
params = {
|
93
|
+
params = {'minprice' => min_price, 'maxprice' => max_price }
|
94
94
|
|
95
95
|
if query
|
96
|
-
params[
|
96
|
+
params['query'] = query
|
97
97
|
end
|
98
98
|
|
99
99
|
if location
|
100
|
-
params[
|
100
|
+
params['location'] = Convert.to_latlng(location)
|
101
101
|
end
|
102
102
|
|
103
103
|
if radius
|
104
|
-
params[
|
104
|
+
params['radius'] = radius
|
105
105
|
end
|
106
106
|
|
107
107
|
if keyword
|
108
|
-
params[
|
108
|
+
params['keyword'] = keyword
|
109
109
|
end
|
110
110
|
|
111
111
|
if language
|
112
|
-
params[
|
112
|
+
params['language'] = language
|
113
113
|
end
|
114
114
|
|
115
115
|
if name
|
116
|
-
params[
|
116
|
+
params['name'] = Convert.join_array(' ', name)
|
117
117
|
end
|
118
118
|
|
119
119
|
if open_now
|
120
|
-
params[
|
120
|
+
params['opennow'] = 'true'
|
121
121
|
end
|
122
122
|
|
123
123
|
if rank_by
|
124
|
-
params[
|
124
|
+
params['rankby'] = rank_by
|
125
125
|
end
|
126
126
|
|
127
127
|
if type
|
128
|
-
params[
|
128
|
+
params['type'] = type
|
129
129
|
end
|
130
130
|
|
131
131
|
if page_token
|
132
|
-
params[
|
132
|
+
params['pagetoken'] = page_token
|
133
133
|
end
|
134
134
|
|
135
135
|
self.client.get(url: "/maps/api/place/#{url_part}search/#{self.client.response_format}", params: params)
|
136
136
|
end
|
137
137
|
|
138
|
-
|
139
138
|
# Comprehensive details for an individual place.
|
140
139
|
#
|
141
140
|
# @param [String] place_id A textual identifier that uniquely identifies a place, returned from a Places search.
|
@@ -143,9 +142,9 @@ module GoogleMaps
|
|
143
142
|
#
|
144
143
|
# @return [Hash, Nokogiri::XML::Document] Valid JSON or XML response.
|
145
144
|
def place_details(place_id:, language: nil)
|
146
|
-
params = {
|
145
|
+
params = {'placeid' => place_id }
|
147
146
|
if language
|
148
|
-
params[
|
147
|
+
params['language'] = language
|
149
148
|
end
|
150
149
|
|
151
150
|
self.client.get(url: "/maps/api/place/details/#{self.client.response_format}", params: params)
|
@@ -159,21 +158,21 @@ module GoogleMaps
|
|
159
158
|
#
|
160
159
|
# @return [String] URL of the photo.
|
161
160
|
def place_photo(photo_reference:, max_width: nil, max_height: nil)
|
162
|
-
|
163
|
-
raise StandardError,
|
161
|
+
unless max_width || max_height
|
162
|
+
raise StandardError, 'a max_width or max_height arg is required'
|
164
163
|
end
|
165
164
|
|
166
|
-
params = {
|
165
|
+
params = {'photoreference' => photo_reference}
|
167
166
|
|
168
167
|
if max_width
|
169
|
-
params[
|
168
|
+
params['maxwidth'] = max_width
|
170
169
|
end
|
171
170
|
|
172
171
|
if max_height
|
173
|
-
params[
|
172
|
+
params['maxheight'] = max_height
|
174
173
|
end
|
175
174
|
|
176
|
-
self.client.get(url:
|
175
|
+
self.client.get(url: '/maps/api/place/photo', params: params)
|
177
176
|
end
|
178
177
|
|
179
178
|
# Returns Place predictions given a textual search string and optional geographic bounds.
|
@@ -202,7 +201,7 @@ module GoogleMaps
|
|
202
201
|
#
|
203
202
|
# @return [Array, Nokogiri::XML::NodeSet] Array of predictions.
|
204
203
|
def autocomplete_query(input_text:, offset: nil, location: nil, radius: nil, language: nil)
|
205
|
-
_autocomplete(url_part:
|
204
|
+
_autocomplete(url_part: 'query', input_text: input_text, offset: offset,
|
206
205
|
location: location, radius: radius, language: language)
|
207
206
|
end
|
208
207
|
|
@@ -210,37 +209,37 @@ module GoogleMaps
|
|
210
209
|
# @private
|
211
210
|
def _autocomplete(url_part:, input_text:, offset: nil, location: nil,
|
212
211
|
radius: nil, language: nil, type: nil, components: nil)
|
213
|
-
params = {
|
212
|
+
params = {'input' => input_text }
|
214
213
|
|
215
214
|
if offset
|
216
|
-
params[
|
215
|
+
params['offset'] = offset
|
217
216
|
end
|
218
217
|
|
219
218
|
if location
|
220
|
-
params[
|
219
|
+
params['location'] = Convert.to_latlng(location)
|
221
220
|
end
|
222
221
|
|
223
222
|
if radius
|
224
|
-
params[
|
223
|
+
params['radius'] = radius
|
225
224
|
end
|
226
225
|
|
227
226
|
if language
|
228
|
-
params[
|
227
|
+
params['language'] = language
|
229
228
|
end
|
230
229
|
|
231
230
|
if type
|
232
|
-
params[
|
231
|
+
params['type'] = type
|
233
232
|
end
|
234
233
|
|
235
234
|
if components
|
236
|
-
params[
|
235
|
+
params['components'] = Convert.components(components)
|
237
236
|
end
|
238
237
|
|
239
238
|
case self.client.response_format
|
240
239
|
when :xml
|
241
|
-
self.client.get(url: "/maps/api/place/#{url_part}autocomplete/xml", params: params).xpath(
|
240
|
+
self.client.get(url: "/maps/api/place/#{url_part}autocomplete/xml", params: params).xpath('//prediction')
|
242
241
|
else
|
243
|
-
self.client.get(url: "/maps/api/place/#{url_part}autocomplete/json", params: params)[
|
242
|
+
self.client.get(url: "/maps/api/place/#{url_part}autocomplete/json", params: params)['predictions']
|
244
243
|
end
|
245
244
|
end
|
246
245
|
|
@@ -1,11 +1,10 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require 'googlemaps/services/exceptions'
|
2
|
+
require 'googlemaps/services/util'
|
3
|
+
require 'json'
|
4
4
|
|
5
5
|
module GoogleMaps
|
6
6
|
module Services
|
7
|
-
|
8
|
-
$ROADS_BASE_URL = "https://roads.googleapis.com"
|
7
|
+
ROADS_BASE_URL = 'https://roads.googleapis.com'
|
9
8
|
|
10
9
|
# Performs requests to the Google Maps Roads API.
|
11
10
|
class Roads
|
@@ -17,19 +16,19 @@ module GoogleMaps
|
|
17
16
|
begin
|
18
17
|
body = JSON.parse(resp.body)
|
19
18
|
rescue JSON::ParserError
|
20
|
-
raise APIError.new(status_code),
|
19
|
+
raise APIError.new(status_code), 'Received malformed response.'
|
21
20
|
end
|
22
21
|
|
23
|
-
if body.key?(
|
24
|
-
error = body[
|
25
|
-
status = error[
|
22
|
+
if body.key?('error')
|
23
|
+
error = body['error']
|
24
|
+
status = error['status']
|
26
25
|
|
27
|
-
if status ==
|
26
|
+
if status == 'RESOURCE_EXHAUSTED'
|
28
27
|
raise RetriableRequest
|
29
28
|
end
|
30
29
|
|
31
|
-
if error.key?(
|
32
|
-
raise APIError.new(status), error[
|
30
|
+
if error.key?('message')
|
31
|
+
raise APIError.new(status), error['message']
|
33
32
|
else
|
34
33
|
raise APIError.new(status)
|
35
34
|
end
|
@@ -59,14 +58,14 @@ module GoogleMaps
|
|
59
58
|
#
|
60
59
|
# @return [Array] Array of snapped points.
|
61
60
|
def snap_to_roads(path:, interpolate: false)
|
62
|
-
params = {
|
61
|
+
params = {'path' => Convert.piped_location(path) }
|
63
62
|
|
64
63
|
if interpolate
|
65
|
-
params[
|
64
|
+
params['interpolate'] = 'true'
|
66
65
|
end
|
67
66
|
|
68
|
-
self.client.get(url:
|
69
|
-
accepts_clientid: false, extract_body: @@_roads_extract)[
|
67
|
+
self.client.get(url: '/v1/snapToRoads', params: params, base_url: ROADS_BASE_URL,
|
68
|
+
accepts_clientid: false, extract_body: @@_roads_extract)['snappedPoints']
|
70
69
|
end
|
71
70
|
|
72
71
|
# Returns the posted speed limit (in km/h) for given road segments.
|
@@ -78,10 +77,10 @@ module GoogleMaps
|
|
78
77
|
def speed_limits(place_ids:)
|
79
78
|
raise StandardError, "#{__method__.to_s} expected an Array for place_ids." unless place_ids.is_a? Array
|
80
79
|
|
81
|
-
params = {
|
80
|
+
params = {'placeId' => place_ids}
|
82
81
|
|
83
|
-
self.client.get(url:
|
84
|
-
accepts_clientid: false, extract_body: @@_roads_extract)[
|
82
|
+
self.client.get(url: '/v1/speedLimits', params: params, base_url: ROADS_BASE_URL,
|
83
|
+
accepts_clientid: false, extract_body: @@_roads_extract)['speedLimits']
|
85
84
|
end
|
86
85
|
|
87
86
|
# Returns the posted speed limit (in km/h) for given road segments.
|
@@ -91,9 +90,9 @@ module GoogleMaps
|
|
91
90
|
#
|
92
91
|
# @return [Hash] Hash with an array of speed limits and an array of the snapped points.
|
93
92
|
def snapped_speed_limits(path:)
|
94
|
-
params = {
|
93
|
+
params = {'path' => Convert.piped_location(path)}
|
95
94
|
|
96
|
-
self.client.get(url:
|
95
|
+
self.client.get(url: '/v1/speedLimits', params: params, base_url: ROADS_BASE_URL,
|
97
96
|
accepts_clientid: false, extract_body: @@_roads_extract)
|
98
97
|
end
|
99
98
|
|
@@ -105,11 +104,12 @@ module GoogleMaps
|
|
105
104
|
#
|
106
105
|
# @return [Array] An array of snapped points.
|
107
106
|
def nearest_roads(points:)
|
108
|
-
params = {
|
107
|
+
params = {'points' => Convert.piped_location(points)}
|
109
108
|
|
110
|
-
self.client.get(url:
|
111
|
-
accepts_clientid: false, extract_body: @@_roads_extract)[
|
109
|
+
self.client.get(url: '/v1/nearestRoads', params: params, base_url: ROADS_BASE_URL,
|
110
|
+
accepts_clientid: false, extract_body: @@_roads_extract)['snappedPoints']
|
112
111
|
end
|
113
112
|
end
|
113
|
+
|
114
114
|
end
|
115
115
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'googlemaps/services/util'
|
2
2
|
|
3
3
|
module GoogleMaps
|
4
4
|
module Services
|
@@ -27,12 +27,12 @@ module GoogleMaps
|
|
27
27
|
# @return [Hash] Valid JSON or XML response.
|
28
28
|
def query(location:, timestamp: nil, language: nil)
|
29
29
|
params = {
|
30
|
-
|
31
|
-
|
30
|
+
'location' => Convert.to_latlng(location),
|
31
|
+
'timestamp' => Convert.unix_time(timestamp || Util.current_utctime)
|
32
32
|
}
|
33
33
|
|
34
34
|
if language
|
35
|
-
params[
|
35
|
+
params['language'] = language
|
36
36
|
end
|
37
37
|
|
38
38
|
self.client.get(url: "/maps/api/timezone/#{self.client.response_format}", params: params)
|
@@ -1,8 +1,8 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
1
|
+
require 'net/http'
|
2
|
+
require 'openssl'
|
3
|
+
require 'base64'
|
4
|
+
require 'date'
|
5
|
+
require 'erb'
|
6
6
|
|
7
7
|
module GoogleMaps
|
8
8
|
module Services
|
@@ -12,7 +12,7 @@ module GoogleMaps
|
|
12
12
|
if has_key?(meth.to_s)
|
13
13
|
self[meth.to_s]
|
14
14
|
else
|
15
|
-
raise NoMethodError,
|
15
|
+
raise NoMethodError, "undefined method #{meth} for #{self}"
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -102,11 +102,12 @@ module GoogleMaps
|
|
102
102
|
#
|
103
103
|
# @return [String] seconds since unix epoch.
|
104
104
|
def self.unix_time(val)
|
105
|
-
|
105
|
+
case val
|
106
|
+
when Integer
|
106
107
|
val.to_s
|
107
|
-
|
108
|
+
when Time
|
108
109
|
val.to_i.to_s
|
109
|
-
|
110
|
+
when Date
|
110
111
|
val.to_time.to_i.to_s
|
111
112
|
else
|
112
113
|
raise TypeError, "#{__method__.to_s} expected value to be Integer, Time or Date."
|
@@ -123,9 +124,10 @@ module GoogleMaps
|
|
123
124
|
#
|
124
125
|
# @return [String] comma-separated string.
|
125
126
|
def self.to_latlng(arg)
|
126
|
-
|
127
|
+
case arg
|
128
|
+
when String
|
127
129
|
arg
|
128
|
-
|
130
|
+
when Hash
|
129
131
|
"#{self.format_float(arg[:lat])},#{self.format_float(arg[:lng])}"
|
130
132
|
else
|
131
133
|
raise TypeError, "#{__method__.to_s} expected location to be String or Hash."
|
@@ -140,7 +142,7 @@ module GoogleMaps
|
|
140
142
|
#
|
141
143
|
# @return [String] formatted value of lat or lng float
|
142
144
|
def self.format_float(arg)
|
143
|
-
arg.to_s.chomp(
|
145
|
+
arg.to_s.chomp('0').chomp('.')
|
144
146
|
end
|
145
147
|
|
146
148
|
# Joins an array of locations into a pipe separated string, handling
|
@@ -153,8 +155,8 @@ module GoogleMaps
|
|
153
155
|
#
|
154
156
|
# @return [String] pipe-separated string.
|
155
157
|
def self.piped_location(arg)
|
156
|
-
raise TypeError, "#{__method__.to_s} expected argument to be an Array." unless arg.instance_of?
|
157
|
-
arg.map { |location| to_latlng(location) }.join(
|
158
|
+
raise TypeError, "#{__method__.to_s} expected argument to be an Array." unless arg.instance_of? Array
|
159
|
+
arg.map { |location| to_latlng(location) }.join('|')
|
158
160
|
end
|
159
161
|
|
160
162
|
# If arg is array-like, then joins it with sep
|
@@ -179,9 +181,8 @@ module GoogleMaps
|
|
179
181
|
raise TypeError, "#{__method__.to_s} expected a Hash of components." unless arg.is_a? Hash
|
180
182
|
|
181
183
|
arg.map { |c, val|
|
182
|
-
ArrayBox.wrap(val).map {|elem| "#{c}:#{elem}"}
|
183
|
-
|
184
|
-
}.join("|")
|
184
|
+
ArrayBox.wrap(val).map {|elem| "#{c}:#{elem}"}.sort_by(&:downcase)
|
185
|
+
}.join('|')
|
185
186
|
end
|
186
187
|
|
187
188
|
# Converts a lat/lng bounds to a comma- and pipe-separated string.
|
@@ -212,7 +213,7 @@ module GoogleMaps
|
|
212
213
|
def self.encode_polyline(points)
|
213
214
|
raise TypeError, "#{__method__.to_s} expected an Array of points." unless points.is_a? Array
|
214
215
|
last_lat, last_lng = 0, 0
|
215
|
-
result =
|
216
|
+
result = ''
|
216
217
|
points.each { |point|
|
217
218
|
lat = (point[:lat] * 1e5).round.to_i
|
218
219
|
lng = (point[:lng] * 1e5).round.to_i
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: googlemaps-services
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Faissal Elamraoui
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-11-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -111,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
111
111
|
version: '0'
|
112
112
|
requirements: []
|
113
113
|
rubyforge_project:
|
114
|
-
rubygems_version: 2.
|
114
|
+
rubygems_version: 2.5.1
|
115
115
|
signing_key:
|
116
116
|
specification_version: 4
|
117
117
|
summary: Ruby Client library for Google Maps API Web Services
|