google_distance_matrix 0.4.0 → 0.5.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.
- checksums.yaml +4 -4
- data/.editorconfig +16 -0
- data/.rubocop.yml +6 -0
- data/.ruby-version +1 -1
- data/.travis.yml +1 -0
- data/CHANGELOG.md +20 -0
- data/Gemfile +2 -0
- data/Rakefile +9 -4
- data/google_distance_matrix.gemspec +20 -18
- data/lib/google_distance_matrix/client.rb +32 -18
- data/lib/google_distance_matrix/client_cache.rb +9 -3
- data/lib/google_distance_matrix/configuration.rb +37 -19
- data/lib/google_distance_matrix/errors.rb +6 -3
- data/lib/google_distance_matrix/log_subscriber.rb +14 -14
- data/lib/google_distance_matrix/logger.rb +6 -4
- data/lib/google_distance_matrix/matrix.rb +45 -22
- data/lib/google_distance_matrix/place.rb +32 -25
- data/lib/google_distance_matrix/places.rb +5 -4
- data/lib/google_distance_matrix/polyline_encoder/delta.rb +4 -2
- data/lib/google_distance_matrix/polyline_encoder/value_encoder.rb +11 -4
- data/lib/google_distance_matrix/polyline_encoder.rb +2 -2
- data/lib/google_distance_matrix/railtie.rb +4 -1
- data/lib/google_distance_matrix/route.rb +22 -15
- data/lib/google_distance_matrix/routes_finder.rb +25 -29
- data/lib/google_distance_matrix/url_builder/polyline_encoder_buffer.rb +3 -0
- data/lib/google_distance_matrix/url_builder.rb +44 -16
- data/lib/google_distance_matrix/version.rb +3 -1
- data/lib/google_distance_matrix.rb +25 -23
- data/spec/lib/google_distance_matrix/client_cache_spec.rb +26 -11
- data/spec/lib/google_distance_matrix/client_spec.rb +40 -30
- data/spec/lib/google_distance_matrix/configuration_spec.rb +36 -24
- data/spec/lib/google_distance_matrix/log_subscriber_spec.rb +13 -44
- data/spec/lib/google_distance_matrix/logger_spec.rb +16 -13
- data/spec/lib/google_distance_matrix/matrix_spec.rb +90 -57
- data/spec/lib/google_distance_matrix/place_spec.rb +30 -25
- data/spec/lib/google_distance_matrix/places_spec.rb +29 -28
- data/spec/lib/google_distance_matrix/polyline_encoder/delta_spec.rb +5 -3
- data/spec/lib/google_distance_matrix/polyline_encoder_spec.rb +7 -2
- data/spec/lib/google_distance_matrix/route_spec.rb +11 -9
- data/spec/lib/google_distance_matrix/routes_finder_spec.rb +95 -81
- data/spec/lib/google_distance_matrix/url_builder_spec.rb +97 -48
- data/spec/spec_helper.rb +3 -1
- metadata +35 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e2a2232b164549acbd29af07935315c8859dc19c
|
4
|
+
data.tar.gz: 3f29dc7ef98d87e913c1372fabd660766150dc8b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bead0dcdb680422cac5db6463af54580036dc6fae0f98373eec513e18a3a197ca7981d57db4ca64a27cc7461e675bd181b81a284b0cd98129e98fa916735be28
|
7
|
+
data.tar.gz: 0d6d9b8a96282568c647293adab6c58e9eed438e36d1e42f1f4b473a6da59c7cb5014eebc5cc56b4326211e8faa68e292651940a5f1e1d2c30b9b82ba5435710
|
data/.editorconfig
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# EditorConfig helps developers define and maintain consistent
|
2
|
+
# coding styles between different editors and IDEs
|
3
|
+
# editorconfig.org
|
4
|
+
|
5
|
+
root = true
|
6
|
+
|
7
|
+
[*]
|
8
|
+
end_of_line = lf
|
9
|
+
charset = utf-8
|
10
|
+
trim_trailing_whitespace = true
|
11
|
+
insert_final_newline = true
|
12
|
+
indent_style = space
|
13
|
+
indent_size = 2
|
14
|
+
|
15
|
+
[*.{diff,md}]
|
16
|
+
trim_trailing_whitespace = false
|
data/.rubocop.yml
ADDED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.3.
|
1
|
+
2.3.4
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
## v.0.5.0
|
2
|
+
|
3
|
+
This release contains breaking change where `url` has been renamed to
|
4
|
+
`sensitive_url`. A `filtered_url` method is added to make it clear that
|
5
|
+
the URL returned is filtered according to configuration while the other one
|
6
|
+
will contain sensitive information like key and signature.
|
7
|
+
|
8
|
+
The cache key is changed so it no longer uses the URL, but a digest of the URL
|
9
|
+
as key. You may set `config.cache_key_transform` to a block passing given url
|
10
|
+
through if you don't want this.
|
11
|
+
|
12
|
+
* Fixed an issue where read/write to cache used url with sensitive data and
|
13
|
+
and filtered url resulting in cache miss.
|
14
|
+
* Instrumentation payload `url` renamed `sensitive_url`.
|
15
|
+
* Instrumentation payload added `filtered_url`.
|
16
|
+
* Cache key is a digest of the `sensitive_url` so we don't store in cache the
|
17
|
+
sensitive parts of the URL.
|
18
|
+
* Digesting cache key is configurable with `cache_key_transform`. It's a callable
|
19
|
+
object expected to take the url and transform it to the key you want.
|
20
|
+
|
1
21
|
## v.0.4.0
|
2
22
|
* When mode is `driving` and `departure_time` is set all `route` objects will contain
|
3
23
|
`duration_in_traffic_in_seconds` and `duration_in_traffic_text`.
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -1,9 +1,14 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
|
5
|
+
require 'rubocop/rake_task'
|
6
|
+
RuboCop::RakeTask.new
|
7
|
+
|
8
|
+
require 'rspec/core/rake_task'
|
4
9
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
5
|
-
t.rspec_opts = [
|
10
|
+
t.rspec_opts = ['-c', '-f progress', '-r ./spec/spec_helper.rb']
|
6
11
|
t.pattern = 'spec/**/*_spec.rb'
|
7
12
|
end
|
8
13
|
|
9
|
-
task default:
|
14
|
+
task default: %i[rubocop spec]
|
@@ -1,30 +1,32 @@
|
|
1
|
-
#
|
1
|
+
# frozen_String_literal: true
|
2
|
+
|
2
3
|
lib = File.expand_path('../lib', __FILE__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require 'google_distance_matrix/version'
|
5
6
|
|
6
7
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
8
|
+
spec.name = 'google_distance_matrix'
|
8
9
|
spec.version = GoogleDistanceMatrix::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
11
|
-
spec.description = %
|
12
|
-
spec.summary = %
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
10
|
+
spec.authors = ['Thorbjørn Hermansen']
|
11
|
+
spec.email = ['thhermansen@gmail.com']
|
12
|
+
spec.description = %(Ruby client for The Google Distance Matrix API)
|
13
|
+
spec.summary = %(Ruby client for The Google Distance Matrix API)
|
14
|
+
spec.homepage = ''
|
15
|
+
spec.license = 'MIT'
|
15
16
|
|
16
|
-
spec.files = `git ls-files`.split(
|
17
|
+
spec.files = `git ls-files`.split($RS)
|
17
18
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
19
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = [
|
20
|
+
spec.require_paths = ['lib']
|
20
21
|
|
21
|
-
spec.add_dependency
|
22
|
-
spec.add_dependency
|
23
|
-
spec.add_dependency
|
22
|
+
spec.add_dependency 'activesupport', '>= 3.2.13', '<= 5'
|
23
|
+
spec.add_dependency 'activemodel', '>= 3.2.13', '<= 5'
|
24
|
+
spec.add_dependency 'google_business_api_url_signer', '~> 0.1.3'
|
24
25
|
|
25
|
-
spec.add_development_dependency
|
26
|
-
spec.add_development_dependency
|
27
|
-
spec.add_development_dependency
|
28
|
-
spec.add_development_dependency
|
29
|
-
spec.add_development_dependency
|
26
|
+
spec.add_development_dependency 'bundler'
|
27
|
+
spec.add_development_dependency 'rspec', '~> 3.5.0'
|
28
|
+
spec.add_development_dependency 'rubocop', '~> 0.48'
|
29
|
+
spec.add_development_dependency 'shoulda-matchers', '~> 3.1.1'
|
30
|
+
spec.add_development_dependency 'webmock', '~> 3.0.1'
|
31
|
+
spec.add_development_dependency 'rake'
|
30
32
|
end
|
@@ -1,4 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module GoogleDistanceMatrix
|
4
|
+
# HTTP client making request to Google's API
|
2
5
|
class Client
|
3
6
|
CLIENT_ERRORS = %w[
|
4
7
|
INVALID_REQUEST
|
@@ -6,41 +9,52 @@ module GoogleDistanceMatrix
|
|
6
9
|
OVER_QUERY_LIMIT
|
7
10
|
REQUEST_DENIED
|
8
11
|
UNKNOWN_ERROR
|
9
|
-
]
|
10
|
-
|
11
|
-
|
12
|
+
].freeze
|
13
|
+
|
14
|
+
# Make a GET request to given URL
|
15
|
+
#
|
16
|
+
# @param url The URL to Google's API we'll make a request to
|
17
|
+
# @param instrumentation A hash with instrumentation payload
|
18
|
+
# @param options Other options we don't care about, for example we'll capture
|
19
|
+
# `configuration` option which we are not using, but the ClientCache
|
20
|
+
# is using.
|
21
|
+
#
|
22
|
+
# @return Hash with data from parsed response body
|
23
|
+
def get(url, instrumentation: {}, **_options)
|
12
24
|
uri = URI.parse url
|
13
|
-
instrumentation = {url: url}.merge(options[:instrumentation] || {})
|
14
25
|
|
15
|
-
response = ActiveSupport::Notifications.instrument
|
26
|
+
response = ActiveSupport::Notifications.instrument(
|
27
|
+
'client_request_matrix_data.google_distance_matrix', instrumentation
|
28
|
+
) do
|
16
29
|
Net::HTTP.get_response uri
|
17
30
|
end
|
18
31
|
|
32
|
+
handle response, url
|
33
|
+
rescue Timeout::Error => error
|
34
|
+
raise ServerError, error
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def handle(response, url) # rubocop:disable Metrics/MethodLength
|
19
40
|
case response
|
20
41
|
when Net::HTTPSuccess
|
21
42
|
inspect_for_client_errors! response
|
22
43
|
when Net::HTTPRequestURITooLong
|
23
|
-
|
44
|
+
raise MatrixUrlTooLong.new url, UrlBuilder::MAX_URL_SIZE, response
|
24
45
|
when Net::HTTPClientError
|
25
|
-
|
46
|
+
raise ClientError, response
|
26
47
|
when Net::HTTPServerError
|
27
|
-
|
48
|
+
raise ServerError, response
|
28
49
|
else # Handle this as a request error for now. Maybe fine tune this more later.
|
29
|
-
|
50
|
+
raise ServerError, response
|
30
51
|
end
|
31
|
-
rescue Timeout::Error => error
|
32
|
-
fail ServerError.new error
|
33
52
|
end
|
34
53
|
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
54
|
def inspect_for_client_errors!(response)
|
39
|
-
status = JSON.parse(response.body).fetch
|
55
|
+
status = JSON.parse(response.body).fetch 'status'
|
40
56
|
|
41
|
-
if CLIENT_ERRORS.include? status
|
42
|
-
fail ClientError.new response, status
|
43
|
-
end
|
57
|
+
raise ClientError.new response, status if CLIENT_ERRORS.include? status
|
44
58
|
|
45
59
|
response
|
46
60
|
end
|
@@ -1,9 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module GoogleDistanceMatrix
|
4
|
+
# Cached client, which takes care of caching data from Google API
|
2
5
|
class ClientCache
|
3
6
|
attr_reader :client, :cache
|
4
7
|
|
5
|
-
|
6
|
-
|
8
|
+
# Returns a cache key for given URL
|
9
|
+
#
|
10
|
+
# @return String
|
11
|
+
def self.key(url, config)
|
12
|
+
config.cache_key_transform.call url
|
7
13
|
end
|
8
14
|
|
9
15
|
def initialize(client, cache)
|
@@ -12,7 +18,7 @@ module GoogleDistanceMatrix
|
|
12
18
|
end
|
13
19
|
|
14
20
|
def get(url, options = {})
|
15
|
-
cache.fetch self.class.key(url) do
|
21
|
+
cache.fetch self.class.key(url, options.fetch(:configuration)) do
|
16
22
|
client.get url, options
|
17
23
|
end
|
18
24
|
end
|
@@ -1,3 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'digest'
|
4
|
+
|
1
5
|
module GoogleDistanceMatrix
|
2
6
|
# Public: Configuration of matrix and it's request.
|
3
7
|
#
|
@@ -15,19 +19,20 @@ module GoogleDistanceMatrix
|
|
15
19
|
departure_time arrival_time
|
16
20
|
transit_mode transit_routing_preference
|
17
21
|
traffic_model
|
18
|
-
]
|
22
|
+
].freeze
|
19
23
|
|
20
24
|
API_DEFAULTS = {
|
21
|
-
mode:
|
22
|
-
units:
|
23
|
-
traffic_model:
|
25
|
+
mode: 'driving',
|
26
|
+
units: 'metric',
|
27
|
+
traffic_model: 'best_guess',
|
24
28
|
use_encoded_polylines: false,
|
25
29
|
protocol: 'https',
|
26
30
|
lat_lng_scale: 5,
|
27
|
-
filter_parameters_in_logged_url: [
|
31
|
+
filter_parameters_in_logged_url: %w[key signature].freeze,
|
32
|
+
cache_key_transform: ->(url) { Digest::SHA512.new.update(url).to_s }
|
28
33
|
}.with_indifferent_access
|
29
34
|
|
30
|
-
attr_accessor
|
35
|
+
attr_accessor(*ATTRIBUTES)
|
31
36
|
|
32
37
|
# The protocol to use, either http or https
|
33
38
|
attr_accessor :protocol
|
@@ -50,22 +55,38 @@ module GoogleDistanceMatrix
|
|
50
55
|
# When logging we filter sensitive parameters
|
51
56
|
attr_accessor :filter_parameters_in_logged_url
|
52
57
|
|
53
|
-
|
54
|
-
|
55
|
-
|
58
|
+
# Callable object which transform given url to key used in cache
|
59
|
+
# @see ClientCache
|
60
|
+
attr_accessor :cache_key_transform
|
61
|
+
|
62
|
+
validates :mode, inclusion: { in: %w[driving walking bicycling transit] }, allow_blank: true
|
63
|
+
validates :avoid, inclusion: { in: %w[tolls highways ferries indoor] }, allow_blank: true
|
64
|
+
validates :units, inclusion: { in: %w[metric imperial] }, allow_blank: true
|
56
65
|
|
57
66
|
validates :departure_time, format: /\A(\d+|now)\Z/, allow_blank: true
|
58
67
|
validates :arrival_time, numericality: true, allow_blank: true
|
59
68
|
|
60
|
-
validates :transit_mode,
|
61
|
-
|
62
|
-
|
69
|
+
validates :transit_mode,
|
70
|
+
inclusion: { in: %w[bus subway train tram rail] },
|
71
|
+
allow_blank: true
|
72
|
+
|
73
|
+
validates :transit_routing_preference,
|
74
|
+
inclusion: { in: %w[less_walking fewer_transfers] },
|
75
|
+
allow_blank: true
|
63
76
|
|
64
|
-
validates :
|
77
|
+
validates :traffic_model,
|
78
|
+
inclusion: { in: %w[best_guess pessimistic optimistic] },
|
79
|
+
allow_blank: true
|
80
|
+
|
81
|
+
validates :protocol, inclusion: { in: %w[http https] }, allow_blank: true
|
65
82
|
|
66
83
|
def initialize
|
67
84
|
API_DEFAULTS.each_pair do |attr_name, value|
|
68
|
-
self[attr_name] =
|
85
|
+
self[attr_name] = begin
|
86
|
+
value.dup
|
87
|
+
rescue
|
88
|
+
value
|
89
|
+
end
|
69
90
|
end
|
70
91
|
end
|
71
92
|
|
@@ -77,7 +98,6 @@ module GoogleDistanceMatrix
|
|
77
98
|
public_send "#{attr_name}=", value
|
78
99
|
end
|
79
100
|
|
80
|
-
|
81
101
|
private
|
82
102
|
|
83
103
|
def array_param
|
@@ -89,15 +109,13 @@ module GoogleDistanceMatrix
|
|
89
109
|
out << ['client', google_business_api_client_id]
|
90
110
|
end
|
91
111
|
|
92
|
-
if google_api_key.present?
|
93
|
-
out << ['key', google_api_key]
|
94
|
-
end
|
112
|
+
out << ['key', google_api_key] if google_api_key.present?
|
95
113
|
|
96
114
|
out
|
97
115
|
end
|
98
116
|
|
99
117
|
def param_same_as_api_default?(param)
|
100
|
-
|
118
|
+
API_DEFAULTS[param[0]] == param[1]
|
101
119
|
end
|
102
120
|
end
|
103
121
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module GoogleDistanceMatrix
|
2
4
|
# Public: Error class for lib.
|
3
5
|
class Error < StandardError
|
@@ -67,7 +69,8 @@ module GoogleDistanceMatrix
|
|
67
69
|
end
|
68
70
|
|
69
71
|
def to_s
|
70
|
-
"GoogleDistanceMatrix::ClientError -
|
72
|
+
"GoogleDistanceMatrix::ClientError - \
|
73
|
+
#{[response, status_read_from_api_response].compact.join('. ')}."
|
71
74
|
end
|
72
75
|
end
|
73
76
|
|
@@ -75,7 +78,8 @@ module GoogleDistanceMatrix
|
|
75
78
|
#
|
76
79
|
# See https://developers.google.com/maps/documentation/distancematrix/#Limits, which states:
|
77
80
|
# "Distance Matrix API URLs are restricted to 2048 characters, before URL encoding."
|
78
|
-
# "As some Distance Matrix API service URLs may involve many locations,
|
81
|
+
# "As some Distance Matrix API service URLs may involve many locations,
|
82
|
+
# be aware of this limit when constructing your URLs."
|
79
83
|
#
|
80
84
|
class MatrixUrlTooLong < ClientError
|
81
85
|
attr_reader :url, :max_url_size
|
@@ -91,5 +95,4 @@ module GoogleDistanceMatrix
|
|
91
95
|
"Matrix API URL max size is: #{max_url_size}. Built URL was: #{url.length}. URL: '#{url}'."
|
92
96
|
end
|
93
97
|
end
|
94
|
-
|
95
98
|
end
|
@@ -1,8 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module GoogleDistanceMatrix
|
4
|
+
# LogSubscriber logs to GoogleDistanceMatrix.logger by subscribing to gem's intstrumentation.
|
5
|
+
#
|
6
|
+
# NOTE: This log subscruber uses the default_configuration as it's configuration.
|
7
|
+
# This is relevant for example for the filter_parameters_in_logged_url configuration
|
2
8
|
class LogSubscriber < ActiveSupport::LogSubscriber
|
3
9
|
attr_reader :logger, :config
|
4
10
|
|
5
|
-
def initialize(
|
11
|
+
def initialize(
|
12
|
+
logger: GoogleDistanceMatrix.logger,
|
13
|
+
config: GoogleDistanceMatrix.default_configuration
|
14
|
+
)
|
6
15
|
super()
|
7
16
|
|
8
17
|
@logger = logger
|
@@ -10,20 +19,11 @@ module GoogleDistanceMatrix
|
|
10
19
|
end
|
11
20
|
|
12
21
|
def client_request_matrix_data(event)
|
13
|
-
url =
|
14
|
-
logger.info "(#{event.duration}ms) (elements: #{event.payload[:elements]}) GET #{url}",
|
15
|
-
|
16
|
-
|
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
|
22
|
+
url = event.payload[:filtered_url]
|
23
|
+
logger.info "(#{event.duration}ms) (elements: #{event.payload[:elements]}) GET #{url}",
|
24
|
+
tag: :client
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
GoogleDistanceMatrix::LogSubscriber.attach_to
|
29
|
+
GoogleDistanceMatrix::LogSubscriber.attach_to 'google_distance_matrix'
|
@@ -1,7 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module GoogleDistanceMatrix
|
4
|
+
# Logger class for Google Distance Matrix
|
2
5
|
class Logger
|
3
|
-
PREFIXES = %w[google_distance_matrix]
|
4
|
-
LEVELS = %w[fatal error warn info debug]
|
6
|
+
PREFIXES = %w[google_distance_matrix].freeze
|
7
|
+
LEVELS = %w[fatal error warn info debug].freeze
|
5
8
|
|
6
9
|
attr_reader :backend
|
7
10
|
|
@@ -20,13 +23,12 @@ module GoogleDistanceMatrix
|
|
20
23
|
end
|
21
24
|
end
|
22
25
|
|
23
|
-
|
24
26
|
private
|
25
27
|
|
26
28
|
def tag_msg(msg, tags)
|
27
29
|
msg_buffer = tags.map { |tag| "[#{tag}]" }
|
28
30
|
msg_buffer << msg
|
29
|
-
msg_buffer.join
|
31
|
+
msg_buffer.join ' '
|
30
32
|
end
|
31
33
|
end
|
32
34
|
end
|