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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +16 -0
  3. data/.rubocop.yml +6 -0
  4. data/.ruby-version +1 -1
  5. data/.travis.yml +1 -0
  6. data/CHANGELOG.md +20 -0
  7. data/Gemfile +2 -0
  8. data/Rakefile +9 -4
  9. data/google_distance_matrix.gemspec +20 -18
  10. data/lib/google_distance_matrix/client.rb +32 -18
  11. data/lib/google_distance_matrix/client_cache.rb +9 -3
  12. data/lib/google_distance_matrix/configuration.rb +37 -19
  13. data/lib/google_distance_matrix/errors.rb +6 -3
  14. data/lib/google_distance_matrix/log_subscriber.rb +14 -14
  15. data/lib/google_distance_matrix/logger.rb +6 -4
  16. data/lib/google_distance_matrix/matrix.rb +45 -22
  17. data/lib/google_distance_matrix/place.rb +32 -25
  18. data/lib/google_distance_matrix/places.rb +5 -4
  19. data/lib/google_distance_matrix/polyline_encoder/delta.rb +4 -2
  20. data/lib/google_distance_matrix/polyline_encoder/value_encoder.rb +11 -4
  21. data/lib/google_distance_matrix/polyline_encoder.rb +2 -2
  22. data/lib/google_distance_matrix/railtie.rb +4 -1
  23. data/lib/google_distance_matrix/route.rb +22 -15
  24. data/lib/google_distance_matrix/routes_finder.rb +25 -29
  25. data/lib/google_distance_matrix/url_builder/polyline_encoder_buffer.rb +3 -0
  26. data/lib/google_distance_matrix/url_builder.rb +44 -16
  27. data/lib/google_distance_matrix/version.rb +3 -1
  28. data/lib/google_distance_matrix.rb +25 -23
  29. data/spec/lib/google_distance_matrix/client_cache_spec.rb +26 -11
  30. data/spec/lib/google_distance_matrix/client_spec.rb +40 -30
  31. data/spec/lib/google_distance_matrix/configuration_spec.rb +36 -24
  32. data/spec/lib/google_distance_matrix/log_subscriber_spec.rb +13 -44
  33. data/spec/lib/google_distance_matrix/logger_spec.rb +16 -13
  34. data/spec/lib/google_distance_matrix/matrix_spec.rb +90 -57
  35. data/spec/lib/google_distance_matrix/place_spec.rb +30 -25
  36. data/spec/lib/google_distance_matrix/places_spec.rb +29 -28
  37. data/spec/lib/google_distance_matrix/polyline_encoder/delta_spec.rb +5 -3
  38. data/spec/lib/google_distance_matrix/polyline_encoder_spec.rb +7 -2
  39. data/spec/lib/google_distance_matrix/route_spec.rb +11 -9
  40. data/spec/lib/google_distance_matrix/routes_finder_spec.rb +95 -81
  41. data/spec/lib/google_distance_matrix/url_builder_spec.rb +97 -48
  42. data/spec/spec_helper.rb +3 -1
  43. metadata +35 -7
@@ -1,5 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module GoogleDistanceMatrix
2
4
  class UrlBuilder
5
+ # A buffer to contain Polyline Encoder
3
6
  class PolylineEncoderBuffer
4
7
  def initialize
5
8
  @buffer = []
@@ -1,9 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'url_builder/polyline_encoder_buffer'
2
4
 
3
5
  module GoogleDistanceMatrix
6
+ # Takes care of building the url for given matrix
4
7
  class UrlBuilder
5
- BASE_URL = "maps.googleapis.com/maps/api/distancematrix/json"
6
- DELIMITER = CGI.escape("|")
8
+ BASE_URL = 'maps.googleapis.com/maps/api/distancematrix/json'
9
+ DELIMITER = CGI.escape('|')
7
10
  MAX_URL_SIZE = 2048
8
11
 
9
12
  attr_reader :matrix
