google_maps_service 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,93 @@
1
+ module GoogleMapsService
2
+
3
+ # Performs requests to the Google Maps Directions API.
4
+ module Directions
5
+
6
+ # Get directions between an origin point and a destination point.
7
+ #
8
+ # @param [String, Hash, Array] origin The address or latitude/longitude value from which you wish
9
+ # to calculate directions.
10
+ # @param [String, Hash, Array] destination The address or latitude/longitude value from which
11
+ # you wish to calculate directions.
12
+ # @param [String] mode Specifies the mode of transport to use when calculating
13
+ # directions. One of "driving", "walking", "bicycling" or "transit"
14
+ # @param [Array<String>, Array<Hash>, Array<Array>] waypoints Specifies an array of waypoints. Waypoints alter a
15
+ # route by routing it through the specified location(s).
16
+ # @param [Boolean] alternatives If True, more than one route may be returned in the
17
+ # response.
18
+ # @param [Array, String] avoid Indicates that the calculated route(s) should avoid the
19
+ # indicated features.
20
+ # @param [String] language The language in which to return results.
21
+ # @param [String] units Specifies the unit system to use when displaying results.
22
+ # "metric" or "imperial"
23
+ # @param [String] region The region code, specified as a ccTLD ("top-level domain"
24
+ # two-character value.
25
+ # @param [Integer, DateTime] departure_time Specifies the desired time of departure.
26
+ # @param [Integer, DateTime] arrival_time Specifies the desired time of arrival for transit
27
+ # directions. Note: you can't specify both departure_time and
28
+ # arrival_time.
29
+ # @param [Boolean] optimize_waypoints Optimize the provided route by rearranging the
30
+ # waypoints in a more efficient order.
31
+ # @param [String, Array<String>] transit_mode Specifies one or more preferred modes of transit.
32
+ # This parameter may only be specified for requests where the mode is
33
+ # transit. Valid values are "bus", "subway", "train", "tram", "rail".
34
+ # "rail" is equivalent to ["train", "tram", "subway"].
35
+ # @param [String] transit_routing_preference Specifies preferences for transit
36
+ # requests. Valid values are "less_walking" or "fewer_transfers"
37
+ #
38
+ # @return List of routes
39
+ def directions(origin: nil, destination: nil,
40
+ mode: nil, waypoints: nil, alternatives: false, avoid: nil,
41
+ language: nil, units: nil, region: nil, departure_time: nil,
42
+ arrival_time: nil, optimize_waypoints: false, transit_mode: nil,
43
+ transit_routing_preference: nil)
44
+
45
+ params = {
46
+ origin: _convert_waypoint(origin),
47
+ destination: _convert_waypoint(destination)
48
+ }
49
+
50
+ if mode
51
+ # NOTE(broady): the mode parameter is not validated by the Maps API
52
+ # server. Check here to prevent silent failures.
53
+ unless ["driving", "walking", "bicycling", "transit"].include?(mode)
54
+ raise ArgumentError, "Invalid travel mode."
55
+ end
56
+ params[:mode] = mode
57
+ end
58
+
59
+ if waypoints
60
+ waypoints = GoogleMapsService::Convert.as_list(waypoints)
61
+ waypoints = waypoints.map { |waypoint| _convert_waypoint(waypoint) }
62
+ waypoints = ["optimize:true"] + waypoints if optimize_waypoints
63
+
64
+ params[:waypoints] = GoogleMapsService::Convert.join_list("|", waypoints)
65
+ end
66
+
67
+ params[:alternatives] = "true" if alternatives
68
+ params[:avoid] = GoogleMapsService::Convert.join_list("|", avoid) if avoid
69
+ params[:language] = language if language
70
+ params[:units] = units if units
71
+ params[:region] = region if region
72
+ params[:departure_time] = GoogleMapsService::Convert.time(departure_time) if departure_time
73
+ params[:arrival_time] = GoogleMapsService::Convert.time(arrival_time) if arrival_time
74
+
75
+ if departure_time and arrival_time
76
+ raise ArgumentError, "Should not specify both departure_time and arrival_time."
77
+ end
78
+
79
+ params[:transit_mode] = GoogleMapsService::Convert.join_list("|", transit_mode) if transit_mode
80
+ params[:transit_routing_preference] = transit_routing_preference if transit_routing_preference
81
+
82
+ return get("/maps/api/directions/json", params)[:routes]
83
+ end
84
+
85
+ private
86
+ def _convert_waypoint(waypoint)
87
+ if waypoint.kind_of?(String)
88
+ return waypoint
89
+ end
90
+ return GoogleMapsService::Convert.latlng(waypoint)
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,85 @@
1
+ module GoogleMapsService
2
+
3
+ # Performs requests to the Google Maps Distance Matrix API.
4
+ module DistanceMatrix
5
+
6
+ # Gets travel distance and time for a matrix of origins and destinations.
7
+ #
8
+ # @param [Array<String>, Array<Hash>, Array<Array>] origins One or more addresses and/or latitude/longitude values,
9
+ # from which to calculate distance and time. If you pass an address
10
+ # as a string, the service will geocode the string and convert it to
11
+ # a latitude/longitude coordinate to calculate directions.
12
+ # @param [Array<String>, Array<Hash>, Array<Array>] destinations One or more addresses and/or lat/lng values, to
13
+ # which to calculate distance and time. If you pass an address as a
14
+ # string, the service will geocode the string and convert it to a
15
+ # latitude/longitude coordinate to calculate directions.
16
+ # @param [String] mode Specifies the mode of transport to use when calculating
17
+ # directions. Valid values are "driving", "walking", "transit" or
18
+ # "bicycling".
19
+ # @param [String] language The language in which to return results.
20
+ # @param [String] avoid Indicates that the calculated route(s) should avoid the
21
+ # indicated features. Valid values are "tolls", "highways" or "ferries"
22
+ # @param [String] units Specifies the unit system to use when displaying results.
23
+ # Valid values are "metric" or "imperial"
24
+ # @param [Integer, DateTime] departure_time Specifies the desired time of departure.
25
+ # @param [Integer, DateTime] arrival_time Specifies the desired time of arrival for transit
26
+ # directions. Note: you can't specify both departure_time and
27
+ # arrival_time.
28
+ # @param [String, Array<String>] transit_mode Specifies one or more preferred modes of transit.
29
+ # This parameter may only be specified for requests where the mode is
30
+ # transit. Valid values are "bus", "subway", "train", "tram", "rail".
31
+ # "rail" is equivalent to ["train", "tram", "subway"].
32
+ # @param [String] transit_routing_preference Specifies preferences for transit
33
+ # requests. Valid values are "less_walking" or "fewer_transfers"
34
+ #
35
+ # @return matrix of distances. Results are returned in rows, each row
36
+ # containing one origin paired with each destination.
37
+ def distance_matrix(origins: nil, destinations: nil,
38
+ mode: nil, language: nil, avoid: nil, units: nil,
39
+ departure_time: nil, arrival_time: nil, transit_mode: nil,
40
+ transit_routing_preference: nil)
41
+ params = {
42
+ origins: _convert_path(origins),
43
+ destinations: _convert_path(destinations)
44
+ }
45
+
46
+ if mode
47
+ # NOTE(broady): the mode parameter is not validated by the Maps API
48
+ # server. Check here to prevent silent failures.
49
+ unless ["driving", "walking", "bicycling", "transit"].include?(mode)
50
+ raise ArgumentError, "Invalid travel mode."
51
+ end
52
+ params[:mode] = mode
53
+ end
54
+
55
+ params[:language] = language if language
56
+
57
+ if avoid
58
+ unless ["tolls", "highways", "ferries"].include?(avoid)
59
+ raise ArgumentError, "Invalid route restriction."
60
+ end
61
+ params[:avoid] = avoid
62
+ end
63
+
64
+
65
+ params[:units] = units if units
66
+ params[:departure_time] = convert.time(departure_time) if departure_time
67
+ params[:arrival_time] = convert.time(arrival_time) if arrival_time
68
+
69
+ if departure_time and arrival_time
70
+ raise ArgumentError, "Should not specify both departure_time and arrival_time."
71
+ end
72
+
73
+ params[:transit_mode] = convert.join_list("|", transit_mode) if transit_mode
74
+ params[:transit_routing_preference] = transit_routing_preference if transit_routing_preference
75
+
76
+ return get("/maps/api/distancematrix/json", params)
77
+ end
78
+
79
+ private
80
+ def _convert_path(waypoints)
81
+ waypoints = GoogleMapsService::Convert.as_list(waypoints)
82
+ return GoogleMapsService::Convert.join_list("|", waypoints.map { |k| k.kind_of?(String) ? k : GoogleMapsService::Convert.latlng(k) })
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,57 @@
1
+ module GoogleMapsService
2
+
3
+ # Performs requests to the Google Maps Elevation API.
4
+ module Elevation
5
+
6
+ # Provides elevation data for locations provided on the surface of the
7
+ # earth, including depth locations on the ocean floor (which return negative
8
+ # values)
9
+ #
10
+ # @param [Array] locations A single latitude/longitude hash, or an array of
11
+ # latitude/longitude hash from which you wish to calculate
12
+ # elevation data.
13
+ #
14
+ # @return [Array] Array of elevation data responses
15
+ def elevation(locations: nil)
16
+ params = {}
17
+ if locations.kind_of?(Array) and locations.length == 2 and not locations[0].kind_of?(Array)
18
+ locations = [locations]
19
+ end
20
+
21
+ params[:locations] = _convert_locations(locations)
22
+
23
+ return get("/maps/api/elevation/json", params)[:results]
24
+ end
25
+
26
+ # Provides elevation data sampled along a path on the surface of the earth.
27
+ #
28
+ # @param [String, Array] path A encoded polyline string, or a list of
29
+ # latitude/longitude tuples from which you wish to calculate
30
+ # elevation data.
31
+ #
32
+ # @param [Integer] samples The number of sample points along a path for which to
33
+ # return elevation data.
34
+ #
35
+ # @return [Array] Array of elevation data responses
36
+ def elevation_along_path(path: nil, samples: nil)
37
+ if path.kind_of?(String)
38
+ path = "enc:%s" % path
39
+ else
40
+ path = _convert_locations(path)
41
+ end
42
+
43
+ params = {
44
+ path: path,
45
+ samples: samples
46
+ }
47
+
48
+ return get("/maps/api/elevation/json", params)[:results]
49
+ end
50
+
51
+ private
52
+ def _convert_locations(locations)
53
+ locations = GoogleMapsService::Convert.as_list(locations)
54
+ return GoogleMapsService::Convert.join_list("|", locations.map { |k| k.kind_of?(String) ? k : GoogleMapsService::Convert.latlng(k) })
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,40 @@
1
+ module GoogleMapsService
2
+ module Error
3
+ # Base error, capable of wrapping another
4
+ class BaseError < StandardError
5
+ attr_reader :response
6
+
7
+ def initialize(response)
8
+ @response = response
9
+ end
10
+ end
11
+
12
+ # An exception that is raised if a redirect is required
13
+ class RedirectError < BaseError
14
+ end
15
+
16
+ # A 4xx class HTTP error occurred.
17
+ class ClientError < BaseError
18
+ end
19
+
20
+ # A 5xx class HTTP error occurred.
21
+ class ServerError < BaseError
22
+ end
23
+
24
+ # An API error occured.
25
+ class ApiError < BaseError
26
+ end
27
+
28
+ # Requiered query is missing
29
+ class InvalidRequestError < ApiError
30
+ end
31
+
32
+ # Over quota.
33
+ class RateLimitError < ApiError
34
+ end
35
+
36
+ # An unathorized error occurred. It might be caused by invalid key/secret or invalid access.
37
+ class RequestDeniedError < ApiError
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,58 @@
1
+ require 'google_maps_service/convert'
2
+
3
+ module GoogleMapsService
4
+
5
+ # Performs requests to the Google Maps Geocoding API.
6
+ module Geocoding
7
+
8
+ # Geocoding is the process of converting addresses
9
+ # (like +"1600 Amphitheatre Parkway, Mountain View, CA"+) into geographic
10
+ # coordinates (like latitude 37.423021 and longitude -122.083739), which you
11
+ # can use to place markers or position the map.
12
+ #
13
+ # @param [String] address The address to geocode.
14
+ # @param [Hash] components A component filter for which you wish to obtain a geocode,
15
+ # for example: `{ 'administrative_area': 'TX','country': 'US' }`
16
+ # @param [String, Hash] bounds The bounding box of the viewport within which to bias geocode
17
+ # results more prominently. Accept string or hash with northeast and southwest keys.
18
+ # @param [String] region The region code, specified as a ccTLD ("top-level domain")
19
+ # two-character value.
20
+ # @param [String] language The language in which to return results.
21
+ #
22
+ # @return Array of geocoding results.
23
+ def geocode(address: nil, components: nil, bounds: nil, region: nil, language: nil)
24
+ params = {}
25
+
26
+ params[:address] = address if address
27
+ params[:components] = GoogleMapsService::Convert.components(components) if components
28
+ params[:bounds] = GoogleMapsService::Convert.bounds(bounds) if bounds
29
+ params[:region] = region if region
30
+ params[:language] = language if language
31
+
32
+ return get('/maps/api/geocode/json', params)[:results]
33
+ end
34
+
35
+ # Reverse geocoding is the process of converting geographic coordinates into a
36
+ # human-readable address.
37
+ #
38
+ # @param [Hash, Array] latlng The latitude/longitude value for which you wish to obtain the
39
+ # closest, human-readable address#
40
+ # @param [String, Array<String>] result_type One or more address types to restrict results to.
41
+ # @param [Array<String>] location_type One or more location types to restrict results to.
42
+ # @param [String] language The language in which to return results.
43
+ #
44
+ # @return Array of reverse geocoding results.
45
+ def reverse_geocode(latlng: nil, result_type: nil, location_type: nil, language: nil)
46
+ params = {
47
+ latlng: GoogleMapsService::Convert.latlng(latlng)
48
+ }
49
+
50
+ params[:result_type] = GoogleMapsService::Convert.join_list("|", result_type) if result_type
51
+ params[:location_type] = GoogleMapsService::Convert.join_list("|", location_type) if location_type
52
+ params[:language] = language if language
53
+
54
+ return get('/maps/api/geocode/json', params)[:results]
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,141 @@
1
+ require 'multi_json'
2
+
3
+ module GoogleMapsService
4
+
5
+ # Performs requests to the Google Maps Roads API."""
6
+ module Roads
7
+
8
+ # Base URL of Google Maps Roads API
9
+ ROADS_BASE_URL = "https://roads.googleapis.com"
10
+
11
+ # Snaps a path to the most likely roads travelled.
12
+ #
13
+ # Takes up to 100 GPS points collected along a route, and returns a similar
14
+ # set of data with the points snapped to the most likely roads the vehicle
15
+ # was traveling along.
16
+ #
17
+ # @param [] path The path to be snapped. A list of latitude/longitude tuples.
18
+ # :type path: list
19
+ #
20
+ # @param [] interpolate Whether to interpolate a path to include all points
21
+ # forming the full road-geometry. When true, additional interpolated
22
+ # points will also be returned, resulting in a path that smoothly
23
+ # follows the geometry of the road, even around corners and through
24
+ # tunnels. Interpolated paths may contain more points than the
25
+ # original path.
26
+ # :type interpolate: bool
27
+ #
28
+ # :rtype: A list of snapped points.
29
+ def snap_to_roads(path: nil, interpolate: false)
30
+ if path.kind_of?(Array) and path.length == 2 and not path[0].kind_of?(Array)
31
+ path = [path]
32
+ end
33
+
34
+ path = _convert_path(path)
35
+
36
+ params = {
37
+ path: path
38
+ }
39
+
40
+ params[:interpolate] = "true" if interpolate
41
+
42
+ return get("/v1/snapToRoads", params,
43
+ base_url: ROADS_BASE_URL,
44
+ accepts_client_id: false,
45
+ custom_response_decoder: method(:extract_roads_body))[:snappedPoints]
46
+ end
47
+
48
+ # Returns the posted speed limit (in km/h) for given road segments.
49
+ #
50
+ # @param [String, Array<String>] place_ids The Place ID of the road segment. Place IDs are returned
51
+ # by the snap_to_roads function. You can pass up to 100 Place IDs.
52
+ # @return Array of speed limits.
53
+ def speed_limits(place_ids: nil)
54
+ params = GoogleMapsService::Convert.as_list(place_ids).map { |place_id| ["placeId", place_id] }
55
+
56
+ return get("/v1/speedLimits", params,
57
+ base_url: ROADS_BASE_URL,
58
+ accepts_client_id: false,
59
+ custom_response_decoder: method(:extract_roads_body))[:speedLimits]
60
+ end
61
+
62
+
63
+ # Returns the posted speed limit (in km/h) for given road segments.
64
+ #
65
+ # The provided points will first be snapped to the most likely roads the
66
+ # vehicle was traveling along.
67
+ #
68
+ # @param [Hash, Array] path The path of points to be snapped. A list of (or single)
69
+ # latitude/longitude tuples.
70
+ #
71
+ # @return [Hash] a dict with both a list of speed limits and a list of the snapped
72
+ # points.
73
+ def snapped_speed_limits(path: nil)
74
+
75
+ if path.kind_of?(Array) and path.length == 2 and not path[0].kind_of?(Array)
76
+ path = [path]
77
+ end
78
+
79
+ path = _convert_path(path)
80
+
81
+ params = {
82
+ path: path
83
+ }
84
+
85
+ return get("/v1/speedLimits", params,
86
+ base_url: ROADS_BASE_URL,
87
+ accepts_client_id: false,
88
+ custom_response_decoder: method(:extract_roads_body))
89
+ end
90
+
91
+ private
92
+ def _convert_path(paths)
93
+ paths = GoogleMapsService::Convert.as_list(paths)
94
+ return GoogleMapsService::Convert.join_list("|", paths.map { |k| k.kind_of?(String) ? k : GoogleMapsService::Convert.latlng(k) })
95
+ end
96
+
97
+ # Extracts a result from a Roads API HTTP response.
98
+ def extract_roads_body(response)
99
+ begin
100
+ body = MultiJson.load(response.body, :symbolize_keys => true)
101
+ rescue
102
+ unless response.status_code == 200
103
+ check_response_status_code(response)
104
+ end
105
+ raise GoogleMapsService::Error::ApiError.new(response), "Received a malformed response."
106
+ end
107
+
108
+ if body.has_key?(:error)
109
+ error = body[:error]
110
+ status = error[:status]
111
+
112
+ if status == 'INVALID_ARGUMENT'
113
+ if error[:message] == 'The provided API key is invalid.'
114
+ raise GoogleMapsService::Error::RequestDeniedError.new(response), error[:message]
115
+ end
116
+ raise GoogleMapsService::Error::InvalidRequestError.new(response), error[:message]
117
+ end
118
+
119
+ if status == 'PERMISSION_DENIED'
120
+ raise GoogleMapsService::Error::RequestDeniedError.new(response), error[:message]
121
+ end
122
+
123
+ if status == 'RESOURCE_EXHAUSTED'
124
+ raise GoogleMapsService::Error::RateLimitError.new(response), error[:message]
125
+ end
126
+
127
+ if error.has_key?(:message)
128
+ raise GoogleMapsService::Error::ApiError.new(response), error[:message]
129
+ else
130
+ raise GoogleMapsService::Error::ApiError.new(response)
131
+ end
132
+ end
133
+
134
+ unless response.status_code == 200
135
+ raise GoogleMapsService::Error::HTTPError.new(response)
136
+ end
137
+
138
+ return body
139
+ end
140
+ end
141
+ end