Skip to content

Commit

Permalink
Merge branch 'release/v0.4.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
edwardsamuel committed Sep 23, 2015
2 parents 5bde9b1 + 569cf23 commit 3f354c2
Show file tree
Hide file tree
Showing 11 changed files with 140 additions and 48 deletions.
5 changes: 4 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
language: ruby
rvm:
- ruby-head
- 2.2
- 2.1
- 2.0.0
- 2.0.0
- jruby-head
- jruby-9000
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## 0.4.1

* Support JRuby 9.0.0.0
* Refactoring and more test coverage

## 0.4.0

* Use required positional and optional named parameters (_breaking changes_)
Expand Down
20 changes: 20 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,23 @@ source 'https://rubygems.org'

# Specify your gem's dependencies in google_maps_service.gemspec
gemspec

group :development do
gem 'bundler', '~> 1.6'
gem 'rake', '~> 10.0'
gem 'rspec', '~> 3.3'
gem 'simplecov', '~> 0.10'
gem 'coveralls', '~> 0.8.2'
gem 'webmock', '~> 1.21'
end

platforms :ruby do
group :development do
gem 'yard', '~> 0.8'
gem 'redcarpet', '~> 3.2'
end
end

if ENV['RAILS_VERSION']
gem 'rails', ENV['RAILS_VERSION']
end
13 changes: 8 additions & 5 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
require "bundler/gem_tasks"
require "rspec/core/rake_task"
require "yard"
require 'bundler/gem_tasks'
require 'rspec/core/rake_task'

RSpec::Core::RakeTask.new

task :default => :spec
task :test => :spec

YARD::Rake::YardocTask.new do |t|
t.files = ['lib/**/*.rb']
unless defined?(JRUBY_VERSION)
require 'yard'

YARD::Rake::YardocTask.new do |t|
t.files = ['lib/**/*.rb']
end
end
10 changes: 1 addition & 9 deletions google_maps_service.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,5 @@ Gem::Specification.new do |spec|

spec.add_runtime_dependency 'multi_json', '~> 1.11'
spec.add_runtime_dependency 'hurley', '~> 0.1'
spec.add_runtime_dependency 'retriable', '~> 2.0', '>= 2.0.2'
spec.add_development_dependency 'bundler', '~> 1.7'
spec.add_development_dependency 'rake', '~> 10.0'
spec.add_development_dependency 'yard', '~> 0.8.7.6'
spec.add_development_dependency 'redcarpet', '~> 3.3'
spec.add_development_dependency 'rspec', '~> 3.3'
spec.add_development_dependency 'simplecov', '~> 0.10.0'
spec.add_development_dependency 'coveralls', '~> 0.8.2'
spec.add_development_dependency 'webmock', '~> 1.21', '>= 1.21.0'
spec.add_runtime_dependency 'retriable', '~> 2.0'
end
2 changes: 2 additions & 0 deletions lib/google_maps_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class << self
# @return [Object]
attr_accessor :connection

# Configure global parameters.
# @yield [config]
def configure
yield self
true
Expand Down
2 changes: 1 addition & 1 deletion lib/google_maps_service/apis/roads.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def extract_roads_body(response)

# Check response body for error status.
#
# @param [Hurley::Response] body Response object.
# @param [Hurley::Response] response Response object.
# @param [Hash] body Response body.
def check_roads_body_error(response, body)
error = body[:error]
Expand Down
71 changes: 40 additions & 31 deletions lib/google_maps_service/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,6 @@ class Client
# connection: Hurley::HttpCache.new(HurleyExcon::Connection.new)
# )
#
#
#
# @option options [String] :key Secret key for accessing Google Maps Web Service.
# Can be obtained at https://developers.google.com/maps/documentation/geocoding/get-api-key#key.
# @option options [String] :client_id Client id for using Maps API for Work services.
Expand All @@ -111,17 +109,13 @@ class Client
# By default, the default Hurley's HTTP client connection (Net::Http) will be used.
# See https://github.com/lostisland/hurley/blob/master/README.md#connections.
def initialize(**options)
@key = options[:key] || GoogleMapsService.key
@client_id = options[:client_id] || GoogleMapsService.client_id
@client_secret = options[:client_secret] || GoogleMapsService.client_secret
@retry_timeout = options[:retry_timeout] || GoogleMapsService.retry_timeout || 60
@queries_per_second = options[:queries_per_second] || GoogleMapsService.queries_per_second
@request_options = options[:request_options] || GoogleMapsService.request_options
@ssl_options = options[:ssl_options] || GoogleMapsService.ssl_options
@connection = options[:connection] || GoogleMapsService.connection

#
initialize_qps if @queries_per_second
[:key, :client_id, :client_secret,
:retry_timeout, :queries_per_second,
:request_options, :ssl_options, :connection].each do |key|
self.instance_variable_set("@#{key}".to_sym, options[key] || GoogleMapsService.instance_variable_get("@#{key}"))
end

initialize_query_tickets
end

# Get the current HTTP client.
Expand All @@ -133,24 +127,27 @@ def client
protected

# Initialize QPS queue. QPS queue is a "tickets" for calling API
def initialize_qps
@qps_queue = SizedQueue.new @queries_per_second
@queries_per_second.times do
@qps_queue << 0
def initialize_query_tickets
if @queries_per_second
@qps_queue = SizedQueue.new @queries_per_second
@queries_per_second.times do
@qps_queue << 0
end
end
end

# Create a new HTTP client.
# @return [Hurley::Client]
def new_client
client = Hurley::Client.new
client.request_options.query_class = Hurley::Query::Flat
client.request_options.redirection_limit = 0
client.header[:user_agent] = user_agent