@@ -12,41 +15,62 @@ module GoogleDistanceMatrix
12
15
  def initialize(matrix)
13
16
  @matrix = matrix
14
17
 
15
- fail InvalidMatrix.new matrix if matrix.invalid?
18
+ raise InvalidMatrix, matrix if matrix.invalid?
16
19
  end
17
20
 
18
- def url
19
- @url ||= build_url
21
+ # Returns the URL we'll call Google API with
22
+ #
23
+ # This URL contains key and signature and is therefor
24
+ # sensitive.
25
+ #
26
+ # @return String
27
+ # @see filtered_url
28
+ def sensitive_url
29
+ @sensitive_url ||= build_url
20
30
  end
21
31
 
32
+ # Returns the URL filtered as the configuration of the matrix dictates
33
+ #
34
+ # @return String
35
+ def filtered_url
36
+ filter_url sensitive_url
37
+ end
22
38
 
23
39
  private
24
40
 
25
41
  def build_url
26
- url = [protocol, BASE_URL, "?", get_params_string].join
42
+ url = [protocol, BASE_URL, '?', query_params_string].join
27
43
 
28
44
  if sign_url?
29
- url = GoogleBusinessApiUrlSigner.add_signature(url, configuration.google_business_api_private_key)
45
+ url = GoogleBusinessApiUrlSigner.add_signature(
46
+ url, configuration.google_business_api_private_key
47
+ )
30
48
  end
31
49
 
