google_maps_service 0.1.0

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.
@@ -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