client.connection = @connection if @connection
@request_options.each_pair {|key, value| client.request_options[key] = value } if @request_options
@ssl_options.each_pair {|key, value| client.ssl_options[key] = value } if @ssl_options

client.request_options.query_class = Hurley::Query::Flat
client.header[:user_agent] = user_agent
client
end

Expand All @@ -175,30 +172,42 @@ def get(path, params, base_url: DEFAULT_BASE_URL, accepts_client_id: true, custo
url = base_url + generate_auth_url(path, params, accepts_client_id)

Retriable.retriable timeout: @retry_timeout, on: RETRIABLE_ERRORS do |try|
# Get/wait the request "ticket" if QPS is configured
# Check for previous request time, it must be more than a second ago before calling new request
if @qps_queue
elapsed_since_earliest = Time.now - @qps_queue.pop
sleep(1 - elapsed_since_earliest) if elapsed_since_earliest.to_f < 1
end

begin
request_query_ticket
response = client.get url
ensure
# Release request "ticket"
@qps_queue << Time.now if @qps_queue
release_query_ticket
end

return custom_response_decoder.call(response) if custom_response_decoder
decode_response_body(response)
end
end

# Get/wait the request "ticket" if QPS is configured.
# Check for previous request time, it must be more than a second ago before calling new request.
#
# @return [void]
def request_query_ticket
if @qps_queue
elapsed_since_earliest = Time.now - @qps_queue.pop
sleep(1 - elapsed_since_earliest) if elapsed_since_earliest.to_f < 1
end
end

# Release request "ticket".
#
# @return [void]
def release_query_ticket
@qps_queue << Time.now if @qps_queue
end

# Returns the path and query string portion of the request URL,
# first adding any necessary parameters.
#
# @param [String] path The path portion of the URL.
# @param [Hash] params URL parameters.
# @param [Boolean] accepts_client_id Sign the request using API {#keys} instead of {#client_id}.
#
# @return [String]
def generate_auth_url(path, params, accepts_client_id)
Expand Down Expand Up @@ -253,15 +262,15 @@ def check_response_status_code(response)
raise GoogleMapsService::Error::ClientError.new(response), 'Invalid request'
when 500..600
raise GoogleMapsService::Error::ServerError.new(response), 'Server error'
else
raise ArgumentError, 'Invalid response status code'
end
end

# Check response body for error status.
#
# @param [Hurley::Response] body Response object.
# @param [Hurley::Response] response Response object.
# @param [Hash] body Response body.
#
# @return [void]
def check_body_error(response, body)
case body[:status]
when 'OK', 'ZERO_RESULTS'
Expand Down
3 changes: 3 additions & 0 deletions lib/google_maps_service/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ class BaseError < StandardError
# @return [Hurley::Response]
attr_reader :response

# Initialize error
#
# @param [Hurley::Response] response HTTP response.
def initialize(response = nil)
@response = response
end
Expand Down
2 changes: 1 addition & 1 deletion lib/google_maps_service/version.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module GoogleMapsService
# GoogleMapsService gem version
VERSION = '0.4.0'
VERSION = '0.4.1'

# Current operating system
# @private
Expand Down
55 changes: 55 additions & 0 deletions spec/google_maps_service/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,17 @@
end
end

context 'with unknown api error' do
before(:example) do
stub_request(:get, /https:\/\/maps.googleapis.com\/maps\/api\/geocode\/.*/)
.to_return(:status => 200, headers: { 'Content-Type' => 'application/json' }, body: '{"status":"UNKNOWN_ERROR"}')
end

it 'should raise GoogleMapsService::Error::ApiError' do
expect { client.geocode('Sydney') }.to raise_error GoogleMapsService::Error::ApiError
end
end

context 'with server error and then success' do
before(:example) do
stub_request(:get, /https:\/\/maps.googleapis.com\/maps\/api\/geocode\/.*/)
Expand All @@ -120,6 +131,50 @@
end
end

context 'with server error' do
before(:example) do
stub_request(:get, /https:\/\/maps.googleapis.com\/maps\/api\/geocode\/.*/)
.to_return(:status => 500, body: 'Internal server error.')
end

it 'should raise GoogleMapsService::Error::ServerError' do
expect { client.geocode('Sydney') }.to raise_error GoogleMapsService::Error::ServerError
end
end

context 'with unauthorized status code error' do
before(:example) do
stub_request(:get, /https:\/\/maps.googleapis.com\/maps\/api\/geocode\/.*/)
.to_return(:status => 401, body: 'Unauthorized.')
end

it 'should raise GoogleMapsService::Error::ClientError' do
expect { client.geocode('Sydney') }.to raise_error GoogleMapsService::Error::ClientError
end
end

context 'with client error' do
before(:example) do
stub_request(:get, /https:\/\/maps.googleapis.com\/maps\/api\/geocode\/.*/)
.to_return(:status => 400, body: 'Bad request.')
end

it 'should raise GoogleMapsService::Error::ClientError' do
expect { client.geocode('Sydney') }.to raise_error GoogleMapsService::Error::ClientError
end
end

context 'with redirect error' do
before(:example) do
stub_request(:get, /https:\/\/maps.googleapis.com\/maps\/api\/geocode\/.*/)
.to_return(:status => 301, headers: { 'location' => 'https://maps2.googleapis.com' } )
end

it 'should raise GoogleMapsService::Error::RedirectError' do
expect { client.geocode('Sydney') }.to raise_error GoogleMapsService::Error::RedirectError
end
end

context 'with connection failed' do
before(:example) do
stub_request(:get, /https:\/\/maps.googleapis.com\/maps\/api\/geocode\/.*/)
Expand Down

0 comments on commit 3f354c2

Please sign in to comment.