google_distance_matrix 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +0 -1
- data/CHANGELOG.md +10 -1
- data/README.md +31 -12
- data/lib/google_distance_matrix.rb +3 -1
- data/lib/google_distance_matrix/configuration.rb +28 -8
- data/lib/google_distance_matrix/errors.rb +7 -0
- data/lib/google_distance_matrix/log_subscriber.rb +19 -3
- data/lib/google_distance_matrix/matrix.rb +5 -3
- data/lib/google_distance_matrix/place.rb +4 -0
- data/lib/google_distance_matrix/polyline_encoder.rb +47 -0
- data/lib/google_distance_matrix/polyline_encoder/delta.rb +52 -0
- data/lib/google_distance_matrix/polyline_encoder/value_encoder.rb +61 -0
- data/lib/google_distance_matrix/route.rb +11 -3
- data/lib/google_distance_matrix/routes_finder.rb +35 -1
- data/lib/google_distance_matrix/url_builder.rb +24 -4
- data/lib/google_distance_matrix/url_builder/polyline_encoder_buffer.rb +26 -0
- data/lib/google_distance_matrix/version.rb +1 -1
- data/spec/lib/google_distance_matrix/configuration_spec.rb +13 -0
- data/spec/lib/google_distance_matrix/log_subscriber_spec.rb +88 -0
- data/spec/lib/google_distance_matrix/matrix_spec.rb +17 -2
- data/spec/lib/google_distance_matrix/polyline_encoder/delta_spec.rb +15 -0
- data/spec/lib/google_distance_matrix/polyline_encoder_spec.rb +17 -0
- data/spec/lib/google_distance_matrix/route_spec.rb +3 -0
- data/spec/lib/google_distance_matrix/routes_finder_spec.rb +43 -1
- data/spec/lib/google_distance_matrix/url_builder_spec.rb +26 -0
- data/spec/request_recordings/success_with_in_traffic +78 -0
- metadata +14 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3ca9d7d93abd6340a3cb5d36d03cbadfda5e4e1c
|
4
|
+
data.tar.gz: 2cb7956404bd763af695eae8c10b81de5db48450
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c5364924b1a055ce8c67c1508b219a1fc187ee9ecfa95d683775c21888f1076518bd1617b6a2e5be0020f5ef862e6707341bf8c71fff60e12e011d4dad719b9
|
7
|
+
data.tar.gz: 59c211df2561ea00a1da7858051fb87de4a02e35642faba695852baf974e9e3d30d34c9b710e3078e05a2cf1ea1caefb6411f35a0604a90a6f01c37f9c9af715
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,13 @@
|
|
1
|
-
## v.0.
|
1
|
+
## v.0.4.0
|
2
|
+
* When mode is `driving` and `departure_time` is set all `route` objects will contain
|
3
|
+
`duration_in_traffic_in_seconds` and `duration_in_traffic_text`.
|
4
|
+
You can also query the matrix by `shortest_route_by_duration_in_traffic_to(place)`.
|
5
|
+
* Added option to encode origins and destinations as polylines to save characters in the URL.
|
6
|
+
* Filter sensitive GET params when logging the URL we query Google Matrix with.
|
7
|
+
* departure_time can now be set to 'now'.
|
8
|
+
* Dropped support for Ruby 2.0.0
|
9
|
+
|
10
|
+
## v.0.3.0
|
2
11
|
This release includes one breaking change, the removal of sensor parameter.
|
3
12
|
This parameter is no longer used - see:
|
4
13
|
https://developers.google.com/maps/documentation/distance-matrix/intro#Sensor
|
data/README.md
CHANGED
@@ -56,14 +56,14 @@ matrix.configure do |config|
|
|
56
56
|
config.google_business_api_client_id = "123"
|
57
57
|
config.google_business_api_private_key = "your-secret-key"
|
58
58
|
|
59
|
-
# If you have an API key, you can specify that as well.
|
59
|
+
# If you have an API key, you can specify that as well.
|
60
60
|
config.google_api_key = "YOUR_API_KEY"
|
61
61
|
end
|
62
62
|
```
|
63
63
|
### Get the data for the matrix
|
64
64
|
|
65
65
|
`matrix.data` returns the data, loaded from Google, for this matrix.
|
66
|
-
|
66
|
+
|
67
67
|
It is a multi dimensional array. Rows are ordered according to the values in the origins.
|
68
68
|
Each row corresponds to an origin, and each element within that row corresponds to a pairing of the origin with a destination.
|
69
69
|
|
@@ -80,19 +80,25 @@ Returns Google::DistanceMatrix::Route with given origin and destination
|
|
80
80
|
|
81
81
|
```ruby
|
82
82
|
matrix.route_for origin: lat_lng, destination: dest_address
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
matrix.shortest_route_by_duration_to(dest_address)
|
83
|
+
|
84
|
+
# Returns the shortest route to given destination, either by distance or duration
|
85
|
+
matrix.shortest_route_by_distance_to(dest_address)
|
86
|
+
matrix.shortest_route_by_duration_to(dest_address)
|
87
|
+
|
88
|
+
# If your matrix is for driving and you provided a departure_time all Route objects within
|
89
|
+
# the matrix will have duration_in_traffic_in_seconds. We can query the matrix for this data as well:
|
90
|
+
matrix.shortest_route_by_duration_in_traffic_to(dest_address)
|
87
91
|
```
|
88
92
|
|
89
|
-
In cases where you built the place with an object (not hash with attributes) you may provide that object
|
93
|
+
In cases where you built the place with an object (not hash with attributes) you may provide that object
|
94
|
+
as well asking for routes. This is true for `route_for` and `shortest_route_by_*` as well.
|
90
95
|
|
91
96
|
```ruby
|
92
97
|
matrix.routes_for point_dest # Returns routes for dest_object
|
93
98
|
```
|
94
99
|
|
95
|
-
You may call query methods with a bang, in which case it will fail with an error if not all of the
|
100
|
+
You may call query methods with a bang, in which case it will fail with an error if not all of the
|
101
|
+
routes in your result set for the called method are ok.
|
96
102
|
|
97
103
|
|
98
104
|
## Installation
|
@@ -117,6 +123,19 @@ Configuration is done directly on a matrix or via `GoogleDistanceMatrix.configur
|
|
117
123
|
Apart from configuration on requests it is also possible to provide your own logger class and
|
118
124
|
set a cache.
|
119
125
|
|
126
|
+
### Shorting the URL using encoded coordinates
|
127
|
+
Instead of lat and lng values in the URL it is possible to use encoded set of coordinates
|
128
|
+
using the Encoded Polyline Algorithm. This is particularly useful if you have a large
|
129
|
+
number of origin points, because the URL is significantly shorter when
|
130
|
+
using an encoded polyline.
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
GoogleDistanceMatrix.configure_defaults do |config|
|
134
|
+
config.use_encoded_polylines = true
|
135
|
+
end
|
136
|
+
```
|
137
|
+
|
138
|
+
|
120
139
|
### Request cache
|
121
140
|
|
122
141
|
Given Google's limit to the service you may have the need to cache requests. This is done by simply
|
@@ -124,10 +143,10 @@ using URL as cache keys. Cache we'll accept should provide a default ActiveSuppo
|
|
124
143
|
|
125
144
|
```ruby
|
126
145
|
GoogleDistanceMatrix.configure_defaults do |config|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
146
|
+
config.cache = ActiveSupport::Cache.lookup_store :your_store, {
|
147
|
+
expires_in: 12.hours
|
148
|
+
# ..or other options you like for your store
|
149
|
+
}
|
131
150
|
end
|
132
151
|
```
|
133
152
|
|
@@ -17,8 +17,8 @@ require "google_distance_matrix/matrix"
|
|
17
17
|
require "google_distance_matrix/places"
|
18
18
|
require "google_distance_matrix/place"
|
19
19
|
require "google_distance_matrix/route"
|
20
|
+
require "google_distance_matrix/polyline_encoder"
|
20
21
|
|
21
|
-
require "google_distance_matrix/log_subscriber"
|
22
22
|
require 'google_distance_matrix/railtie' if defined? Rails
|
23
23
|
|
24
24
|
|
@@ -37,3 +37,5 @@ module GoogleDistanceMatrix
|
|
37
37
|
@logger ||= Logger.new default_configuration.logger
|
38
38
|
end
|
39
39
|
end
|
40
|
+
|
41
|
+
require "google_distance_matrix/log_subscriber"
|
@@ -9,6 +9,7 @@ module GoogleDistanceMatrix
|
|
9
9
|
class Configuration
|
10
10
|
include ActiveModel::Validations
|
11
11
|
|
12
|
+
# Attributes we'll include building URL for our matrix
|
12
13
|
ATTRIBUTES = %w[
|
13
14
|
mode avoid units language
|
14
15
|
departure_time arrival_time
|
@@ -19,19 +20,41 @@ module GoogleDistanceMatrix
|
|
19
20
|
API_DEFAULTS = {
|
20
21
|
mode: "driving",
|
21
22
|
units: "metric",
|
22
|
-
traffic_model: "best_guess"
|
23
|
+
traffic_model: "best_guess",
|
24
|
+
use_encoded_polylines: false,
|
25
|
+
protocol: 'https',
|
26
|
+
lat_lng_scale: 5,
|
27
|
+
filter_parameters_in_logged_url: ['key', 'signature'].freeze
|
23
28
|
}.with_indifferent_access
|
24
29
|
|
25
|
-
attr_accessor *ATTRIBUTES
|
30
|
+
attr_accessor *ATTRIBUTES
|
31
|
+
|
32
|
+
# The protocol to use, either http or https
|
33
|
+
attr_accessor :protocol
|
34
|
+
|
35
|
+
# lat_lng_scale is used for each Place when we include it's lat and lng values in the URL.
|
36
|
+
# Defaults to 5 decimals, but you can set it lower to save characters in the URL.
|
37
|
+
#
|
38
|
+
# Speaking of saving characters. If you use_encoded_polylines all Places which has lat/lng
|
39
|
+
# will use encoded set of coordinates using the Encoded Polyline Algorithm.
|
40
|
+
# This is particularly useful if you have a large number of origin points,
|
41
|
+
# because the URL is significantly shorter when using an encoded polyline.
|
42
|
+
# See: https://developers.google.com/maps/documentation/distance-matrix/intro#RequestParameters
|
43
|
+
attr_accessor :lat_lng_scale, :use_encoded_polylines
|
44
|
+
|
45
|
+
# Google credentials
|
26
46
|
attr_accessor :google_business_api_client_id, :google_business_api_private_key, :google_api_key
|
27
|
-
attr_accessor :cache
|
28
47
|
|
48
|
+
attr_accessor :cache, :logger
|
49
|
+
|
50
|
+
# When logging we filter sensitive parameters
|
51
|
+
attr_accessor :filter_parameters_in_logged_url
|
29
52
|
|
30
53
|
validates :mode, inclusion: {in: ["driving", "walking", "bicycling", "transit"]}, allow_blank: true
|
31
54
|
validates :avoid, inclusion: {in: ["tolls", "highways", "ferries", "indoor"]}, allow_blank: true
|
32
55
|
validates :units, inclusion: {in: ["metric", "imperial"]}, allow_blank: true
|
33
56
|
|
34
|
-
validates :departure_time,
|
57
|
+
validates :departure_time, format: /\A(\d+|now)\Z/, allow_blank: true
|
35
58
|
validates :arrival_time, numericality: true, allow_blank: true
|
36
59
|
|
37
60
|
validates :transit_mode, inclusion: {in: %w[bus subway train tram rail]}, allow_blank: true
|
@@ -41,11 +64,8 @@ module GoogleDistanceMatrix
|
|
41
64
|
validates :protocol, inclusion: {in: ["http", "https"]}, allow_blank: true
|
42
65
|
|
43
66
|
def initialize
|
44
|
-
self.protocol = "https"
|
45
|
-
self.lat_lng_scale = 5
|
46
|
-
|
47
67
|
API_DEFAULTS.each_pair do |attr_name, value|
|
48
|
-
self[attr_name] = value
|
68
|
+
self[attr_name] = value.dup rescue value
|
49
69
|
end
|
50
70
|
end
|
51
71
|
|
@@ -14,6 +14,13 @@ module GoogleDistanceMatrix
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
+
# Public: Raised when we query the matrix for something it cannot answer.
|
18
|
+
#
|
19
|
+
# Example: Asking it for shortest_route_by_duration_in_traffic when the
|
20
|
+
# matrix data has no such data.
|
21
|
+
class InvalidQuery < Error
|
22
|
+
end
|
23
|
+
|
17
24
|
# Public: Route seems invalid
|
18
25
|
#
|
19
26
|
# Fails if a route is built, but it's status from
|
@@ -1,11 +1,27 @@
|
|
1
1
|
module GoogleDistanceMatrix
|
2
2
|
class LogSubscriber < ActiveSupport::LogSubscriber
|
3
|
+
attr_reader :logger, :config
|
4
|
+
|
5
|
+
def initialize(logger: GoogleDistanceMatrix.logger, config: GoogleDistanceMatrix.default_configuration)
|
6
|
+
super()
|
7
|
+
|
8
|
+
@logger = logger
|
9
|
+
@config = config
|
10
|
+
end
|
11
|
+
|
3
12
|
def client_request_matrix_data(event)
|
4
|
-
|
13
|
+
url = filter_url! event.payload[:url]
|
14
|
+
logger.info "(#{event.duration}ms) (elements: #{event.payload[:elements]}) GET #{url}", tag: :client
|
5
15
|
end
|
6
16
|
|
7
|
-
|
8
|
-
|
17
|
+
private
|
18
|
+
|
19
|
+
def filter_url!(url)
|
20
|
+
config.filter_parameters_in_logged_url.each do |param|
|
21
|
+
url.gsub! %r{(#{param})=.*?(&|$)}, '\1=[FILTERED]\2'
|
22
|
+
end
|
23
|
+
|
24
|
+
url
|
9
25
|
end
|
10
26
|
end
|
11
27
|
end
|
@@ -54,10 +54,12 @@ module GoogleDistanceMatrix
|
|
54
54
|
end
|
55
55
|
|
56
56
|
|
57
|
-
delegate :route_for,
|
57
|
+
delegate :route_for, :routes_for, to: :routes_finder
|
58
58
|
delegate :route_for!, :routes_for!, to: :routes_finder
|
59
|
-
delegate :shortest_route_by_distance_to,
|
60
|
-
delegate :shortest_route_by_distance_to!, :shortest_route_by_duration_to!,
|
59
|
+
delegate :shortest_route_by_distance_to, :shortest_route_by_duration_to, to: :routes_finder
|
60
|
+
delegate :shortest_route_by_distance_to!, :shortest_route_by_duration_to!, to: :routes_finder
|
61
|
+
delegate :shortest_route_by_duration_in_traffic_to, to: :routes_finder
|
62
|
+
delegate :shortest_route_by_duration_in_traffic_to!, to: :routes_finder
|
61
63
|
|
62
64
|
|
63
65
|
# Public: The data for this matrix.
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require_relative 'polyline_encoder/delta'
|
2
|
+
require_relative 'polyline_encoder/value_encoder'
|
3
|
+
|
4
|
+
module GoogleDistanceMatrix
|
5
|
+
# Encodes a set of lat/lng pairs in to a polyline
|
6
|
+
# according to Google's Encoded Polyline Algorithm Format.
|
7
|
+
#
|
8
|
+
# See https://developers.google.com/maps/documentation/utilities/polylinealgorithm
|
9
|
+
class PolylineEncoder
|
10
|
+
|
11
|
+
# Encodes a set of lat/lng pairs
|
12
|
+
#
|
13
|
+
# Example
|
14
|
+
# encoded = PolylineEncoder.encode [[lat, lng], [lat, lng]]
|
15
|
+
def self.encode(array_of_lat_lng_pairs)
|
16
|
+
new(array_of_lat_lng_pairs).encode
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
# Initialize a new encoder
|
21
|
+
#
|
22
|
+
# Arguments
|
23
|
+
# array_of_lat_lng_pairs - The array of lat/lng pairs, like [[lat, lng], [lat, lng], ..etc]
|
24
|
+
# delta - An object responsible for rounding and calculate the deltas
|
25
|
+
# between the given lat/lng pairs.
|
26
|
+
# value_encoder - After deltas are calculated each value is passed to the encoder
|
27
|
+
# to be encoded in to ASCII characters
|
28
|
+
#
|
29
|
+
# @see ::encode
|
30
|
+
def initialize(array_of_lat_lng_pairs, delta: Delta.new, value_encoder: ValueEncoder.new)
|
31
|
+
@array_of_lat_lng_pairs = array_of_lat_lng_pairs
|
32
|
+
@delta = delta
|
33
|
+
@value_encoder = value_encoder
|
34
|
+
@encoded = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
# Encode and returns the encoded string
|
38
|
+
def encode
|
39
|
+
return @encoded if @encoded
|
40
|
+
|
41
|
+
deltas = @delta.deltas_rounded @array_of_lat_lng_pairs
|
42
|
+
chars_array = deltas.map { |v| @value_encoder.encode v }
|
43
|
+
|
44
|
+
@encoded = chars_array.join
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module GoogleDistanceMatrix
|
2
|
+
class PolylineEncoder
|
3
|
+
# Calculates deltas between lat_lng values, internal helper class for PolylineEncoder.
|
4
|
+
#
|
5
|
+
# According to the Google's polyline encoding spec:
|
6
|
+
# "Additionally, to conserve space, points only include the offset
|
7
|
+
# from the previous point (except of course for the first point)"
|
8
|
+
#
|
9
|
+
# @see GoogleDistanceMatrix::PolylineEncoder
|
10
|
+
class Delta
|
11
|
+
def initialize(precision = 1e5)
|
12
|
+
@precision = precision
|
13
|
+
end
|
14
|
+
|
15
|
+
# Takes a set of lat/lng pairs and calculates delta
|
16
|
+
#
|
17
|
+
# Returns a flatten array where each lat/lng delta pair is put in order.
|
18
|
+
def deltas_rounded(array_of_lat_lng_pairs)
|
19
|
+
rounded = round_to_precision array_of_lat_lng_pairs
|
20
|
+
calculate_deltas rounded
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def round_to_precision(array_of_lat_lng_pairs)
|
27
|
+
array_of_lat_lng_pairs.map do |(lat, lng)|
|
28
|
+
[
|
29
|
+
(lat * @precision).round,
|
30
|
+
(lng * @precision).round
|
31
|
+
]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def calculate_deltas(rounded)
|
36
|
+
deltas = []
|
37
|
+
|
38
|
+
delta_lat = 0
|
39
|
+
delta_lng = 0
|
40
|
+
|
41
|
+
rounded.each do |(lat, lng)|
|
42
|
+
deltas << lat - delta_lat
|
43
|
+
deltas << lng - delta_lng
|
44
|
+
|
45
|
+
delta_lat, delta_lng = lat, lng
|
46
|
+
end
|
47
|
+
|
48
|
+
deltas
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module GoogleDistanceMatrix
|
2
|
+
class PolylineEncoder
|
3
|
+
# Encodes a single value, like 17998321, in to encoded polyline value,
|
4
|
+
# as described in Google's documentation
|
5
|
+
# https://developers.google.com/maps/documentation/utilities/polylinealgorithm
|
6
|
+
#
|
7
|
+
# This is an internal helper class for PolylineEncoder.
|
8
|
+
# This encoder expects that the value is rounded.
|
9
|
+
#
|
10
|
+
# @see GoogleDistanceMatrix::PolylineEncoder
|
11
|
+
class ValueEncoder
|
12
|
+
def encode(value)
|
13
|
+
negative = value < 0
|
14
|
+
value = value.abs
|
15
|
+
|
16
|
+
# Step 3: Two's complement when negative
|
17
|
+
value = ~value + 1 if negative
|
18
|
+
|
19
|
+
# Step 4: Left shift one bit
|
20
|
+
value = value << 1
|
21
|
+
|
22
|
+
# Step 5: Invert if value was negative
|
23
|
+
value = ~value if negative
|
24
|
+
|
25
|
+
# Step 6 and 7: 5-bit chunks in reverse order
|
26
|
+
# We AND 5 first bits and push them on to chunks array.
|
27
|
+
# Right shift bits to get rid of the ones we just put on the array.
|
28
|
+
# Bits will end up in reverse order.
|
29
|
+
chunks_of_5_bits = []
|
30
|
+
while value > 0 do
|
31
|
+
chunks_of_5_bits.push(value & 0x1f)
|
32
|
+
value >>= 5
|
33
|
+
end
|
34
|
+
|
35
|
+
chunks_of_5_bits << 0 if chunks_of_5_bits.empty?
|
36
|
+
|
37
|
+
# Step 8, 9 and 10: OR each value with 0x20, unless last one. Add 63 to all values
|
38
|
+
last_index = chunks_of_5_bits.length - 1
|
39
|
+
chunks_of_5_bits.each_with_index do |chunk, index|
|
40
|
+
chunks_of_5_bits[index] = chunk | 0x20 unless index == last_index
|
41
|
+
chunks_of_5_bits[index] += 63
|
42
|
+
end
|
43
|
+
|
44
|
+
# step 11: Convert to ASCII
|
45
|
+
chunks_of_5_bits.map(&:chr)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
# Debug method for pretty printing integers as bits.
|
51
|
+
#
|
52
|
+
# Example of usage
|
53
|
+
# p d 17998321 # => "00000001 00010010 10100001 11110001"
|
54
|
+
def d(v, bits = 32, chunk_size = 8)
|
55
|
+
(bits - 1).downto(0).
|
56
|
+
map { |n| v[n] }.
|
57
|
+
each_slice(chunk_size).map { |chunk| chunk.join }.join ' '
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -5,12 +5,15 @@ module GoogleDistanceMatrix
|
|
5
5
|
# it's origin and destination.
|
6
6
|
#
|
7
7
|
class Route
|
8
|
-
STATUSES = %w[ok zero_results not_found]
|
8
|
+
STATUSES = %w[ok zero_results not_found].freeze
|
9
9
|
|
10
10
|
ATTRIBUTES = %w[
|
11
11
|
origin destination
|
12
|
-
status
|
13
|
-
|
12
|
+
status
|
13
|
+
distance_text distance_in_meters
|
14
|
+
duration_text duration_in_seconds
|
15
|
+
duration_in_traffic_text duration_in_traffic_in_seconds
|
16
|
+
].freeze
|
14
17
|
|
15
18
|
attr_reader *ATTRIBUTES
|
16
19
|
|
@@ -30,6 +33,11 @@ module GoogleDistanceMatrix
|
|
30
33
|
@distance_in_meters = attributes[:distance][:value]
|
31
34
|
@duration_text = attributes[:duration][:text]
|
32
35
|
@duration_in_seconds = attributes[:duration][:value]
|
36
|
+
|
37
|
+
if attributes.key? :duration_in_traffic
|
38
|
+
@duration_in_traffic_text = attributes[:duration_in_traffic][:text]
|
39
|
+
@duration_in_traffic_in_seconds = attributes[:duration_in_traffic][:value]
|
40
|
+
end
|
33
41
|
end
|
34
42
|
end
|
35
43
|
|
@@ -3,7 +3,7 @@ module GoogleDistanceMatrix
|
|
3
3
|
class RoutesFinder
|
4
4
|
|
5
5
|
attr_reader :matrix
|
6
|
-
delegate :data, :origins, :destinations, to: :matrix
|
6
|
+
delegate :data, :origins, :destinations, :configuration, to: :matrix
|
7
7
|
|
8
8
|
|
9
9
|
def initialize(matrix)
|
@@ -110,6 +110,34 @@ module GoogleDistanceMatrix
|
|
110
110
|
routes_for!(place_or_object_place_was_built_from).min_by &:duration_in_seconds
|
111
111
|
end
|
112
112
|
|
113
|
+
# Public: Finds shortes route by duration in traffic to a place.
|
114
|
+
#
|
115
|
+
# NOTE The matrix must be loaded with mode driving and a departure_time set to
|
116
|
+
# get the matrix loaded with duration in traffic.
|
117
|
+
#
|
118
|
+
# place - The place, or object place was built from, you want the shortest route to
|
119
|
+
#
|
120
|
+
# Returns shortest route, or nil if no routes had status ok
|
121
|
+
def shortest_route_by_duration_in_traffic_to(place_or_object_place_was_built_from)
|
122
|
+
ensure_driving_and_departure_time_or_fail!
|
123
|
+
|
124
|
+
routes = routes_for place_or_object_place_was_built_from
|
125
|
+
select_ok_routes(routes).min_by &:duration_in_traffic_in_seconds
|
126
|
+
end
|
127
|
+
|
128
|
+
# Public: Finds shortes route by duration in traffic to a place.
|
129
|
+
#
|
130
|
+
# NOTE The matrix must be loaded with mode driving and a departure_time set to
|
131
|
+
# get the matrix loaded with duration in traffic.
|
132
|
+
#
|
133
|
+
# place - The place, or object place was built from, you want the shortest route to
|
134
|
+
#
|
135
|
+
# Returns shortest route, fails if any of the routes are not ok
|
136
|
+
def shortest_route_by_duration_in_traffic_to!(place_or_object_place_was_built_from)
|
137
|
+
ensure_driving_and_departure_time_or_fail!
|
138
|
+
|
139
|
+
routes_for!(place_or_object_place_was_built_from).min_by &:duration_in_traffic_in_seconds
|
140
|
+
end
|
113
141
|
|
114
142
|
|
115
143
|
|
@@ -165,5 +193,11 @@ module GoogleDistanceMatrix
|
|
165
193
|
def select_ok_routes(routes)
|
166
194
|
routes.select &:ok?
|
167
195
|
end
|
196
|
+
|
197
|
+
def ensure_driving_and_departure_time_or_fail!
|
198
|
+
if configuration.mode != 'driving' || configuration.departure_time.nil?
|
199
|
+
fail InvalidQuery, "Matrix must be in mode driving and a departure_time must be set"
|
200
|
+
end
|
201
|
+
end
|
168
202
|
end
|
169
203
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require_relative 'url_builder/polyline_encoder_buffer'
|
2
|
+
|
1
3
|
module GoogleDistanceMatrix
|
2
4
|
class UrlBuilder
|
3
5
|
BASE_URL = "maps.googleapis.com/maps/api/distancematrix/json"
|
@@ -48,14 +50,32 @@ module GoogleDistanceMatrix
|
|
48
50
|
end
|
49
51
|
|
50
52
|
def params
|
51
|
-
places_to_param_config = {lat_lng_scale: configuration.lat_lng_scale}
|
52
|
-
|
53
53
|
configuration.to_param.merge(
|
54
|
-
origins: matrix.origins
|
55
|
-
destinations: matrix.destinations
|
54
|
+
origins: places_to_param(matrix.origins),
|
55
|
+
destinations: places_to_param(matrix.destinations)
|
56
56
|
)
|
57
57
|
end
|
58
58
|
|
59
|
+
def places_to_param(places)
|
60
|
+
places_to_param_config = {lat_lng_scale: configuration.lat_lng_scale}
|
61
|
+
|
62
|
+
out = []
|
63
|
+
polyline_encode_buffer = PolylineEncoderBuffer.new
|
64
|
+
|
65
|
+
places.each do |place|
|
66
|
+
if place.lat_lng? && configuration.use_encoded_polylines
|
67
|
+
polyline_encode_buffer << place.lat_lng
|
68
|
+
else
|
69
|
+
polyline_encode_buffer.flush to: out
|
70
|
+
out << escape(place.to_param places_to_param_config)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
polyline_encode_buffer.flush to: out
|
75
|
+
|
76
|
+
out.join(DELIMITER)
|
77
|
+
end
|
78
|
+
|
59
79
|
def protocol
|
60
80
|
configuration.protocol + "://"
|
61
81
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module GoogleDistanceMatrix
|
2
|
+
class UrlBuilder
|
3
|
+
class PolylineEncoderBuffer
|
4
|
+
def initialize
|
5
|
+
@buffer = []
|
6
|
+
end
|
7
|
+
|
8
|
+
def <<(lat_lng)
|
9
|
+
@buffer << lat_lng
|
10
|
+
end
|
11
|
+
|
12
|
+
def flush(to:)
|
13
|
+
return if @buffer.empty?
|
14
|
+
|
15
|
+
to << escape("enc:#{PolylineEncoder.encode @buffer}:")
|
16
|
+
@buffer.clear
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def escape(string)
|
22
|
+
CGI.escape string
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -13,6 +13,18 @@ describe GoogleDistanceMatrix::Configuration do
|
|
13
13
|
expect(subject.errors[:departure_time].length).to eq 0
|
14
14
|
end
|
15
15
|
|
16
|
+
it 'is valid with "now"' do
|
17
|
+
subject.departure_time = 'now'
|
18
|
+
subject.valid?
|
19
|
+
expect(subject.errors[:departure_time].length).to eq 0
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'is invalid with "123now"' do
|
23
|
+
subject.departure_time = '123now'
|
24
|
+
subject.valid?
|
25
|
+
expect(subject.errors[:departure_time].length).to eq 1
|
26
|
+
end
|
27
|
+
|
16
28
|
it 'is invalid with something else' do
|
17
29
|
subject.departure_time = 'foo'
|
18
30
|
subject.valid?
|
@@ -57,6 +69,7 @@ describe GoogleDistanceMatrix::Configuration do
|
|
57
69
|
it { expect(subject.avoid).to be_nil }
|
58
70
|
it { expect(subject.units).to eq "metric" }
|
59
71
|
it { expect(subject.lat_lng_scale).to eq 5 }
|
72
|
+
it { expect(subject.use_encoded_polylines).to eq false }
|
60
73
|
it { expect(subject.protocol).to eq 'https' }
|
61
74
|
it { expect(subject.language).to be_nil }
|
62
75
|
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module GoogleDistanceMatrix
|
4
|
+
describe LogSubscriber do
|
5
|
+
class MockLogger
|
6
|
+
attr_reader :logged
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@logged = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def info(msg, tag)
|
13
|
+
@logged << msg
|
14
|
+
end
|
15
|
+
|
16
|
+
def error(msg)
|
17
|
+
fail msg
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Little helper to clean up examples
|
22
|
+
def notify(instrumentation)
|
23
|
+
ActiveSupport::Notifications.instrument "client_request_matrix_data.google_distance_matrix", instrumentation do
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
let(:mock_logger) { MockLogger.new }
|
29
|
+
let(:config) { Configuration.new }
|
30
|
+
|
31
|
+
# Attach our own test logger, re-attach the original attached log subscriber after test.
|
32
|
+
before do
|
33
|
+
@old_subscribers = LogSubscriber.subscribers.dup
|
34
|
+
LogSubscriber.subscribers.clear
|
35
|
+
LogSubscriber.attach_to "google_distance_matrix", LogSubscriber.new(logger: mock_logger, config: config)
|
36
|
+
end
|
37
|
+
|
38
|
+
after do
|
39
|
+
@old_subscribers.each do |subscriber|
|
40
|
+
LogSubscriber.attach_to "google_distance_matrix", subscriber
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
it "logs the url and elements" do
|
46
|
+
url = 'https://example.com'
|
47
|
+
instrumentation = {url: url, elements: 0}
|
48
|
+
|
49
|
+
expect { notify instrumentation }.to change(mock_logger.logged, :length).from(0).to 1
|
50
|
+
|
51
|
+
expect(mock_logger.logged.first).to include "(elements: 0) GET https://example.com"
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "filtering of logged url" do
|
55
|
+
it "filters nothing if config has no keys to be filtered" do
|
56
|
+
config.filter_parameters_in_logged_url.clear
|
57
|
+
|
58
|
+
instrumentation = {url: 'https://example.com/?foo=bar&sensitive=secret'}
|
59
|
+
notify instrumentation
|
60
|
+
|
61
|
+
expect(mock_logger.logged.first).to include "https://example.com/?foo=bar&sensitive=secret"
|
62
|
+
end
|
63
|
+
|
64
|
+
it "filters sensitive GET param if config has it in list of params to filter" do
|
65
|
+
config.filter_parameters_in_logged_url << 'sensitive'
|
66
|
+
|
67
|
+
instrumentation = {url: 'https://example.com/?foo=bar&sensitive=secret'}
|
68
|
+
notify instrumentation
|
69
|
+
|
70
|
+
expect(mock_logger.logged.first).to include "https://example.com/?foo=bar&sensitive=[FILTERED]"
|
71
|
+
end
|
72
|
+
|
73
|
+
it "filters key and signature as defaul from configuration" do
|
74
|
+
instrumentation = {url: 'https://example.com/?key=bar&signature=secret&other=foo'}
|
75
|
+
notify instrumentation
|
76
|
+
|
77
|
+
expect(mock_logger.logged.first).to include "https://example.com/?key=[FILTERED]&signature=[FILTERED]&other=foo"
|
78
|
+
end
|
79
|
+
|
80
|
+
it "filters all appearances of a param" do
|
81
|
+
instrumentation = {url: 'https://example.com/?key=bar&key=secret&other=foo'}
|
82
|
+
notify instrumentation
|
83
|
+
|
84
|
+
expect(mock_logger.logged.first).to include "https://example.com/?key=[FILTERED]&key=[FILTERED]&other=foo"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -81,6 +81,8 @@ describe GoogleDistanceMatrix::Matrix do
|
|
81
81
|
shortest_route_by_duration_to!
|
82
82
|
shortest_route_by_distance_to
|
83
83
|
shortest_route_by_distance_to!
|
84
|
+
shortest_route_by_duration_in_traffic_to
|
85
|
+
shortest_route_by_duration_in_traffic_to!
|
84
86
|
].each do |method|
|
85
87
|
it "delegates #{method} to routes_finder" do
|
86
88
|
finder = double
|
@@ -94,9 +96,22 @@ describe GoogleDistanceMatrix::Matrix do
|
|
94
96
|
end
|
95
97
|
|
96
98
|
describe "making API requests", :request_recordings do
|
97
|
-
it "loads correctly" do
|
99
|
+
it "loads correctly API response data in to route objects" do
|
98
100
|
stub_request(:get, url).to_return body: recorded_request_for(:success)
|
101
|
+
expect(subject.data[0][0].distance_text).to eq '2.0 km'
|
99
102
|
expect(subject.data[0][0].distance_in_meters).to eq 2032
|
103
|
+
expect(subject.data[0][0].duration_text).to eq '6 mins'
|
104
|
+
expect(subject.data[0][0].duration_in_seconds).to eq 367
|
105
|
+
end
|
106
|
+
|
107
|
+
it "loads correctly API response data in to route objects when it includes in traffic data" do
|
108
|
+
stub_request(:get, url).to_return body: recorded_request_for(:success_with_in_traffic)
|
109
|
+
expect(subject.data[0][0].distance_text).to eq '1.8 km'
|
110
|
+
expect(subject.data[0][0].distance_in_meters).to eq 1752
|
111
|
+
expect(subject.data[0][0].duration_text).to eq '7 mins'
|
112
|
+
expect(subject.data[0][0].duration_in_seconds).to eq 435
|
113
|
+
expect(subject.data[0][0].duration_in_traffic_text).to eq '7 mins'
|
114
|
+
expect(subject.data[0][0].duration_in_traffic_in_seconds).to eq 405
|
100
115
|
end
|
101
116
|
|
102
117
|
context "no cache" do
|
@@ -185,7 +200,7 @@ describe GoogleDistanceMatrix::Matrix do
|
|
185
200
|
expect(api_request_stub).to have_been_requested
|
186
201
|
end
|
187
202
|
|
188
|
-
it "
|
203
|
+
it "adds loaded route with errors correctly" do
|
189
204
|
route = subject.data[0][1]
|
190
205
|
|
191
206
|
expect(route.status).to eq "zero_results"
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module GoogleDistanceMatrix
|
4
|
+
describe PolylineEncoder::Delta do
|
5
|
+
it 'calculates deltas correctly' do
|
6
|
+
deltas = subject.deltas_rounded [[38.5, -120.2], [40.7, -120.95], [43.252, -126.453]]
|
7
|
+
|
8
|
+
expect(deltas).to eq [
|
9
|
+
3850000, -12020000,
|
10
|
+
220000, -75000,
|
11
|
+
255200, -550300
|
12
|
+
]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module GoogleDistanceMatrix
|
4
|
+
describe PolylineEncoder do
|
5
|
+
tests = {
|
6
|
+
[[-179.9832104, -179.9832104]] => '`~oia@`~oia@',
|
7
|
+
[[38.5, -120.2], [40.7, -120.95], [43.252, -126.453]] => '_p~iF~ps|U_ulLnnqC_mqNvxq`@',
|
8
|
+
[[41.3522171071184, -86.0456299662023],[41.3522171071183, -86.0454368471533]] => 'krk{FdxdlO?e@'
|
9
|
+
}
|
10
|
+
|
11
|
+
tests.each_pair do |lat_lng_values, expected|
|
12
|
+
it "encodes #{lat_lng_values} to #{expected}" do
|
13
|
+
expect(described_class.encode lat_lng_values).to eq expected
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -5,6 +5,7 @@ describe GoogleDistanceMatrix::Route do
|
|
5
5
|
{
|
6
6
|
"distance" => {"text" => "2.0 km", "value" => 2032},
|
7
7
|
"duration" => {"text" =>"6 mins", "value" => 367},
|
8
|
+
"duration_in_traffic" => {"text" =>"5 mins", "value" => 301},
|
8
9
|
"status" =>"OK"
|
9
10
|
}
|
10
11
|
end
|
@@ -16,6 +17,8 @@ describe GoogleDistanceMatrix::Route do
|
|
16
17
|
it { expect(subject.distance_text).to eq "2.0 km" }
|
17
18
|
it { expect(subject.duration_in_seconds).to eq 367 }
|
18
19
|
it { expect(subject.duration_text).to eq "6 mins" }
|
20
|
+
it { expect(subject.duration_in_traffic_in_seconds).to eq 301 }
|
21
|
+
it { expect(subject.duration_in_traffic_text).to eq "5 mins" }
|
19
22
|
|
20
23
|
it { is_expected.to be_ok }
|
21
24
|
end
|
@@ -21,7 +21,33 @@ describe GoogleDistanceMatrix::RoutesFinder, :request_recordings do
|
|
21
21
|
|
22
22
|
subject { described_class.new matrix }
|
23
23
|
|
24
|
-
context "success" do
|
24
|
+
context "success, with traffic data" do
|
25
|
+
before do
|
26
|
+
matrix.configure do |c|
|
27
|
+
c.departure_time = 'now'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
let!(:api_request_stub) { stub_request(:get, url).to_return body: recorded_request_for(:success_with_in_traffic) }
|
32
|
+
|
33
|
+
describe "#shortest_route_by_duration_in_traffic_to" do
|
34
|
+
it "returns route representing shortest duration to given origin" do
|
35
|
+
expect(subject.shortest_route_by_duration_in_traffic_to(origin_1)).to eq matrix.data[0][0]
|
36
|
+
end
|
37
|
+
|
38
|
+
it "returns route representing shortest duration to given destination" do
|
39
|
+
expect(subject.shortest_route_by_duration_in_traffic_to(destination_2)).to eq matrix.data[1][1]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#shortest_route_by_duration_in_traffic_to!" do
|
44
|
+
it "returns the same as shortest_route_by_duration_in_traffic_to" do
|
45
|
+
expect(subject.shortest_route_by_duration_in_traffic_to!(origin_1)).to eq subject.shortest_route_by_duration_in_traffic_to(origin_1)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "success, without in traffic data" do
|
25
51
|
let!(:api_request_stub) { stub_request(:get, url).to_return body: recorded_request_for(:success) }
|
26
52
|
|
27
53
|
describe "#routes_for" do
|
@@ -123,6 +149,22 @@ describe GoogleDistanceMatrix::RoutesFinder, :request_recordings do
|
|
123
149
|
expect(subject.shortest_route_by_duration_to!(origin_1)).to eq subject.shortest_route_by_duration_to(origin_1)
|
124
150
|
end
|
125
151
|
end
|
152
|
+
|
153
|
+
describe "#shortest_route_by_duration_in_traffic_to" do
|
154
|
+
it "returns route representing shortest duration to given origin" do
|
155
|
+
expect {
|
156
|
+
subject.shortest_route_by_duration_in_traffic_to(origin_1)
|
157
|
+
}.to raise_error GoogleDistanceMatrix::InvalidQuery
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe "#shortest_route_by_duration_in_traffic_to!" do
|
162
|
+
it "returns the same as shortest_route_by_duration_in_traffic_to" do
|
163
|
+
expect {
|
164
|
+
subject.shortest_route_by_duration_in_traffic_to!(origin_1)
|
165
|
+
}.to raise_error GoogleDistanceMatrix::InvalidQuery
|
166
|
+
end
|
167
|
+
end
|
126
168
|
end
|
127
169
|
|
128
170
|
context "routes mssing data" do
|
@@ -3,6 +3,7 @@ require "spec_helper"
|
|
3
3
|
describe GoogleDistanceMatrix::UrlBuilder do
|
4
4
|
let(:delimiter) { described_class::DELIMITER }
|
5
5
|
let(:comma) { CGI.escape "," }
|
6
|
+
let(:colon) { CGI.escape ":" }
|
6
7
|
|
7
8
|
let(:origin_1) { GoogleDistanceMatrix::Place.new address: "address_origin_1" }
|
8
9
|
let(:origin_2) { GoogleDistanceMatrix::Place.new address: "address_origin_2" }
|
@@ -79,6 +80,31 @@ describe GoogleDistanceMatrix::UrlBuilder do
|
|
79
80
|
end
|
80
81
|
end
|
81
82
|
|
83
|
+
describe "use encoded polylines" do
|
84
|
+
let(:destination_3) { GoogleDistanceMatrix::Place.new address: "address_destination_3" }
|
85
|
+
let(:destination_4) { GoogleDistanceMatrix::Place.new lat: 4, lng: 44 }
|
86
|
+
let(:destinations) { [destination_1, destination_2, destination_3, destination_4] }
|
87
|
+
|
88
|
+
before do
|
89
|
+
matrix.configure { |c| c.use_encoded_polylines = true }
|
90
|
+
end
|
91
|
+
|
92
|
+
it "includes places with addresses as addresses" do
|
93
|
+
expect(subject.url).to include "origins=address_origin_1#{delimiter}address_origin_2"
|
94
|
+
end
|
95
|
+
|
96
|
+
it "encodes places with lat/lng values togheter, broken up by addresses to keep places order" do
|
97
|
+
expect(subject.url).to include(
|
98
|
+
# 2 first places encoded togheter as they have lat lng values
|
99
|
+
"destinations=enc#{colon}_ibE_mcbA_ibE_mcbA#{colon}#{delimiter}" +
|
100
|
+
# encoded polyline broken off by a destination with address
|
101
|
+
"address_destination_3#{delimiter}" +
|
102
|
+
# We continue to encode the last destination as it's own ony point polyline
|
103
|
+
"enc#{colon}_glW_wpkG#{colon}"
|
104
|
+
)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
82
108
|
describe "configuration" do
|
83
109
|
context 'with google api key set' do
|
84
110
|
before do
|
@@ -0,0 +1,78 @@
|
|
1
|
+
{
|
2
|
+
"destination_addresses" : [
|
3
|
+
"Drammensveien 1, 0271 Oslo, Norway",
|
4
|
+
"Skjellestadhagen, 1389 Heggedal, Norway"
|
5
|
+
],
|
6
|
+
"origin_addresses" : [ "Karl Johans gate, Oslo, Norway", "Askerveien 1, 1384 Asker, Norway" ],
|
7
|
+
"rows" : [
|
8
|
+
{
|
9
|
+
"elements" : [
|
10
|
+
{
|
11
|
+
"distance" : {
|
12
|
+
"text" : "1.8 km",
|
13
|
+
"value" : 1752
|
14
|
+
},
|
15
|
+
"duration" : {
|
16
|
+
"text" : "7 mins",
|
17
|
+
"value" : 435
|
18
|
+
},
|
19
|
+
"duration_in_traffic" : {
|
20
|
+
"text" : "7 mins",
|
21
|
+
"value" : 405
|
22
|
+
},
|
23
|
+
"status" : "OK"
|
24
|
+
},
|
25
|
+
{
|
26
|
+
"distance" : {
|
27
|
+
"text" : "30.5 km",
|
28
|
+
"value" : 30501
|
29
|
+
},
|
30
|
+
"duration" : {
|
31
|
+
"text" : "38 mins",
|
32
|
+
"value" : 2267
|
33
|
+
},
|
34
|
+
"duration_in_traffic" : {
|
35
|
+
"text" : "36 mins",
|
36
|
+
"value" : 2179
|
37
|
+
},
|
38
|
+
"status" : "OK"
|
39
|
+
}
|
40
|
+
]
|
41
|
+
},
|
42
|
+
{
|
43
|
+
"elements" : [
|
44
|
+
{
|
45
|
+
"distance" : {
|
46
|
+
"text" : "21.3 km",
|
47
|
+
"value" : 21322
|
48
|
+
},
|
49
|
+
"duration" : {
|
50
|
+
"text" : "24 mins",
|
51
|
+
"value" : 1438
|
52
|
+
},
|
53
|
+
"duration_in_traffic" : {
|
54
|
+
"text" : "23 mins",
|
55
|
+
"value" : 1397
|
56
|
+
},
|
57
|
+
"status" : "OK"
|
58
|
+
},
|
59
|
+
{
|
60
|
+
"distance" : {
|
61
|
+
"text" : "9.6 km",
|
62
|
+
"value" : 9550
|
63
|
+
},
|
64
|
+
"duration" : {
|
65
|
+
"text" : "18 mins",
|
66
|
+
"value" : 1109
|
67
|
+
},
|
68
|
+
"duration_in_traffic" : {
|
69
|
+
"text" : "18 mins",
|
70
|
+
"value" : 1083
|
71
|
+
},
|
72
|
+
"status" : "OK"
|
73
|
+
}
|
74
|
+
]
|
75
|
+
}
|
76
|
+
],
|
77
|
+
"status" : "OK"
|
78
|
+
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: google_distance_matrix
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thorbjørn Hermansen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-05-
|
11
|
+
date: 2016-05-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -148,22 +148,30 @@ files:
|
|
148
148
|
- lib/google_distance_matrix/matrix.rb
|
149
149
|
- lib/google_distance_matrix/place.rb
|
150
150
|
- lib/google_distance_matrix/places.rb
|
151
|
+
- lib/google_distance_matrix/polyline_encoder.rb
|
152
|
+
- lib/google_distance_matrix/polyline_encoder/delta.rb
|
153
|
+
- lib/google_distance_matrix/polyline_encoder/value_encoder.rb
|
151
154
|
- lib/google_distance_matrix/railtie.rb
|
152
155
|
- lib/google_distance_matrix/route.rb
|
153
156
|
- lib/google_distance_matrix/routes_finder.rb
|
154
157
|
- lib/google_distance_matrix/url_builder.rb
|
158
|
+
- lib/google_distance_matrix/url_builder/polyline_encoder_buffer.rb
|
155
159
|
- lib/google_distance_matrix/version.rb
|
156
160
|
- spec/lib/google_distance_matrix/client_cache_spec.rb
|
157
161
|
- spec/lib/google_distance_matrix/client_spec.rb
|
158
162
|
- spec/lib/google_distance_matrix/configuration_spec.rb
|
163
|
+
- spec/lib/google_distance_matrix/log_subscriber_spec.rb
|
159
164
|
- spec/lib/google_distance_matrix/logger_spec.rb
|
160
165
|
- spec/lib/google_distance_matrix/matrix_spec.rb
|
161
166
|
- spec/lib/google_distance_matrix/place_spec.rb
|
162
167
|
- spec/lib/google_distance_matrix/places_spec.rb
|
168
|
+
- spec/lib/google_distance_matrix/polyline_encoder/delta_spec.rb
|
169
|
+
- spec/lib/google_distance_matrix/polyline_encoder_spec.rb
|
163
170
|
- spec/lib/google_distance_matrix/route_spec.rb
|
164
171
|
- spec/lib/google_distance_matrix/routes_finder_spec.rb
|
165
172
|
- spec/lib/google_distance_matrix/url_builder_spec.rb
|
166
173
|
- spec/request_recordings/success
|
174
|
+
- spec/request_recordings/success_with_in_traffic
|
167
175
|
- spec/request_recordings/zero_results
|
168
176
|
- spec/spec_helper.rb
|
169
177
|
homepage: ''
|
@@ -194,13 +202,17 @@ test_files:
|
|
194
202
|
- spec/lib/google_distance_matrix/client_cache_spec.rb
|
195
203
|
- spec/lib/google_distance_matrix/client_spec.rb
|
196
204
|
- spec/lib/google_distance_matrix/configuration_spec.rb
|
205
|
+
- spec/lib/google_distance_matrix/log_subscriber_spec.rb
|
197
206
|
- spec/lib/google_distance_matrix/logger_spec.rb
|
198
207
|
- spec/lib/google_distance_matrix/matrix_spec.rb
|
199
208
|
- spec/lib/google_distance_matrix/place_spec.rb
|
200
209
|
- spec/lib/google_distance_matrix/places_spec.rb
|
210
|
+
- spec/lib/google_distance_matrix/polyline_encoder/delta_spec.rb
|
211
|
+
- spec/lib/google_distance_matrix/polyline_encoder_spec.rb
|
201
212
|
- spec/lib/google_distance_matrix/route_spec.rb
|
202
213
|
- spec/lib/google_distance_matrix/routes_finder_spec.rb
|
203
214
|
- spec/lib/google_distance_matrix/url_builder_spec.rb
|
204
215
|
- spec/request_recordings/success
|
216
|
+
- spec/request_recordings/success_with_in_traffic
|
205
217
|
- spec/request_recordings/zero_results
|
206
218
|
- spec/spec_helper.rb
|