32
- if url.length > MAX_URL_SIZE
33
- fail MatrixUrlTooLong.new url, MAX_URL_SIZE
50
+ raise MatrixUrlTooLong.new url, MAX_URL_SIZE if url.length > MAX_URL_SIZE
51
+
52
+ url
53
+ end
54
+
55
+ def filter_url(url)
56
+ configuration.filter_parameters_in_logged_url.each do |param|
57
+ url = url.gsub(/(#{param})=.*?(&|$)/, '\1=[FILTERED]\2')
34
58
  end
35
59
 
36
60
  url
37
61
  end
38
62
 
39
63
  def sign_url?
40
- configuration.google_business_api_client_id.present? and
41
- configuration.google_business_api_private_key.present?
64
+ configuration.google_business_api_client_id.present? &&
65
+ configuration.google_business_api_private_key.present?
42
66
  end
43
67
 
44
68
  def include_api_key?
45
69
  configuration.google_api_key.present?
46
70
  end
47
71
 
48
- def get_params_string
49
- params.to_a.map { |key_value| key_value.join("=") }.join("&")
72
+ def query_params_string
73
+ params.to_a.map { |key_value| key_value.join('=') }.join('&')
50
74
  end
51
75
 
52
76
  def params
@@ -56,8 +80,10 @@ module GoogleDistanceMatrix
56
80
  )
57
81
  end
58
82
 
83
+ # rubocop:disable Metrics/MethodLength
84
+ # rubocop:disable Metrics/AbcSize
59
85
  def places_to_param(places)
60
- places_to_param_config = {lat_lng_scale: configuration.lat_lng_scale}
86
+ places_to_param_config = { lat_lng_scale: configuration.lat_lng_scale }
61
87
 
62
88
  out = []
63
89
  polyline_encode_buffer = PolylineEncoderBuffer.new
@@ -67,7 +93,7 @@ module GoogleDistanceMatrix
67
93
  polyline_encode_buffer << place.lat_lng
68
94
  else
69
95
  polyline_encode_buffer.flush to: out
70
- out << escape(place.to_param places_to_param_config)
96
+ out << escape(place.to_param(places_to_param_config))
71
97
  end
72
98
  end
73
99
 
@@ -75,9 +101,11 @@ module GoogleDistanceMatrix
75
101
 
76
102
  out.join(DELIMITER)
77
103
  end
104
+ # rubocop:enable Metrics/MethodLength
105
+ # rubocop:enable Metrics/AbcSize
78
106
 
79
107
  def protocol
80
- configuration.protocol + "://"
108
+ configuration.protocol + '://'
81
109
  end
82
110
 
83
111
  def escape(string)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module GoogleDistanceMatrix
2
- VERSION = "0.4.0"
4
+ VERSION = '0.5.0'
3
5
  end
@@ -1,29 +1,31 @@
1
- require "google_distance_matrix/version"
2
-
3
- require "cgi"
4
- require "json"
5
- require "active_model"
6
- require "active_support/core_ext/hash"
7
- require "google_business_api_url_signer"
8
-
9
- require "google_distance_matrix/logger"
10
- require "google_distance_matrix/errors"
11
- require "google_distance_matrix/configuration"
12
- require "google_distance_matrix/url_builder"
13
- require "google_distance_matrix/client"
14
- require "google_distance_matrix/client_cache"
15
- require "google_distance_matrix/routes_finder"
16
- require "google_distance_matrix/matrix"
17
- require "google_distance_matrix/places"
18
- require "google_distance_matrix/place"
19
- require "google_distance_matrix/route"
20
- require "google_distance_matrix/polyline_encoder"
1
+ # frozen_string_literal: true
2
+
3
+ require 'google_distance_matrix/version'
4
+
5
+ require 'cgi'
6
+ require 'json'
7
+ require 'active_model'
8
+ require 'active_support/core_ext/hash'
9
+ require 'google_business_api_url_signer'
10
+
11
+ require 'google_distance_matrix/logger'
12
+ require 'google_distance_matrix/errors'
13
+ require 'google_distance_matrix/configuration'
14
+ require 'google_distance_matrix/url_builder'
15
+ require 'google_distance_matrix/client'
16
+ require 'google_distance_matrix/client_cache'
17
+ require 'google_distance_matrix/routes_finder'
18
+ require 'google_distance_matrix/matrix'
19
+ require 'google_distance_matrix/places'
20
+ require 'google_distance_matrix/place'
21
+ require 'google_distance_matrix/route'
22
+ require 'google_distance_matrix/polyline_encoder'
21
23
 
22
24
  require 'google_distance_matrix/railtie' if defined? Rails
23
25
 
24
-
26
+ # Main module for the GoogleDistanceMatrix
25
27
  module GoogleDistanceMatrix
26
- extend self
28
+ module_function
27
29
 
28
30
  def default_configuration
29
31
  @default_configuration ||= Configuration.new
@@ -38,4 +40,4 @@ module GoogleDistanceMatrix
38
40
  end
39
41
  end
40
42
 
41
- require "google_distance_matrix/log_subscriber"
43
+ require 'google_distance_matrix/log_subscriber'
@@ -1,25 +1,40 @@
1
- require "spec_helper"
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
2
4
 
3
5
  describe GoogleDistanceMatrix::ClientCache do
4
- let(:url) { "http://www.example.com" }
5
- let(:options) { {hello: :options} }
6
+ let(:config) { GoogleDistanceMatrix::Configuration.new }
7
+ let(:url) { 'http://www.example.com' }
8
+ let(:options) { { hello: :options, configuration: config } }
6
9
 
7
- let(:client) { double get: "data" }
10
+ let(:client) { double get: 'data' }
8
11
  let(:cache) { double }
9
12
 
10
13
  subject { described_class.new client, cache }
11
14
 
12
- describe "#get" do
13
- it "returns from cache if it hits" do
14
- expect(cache).to receive(:fetch).with(url).and_return "cached-data"
15
- expect(subject.get(url, options)).to eq "cached-data"
15
+ # rubocop:disable Metrics/LineLength
16
+ describe '::key' do
17
+ it 'returns a digest of given URL' do
18
+ key = described_class.key 'some url with secret parts', config
19
+ expect(key).to eq 'e90595434d4e321da6b01d2b99d77419ddaa8861d83c5971c4a119ee76bb80a7003915cc16e6966615f205b4a1d5411bb5d4a0d907f611b3fe4cc8d9049f4f9c'
20
+ end
21
+ end
22
+
23
+ describe '#get' do
24
+ it 'returns from cache if it hits' do
25
+ expect(cache)
26
+ .to receive(:fetch)
27
+ .with('2f7d4c4d8a51afd0f9efb9edfda07591591cccc3704130328ad323d3cb5bf7ff19df5e895b402c99217d27d5f4547618094d47069c9ba58370ed8e26cc1de114')
28
+ .and_return 'cached-data'
29
+
30
+ expect(subject.get(url, options)).to eq 'cached-data'
16
31
  end
17
32
 
18
- it "asks client when cache miss" do
19
- expect(client).to receive(:get).with(url, options).and_return "api-data"
33
+ it 'asks client when cache miss' do
34
+ expect(client).to receive(:get).with(url, options).and_return 'api-data'
20
35
  expect(cache).to receive(:fetch) { |&block| block.call }
21
36
 
22
- expect(subject.get(url, options)).to eq "api-data"
37
+ expect(subject.get(url, options)).to eq 'api-data'
23
38
  end
24
39
  end
25
40
  end
@@ -1,66 +1,76 @@
1
- require "spec_helper"
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
2
4
 
3
5
  describe GoogleDistanceMatrix::Client, :request_recordings do
4
- let(:origin_1) { GoogleDistanceMatrix::Place.new address: "Karl Johans gate, Oslo" }
5
- let(:destination_1) { GoogleDistanceMatrix::Place.new address: "Drammensveien 1, Oslo" }
6
- let(:matrix) { GoogleDistanceMatrix::Matrix.new(origins: [origin_1], destinations: [destination_1]) }
6
+ let(:origin_1) { GoogleDistanceMatrix::Place.new address: 'Karl Johans gate, Oslo' }
7
+ let(:destination_1) { GoogleDistanceMatrix::Place.new address: 'Drammensveien 1, Oslo' }
8
+ let(:matrix) do
9
+ GoogleDistanceMatrix::Matrix.new(origins: [origin_1], destinations: [destination_1])
10
+ end
7
11
 
8
12
  let(:url_builder) { GoogleDistanceMatrix::UrlBuilder.new matrix }
9
- let(:url) { url_builder.url }
13
+ let(:url) { url_builder.sensitive_url }
10
14
 
11
15
  subject { GoogleDistanceMatrix::Client.new }
12
16
 
13
- describe "success" do
17
+ describe 'success' do
14
18
  before { stub_request(:get, url).to_return body: recorded_request_for(:success) }
15
19
 
16
- it "makes the request" do
17
- expect(subject.get(url_builder.url).body).to eq recorded_request_for(:success).read
20
+ it 'makes the request' do
21
+ expect(subject.get(url_builder.sensitive_url).body).to eq recorded_request_for(:success).read
18
22
  end
19
23
  end
20
24
 
21
- describe "client errors" do
22
- describe "server issues 4xx client error" do
23
- it "wraps the error http response" do
24
- stub_request(:get, url).to_return status: [400, "Client error"]
25
- expect { subject.get(url_builder.url) }.to raise_error GoogleDistanceMatrix::ClientError
25
+ describe 'client errors' do
26
+ describe 'server issues 4xx client error' do
27
+ it 'wraps the error http response' do
28
+ stub_request(:get, url).to_return status: [400, 'Client error']
29
+ expect { subject.get(url_builder.sensitive_url) }
30
+ .to raise_error GoogleDistanceMatrix::ClientError
26
31
  end
27
32
 
28
- it "wraps uri too long error" do
29
- stub_request(:get, url).to_return status: [414, "Client error"]
30
- expect { subject.get(url_builder.url) }.to raise_error GoogleDistanceMatrix::MatrixUrlTooLong
33
+ it 'wraps uri too long error' do
34
+ stub_request(:get, url).to_return status: [414, 'Client error']
35
+ expect { subject.get(url_builder.sensitive_url) }
36
+ .to raise_error GoogleDistanceMatrix::MatrixUrlTooLong
31
37
  end
32
38
  end
33
39
 
34
40
  described_class::CLIENT_ERRORS.each do |error|
35
41
  it "wraps '#{error}' client error" do
36
- stub_request(:get, url).to_return body: JSON.generate({status: error})
37
- expect { subject.get(url_builder.url) }.to raise_error GoogleDistanceMatrix::ClientError
42
+ stub_request(:get, url).to_return body: JSON.generate(status: error)
43
+ expect { subject.get(url_builder.sensitive_url) }
44
+ .to raise_error GoogleDistanceMatrix::ClientError
38
45
  end
39
46
  end
40
47
  end
41
48
 
42
- describe "request errors" do
43
- describe "server error" do
44
- before { stub_request(:get, url).to_return status: [500, "Internal Server Error"] }
49
+ describe 'request errors' do
50
+ describe 'server error' do
51
+ before { stub_request(:get, url).to_return status: [500, 'Internal Server Error'] }
45
52
 
46
- it "wraps the error http response" do
47
- expect { subject.get(url_builder.url) }.to raise_error GoogleDistanceMatrix::ServerError
53
+ it 'wraps the error http response' do
54
+ expect { subject.get(url_builder.sensitive_url) }
55
+ .to raise_error GoogleDistanceMatrix::ServerError
48
56
  end
49
57
  end
50
58
 
51
- describe "timeout" do
59
+ describe 'timeout' do
52
60
  before { stub_request(:get, url).to_timeout }
53
61
 
54
- it "wraps the error from Net::HTTP" do
55
- expect { subject.get(url_builder.url).body }.to raise_error GoogleDistanceMatrix::ServerError
62
+ it 'wraps the error from Net::HTTP' do
63
+ expect { subject.get(url_builder.sensitive_url).body }
64
+ .to raise_error GoogleDistanceMatrix::ServerError
56
65
  end
57
66
  end
58
67
 
59
- describe "server error" do
60
- before { stub_request(:get, url).to_return status: [999, "Unknown"] }
68
+ describe 'server error' do
69
+ before { stub_request(:get, url).to_return status: [999, 'Unknown'] }
61
70
 
62
- it "wraps the error http response" do
63
- expect { subject.get(url_builder.url) }.to raise_error GoogleDistanceMatrix::ServerError
71
+ it 'wraps the error http response' do
72
+ expect { subject.get(url_builder.sensitive_url) }
73
+ .to raise_error GoogleDistanceMatrix::ServerError
64
74
  end
65
75
  end
66
76
  end
@@ -1,11 +1,13 @@
1
- require "spec_helper"
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
2
4
 
3
5
  describe GoogleDistanceMatrix::Configuration do
4
6
  include Shoulda::Matchers::ActiveModel
5
7
 
6
8
  subject { described_class.new }
7
9
 
8
- describe "Validations" do
10
+ describe 'Validations' do
9
11
  describe 'departure_time' do
10
12
  it 'is valid with a timestamp' do
11
13
  subject.departure_time = Time.now.to_i
@@ -46,28 +48,32 @@ describe GoogleDistanceMatrix::Configuration do
46
48
  end
47
49
  end
48
50
 
49
- it { should validate_inclusion_of(:mode).in_array(["driving", "walking", "bicycling", "transit"]) }
51
+ it { should validate_inclusion_of(:mode).in_array(%w[driving walking bicycling transit]) }
50
52
  it { should allow_value(nil).for(:mode) }
51
53
 
52
- it { should validate_inclusion_of(:avoid).in_array(["tolls", "highways", "ferries", "indoor"]) }
54
+ it { should validate_inclusion_of(:avoid).in_array(%w[tolls highways ferries indoor]) }
53
55
  it { should allow_value(nil).for(:avoid) }
54
56
 
55
- it { should validate_inclusion_of(:units).in_array(["metric", "imperial"]) }
57
+ it { should validate_inclusion_of(:units).in_array(%w[metric imperial]) }
56
58
  it { should allow_value(nil).for(:units) }
57
59
 
58
-
59
- it { should validate_inclusion_of(:protocol).in_array(["http", "https"]) }
60
-
61
- it { should validate_inclusion_of(:transit_mode).in_array(["bus", "subway", "train", "tram", "rail"])}
62
- it { should validate_inclusion_of(:transit_routing_preference).in_array(["less_walking", "fewer_transfers"])}
63
- it { should validate_inclusion_of(:traffic_model).in_array(["best_guess", "pessimistic", "optimistic"])}
60
+ it { should validate_inclusion_of(:protocol).in_array(%w[http https]) }
61
+
62
+ it { should validate_inclusion_of(:transit_mode).in_array(%w[bus subway train tram rail]) }
63
+ it {
64
+ should validate_inclusion_of(
65
+ :transit_routing_preference
66
+ ).in_array(%w[less_walking fewer_transfers])
67
+ }
68
+ it {
69
+ should validate_inclusion_of(:traffic_model).in_array(%w[best_guess pessimistic optimistic])
70
+ }
64
71
  end
65
72
 
66
-
67
- describe "defaults" do
68
- it { expect(subject.mode).to eq "driving" }
73
+ describe 'defaults' do
74
+ it { expect(subject.mode).to eq 'driving' }
69
75
  it { expect(subject.avoid).to be_nil }
70
- it { expect(subject.units).to eq "metric" }
76
+ it { expect(subject.units).to eq 'metric' }
71
77
  it { expect(subject.lat_lng_scale).to eq 5 }
72
78
  it { expect(subject.use_encoded_polylines).to eq false }
73
79
  it { expect(subject.protocol).to eq 'https' }
@@ -84,13 +90,19 @@ describe GoogleDistanceMatrix::Configuration do
84
90
 
85
91
  it { expect(subject.logger).to be_nil }
86
92
  it { expect(subject.cache).to be_nil }
87
- end
88
93
 
94
+ # rubocop:disable Metrics/LineLength
95
+ it 'has a default expected cache_key_transform' do
96
+ key = subject.cache_key_transform.call('foo')
97
+ expect(key).to eq 'f7fbba6e0636f890e56fbbf3283e524c6fa3204ae298382d624741d0dc6638326e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7'
98
+ end
99
+ # rubocop:enable Metrics/LineLength
100
+ end
89
101
 
90
- describe "#to_param" do
102
+ describe '#to_param' do
91
103
  described_class::ATTRIBUTES.each do |attr|
92
104
  it "includes #{attr}" do
93
- subject[attr] = "foo"
105
+ subject[attr] = 'foo'
94
106
  expect(subject.to_param[attr]).to eq subject.public_send(attr)
95
107
  end
96
108
 
@@ -108,14 +120,14 @@ describe GoogleDistanceMatrix::Configuration do
108
120
  end
109
121
  end
110
122
 
111
- it "includes client if google_business_api_client_id has been set" do
112
- subject.google_business_api_client_id = "123"
113
- expect(subject.to_param['client']).to eq "123"
123
+ it 'includes client if google_business_api_client_id has been set' do
124
+ subject.google_business_api_client_id = '123'
125
+ expect(subject.to_param['client']).to eq '123'
114
126
  end
115
127
 
116
- it "includes key if google_api_key has been set" do
117
- subject.google_api_key = "12345"
118
- expect(subject.to_param['key']).to eq("12345")
128
+ it 'includes key if google_api_key has been set' do
129
+ subject.google_api_key = '12345'
130
+ expect(subject.to_param['key']).to eq('12345')
119
131
  end
120
132
  end
121
133
  end