google_maps_geocoder 0.4.0.pre1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 843c384bc9a07abcd15c8d310bced7b1fc80c979
4
- data.tar.gz: 3336c894ba548664bcfb7f5b2ef91aed785fff21
3
+ metadata.gz: 060caf858407bc718955028bc0edc35a518b2f63
4
+ data.tar.gz: 616a78c20c6ff0926380a413b51094fe8b824bf1
5
5
  SHA512:
6
- metadata.gz: fe1386c06d1bfedea6c5be18de70bd95455cda8778615f918d21bc7991ec197c5aee9bd8525bea23b520b8c00cd734c9a42aad68d5331277623eedb25569928f
7
- data.tar.gz: 105330f683835366620945bc14dd2b2118f9f3bc07a1d97f8445f5660152a919ec565c23196c1bf842b1c89ceb6f53e65f55af8f207780c7bcf7b8cdd1963fbd
6
+ metadata.gz: 6aebec357d9d33fbba4586cc7c09cceebcd3d159ecc7cd648b1548e6f80810838208f486fba1c526b81e73c40d30eb7e9cffed58912a8d1c1462aa6977d961a2
7
+ data.tar.gz: a624fd613c2c84ed5641186c1549135760d545976c4f83e12fce3c05322bdc24e7be9929e3f96020bc19f42608992af2de6d5035e23e070f6e9102bba9705017
data/README.md CHANGED
@@ -1,12 +1,13 @@
1
1
  # GoogleMapsGeocoder
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/google_maps_geocoder.svg)](http://badge.fury.io/rb/google_maps_geocoder)
3
+ [![Build Status](https://secure.travis-ci.org/ivanoblomov/google_maps_geocoder.png)](http://travis-ci.org/ivanoblomov/google_maps_geocoder)
4
4
  [![Code Climate](https://codeclimate.com/github/ivanoblomov/google_maps_geocoder.png)](https://codeclimate.com/github/ivanoblomov/google_maps_geocoder)
5
5
  [![Coverage Status](https://coveralls.io/repos/ivanoblomov/google_maps_geocoder/badge.svg?branch=master&service=github)](https://coveralls.io/github/ivanoblomov/google_maps_geocoder?branch=master)
6
- [![Build Status](https://secure.travis-ci.org/ivanoblomov/google_maps_geocoder.png)](http://travis-ci.org/ivanoblomov/google_maps_geocoder)
7
6
  [![Dependency Status](https://gemnasium.com/ivanoblomov/google_maps_geocoder.png)](https://gemnasium.com/ivanoblomov/google_maps_geocoder)
7
+ [![Inch CI](https://inch-ci.org/github/Ivanoblomov/google_maps_geocoder.svg?branch=master&style=flat)](https://inch-ci.org/github/Ivanoblomov/google_maps_geocoder)
8
+ [![Gem Version](https://badge.fury.io/rb/google_maps_geocoder.svg)](http://badge.fury.io/rb/google_maps_geocoder)
8
9
 
9
- A simple PORO wrapper for geocoding with Google Maps.
10
+ A simple Plain Old Ruby Object wrapper for geocoding with Google Maps.
10
11
 
11
12
  ## Installation
12
13
 
@@ -62,19 +63,19 @@ chez_barack.state_short_name
62
63
 
63
64
  The complete, hopefully self-explanatory, API is:
64
65
 
65
- * city
66
- * country_long_name
67
- * country_short_name
68
- * county
69
- * exact_match?
70
- * formatted_address
71
- * formatted_street_address
72
- * lat
73
- * lng
74
- * partial_match?
75
- * postal_code
76
- * state_long_name
77
- * state_short_name
66
+ * `GoogleMapsGeocoder#city`
67
+ * `GoogleMapsGeocoder#country_long_name`
68
+ * `GoogleMapsGeocoder#country_short_name`
69
+ * `GoogleMapsGeocoder#county`
70
+ * `GoogleMapsGeocoder#exact_match?`
71
+ * `GoogleMapsGeocoder#formatted_address`
72
+ * `GoogleMapsGeocoder#formatted_street_address`
73
+ * `GoogleMapsGeocoder#lat`
74
+ * `GoogleMapsGeocoder#lng`
75
+ * `GoogleMapsGeocoder#partial_match?`
76
+ * `GoogleMapsGeocoder#postal_code`
77
+ * `GoogleMapsGeocoder#state_long_name`
78
+ * `GoogleMapsGeocoder#state_short_name`
78
79
 
79
80
  ## Google Maps API Key (Optional)
80
81
 
@@ -9,6 +9,7 @@ Gem::Specification.new do |s|
9
9
  s.homepage = 'http://github.com/ivanoblomov/google_maps_geocoder'
10
10
  s.authors = ['Roderick Monje']
11
11
 
12
+ s.add_development_dependency 'codeclimate-test-reporter', '>= 0'
12
13
  s.add_development_dependency 'coveralls', '>= 0'
13
14
  s.add_development_dependency 'rake', '>= 0'
14
15
  s.add_development_dependency 'rspec', '>= 0'
@@ -20,6 +21,6 @@ Gem::Specification.new do |s|
20
21
  s.files = `git ls-files`.split "\n"
21
22
  s.test_files = `git ls-files -- {test,spec,features}/*`.split "\n"
22
23
  s.executables = `git ls-files -- bin/*`.split("\n")
23
- .map { |f| File.basename f }
24
+ .map { |f| File.basename f }
24
25
  s.require_paths = ['lib']
25
26
  end
@@ -1,10 +1,43 @@
1
1
  require 'active_support'
2
+ require 'active_support/core_ext/string/inflections'
2
3
  require 'logger'
3
4
  require 'net/http'
4
5
  require 'rack'
5
6
 
6
7
  # A simple PORO wrapper for geocoding with Google Maps.
8
+ #
9
+ # @example
10
+ # chez_barack = GoogleMapsGeocoder.new '1600 Pennsylvania Ave'
11
+ # chez_barack.formatted_address
12
+ # => "1600 Pennsylvania Avenue Northwest, President's Park,
13
+ # Washington, DC 20500, USA"
14
+ # rubocop:disable Metrics/ClassLength
7
15
  class GoogleMapsGeocoder
16
+ # Error handling for google statuses
17
+ class GeocodingError < StandardError
18
+ def initialize(response_json = '')
19
+ @json = response_json
20
+ super
21
+ end
22
+
23
+ def message
24
+ "Google returned:\n#{@json.inspect}"
25
+ end
26
+ end
27
+
28
+ class ZeroResultsError < GeocodingError; end
29
+ class QueryLimitError < GeocodingError; end
30
+ class RequestDeniedError < GeocodingError; end
31
+ class InvalidRequestError < GeocodingError; end
32
+ class UnknownError < GeocodingError; end
33
+
34
+ ERROR_STATUSES = { zero_results: 'ZERO_RESULTS',
35
+ query_limit: 'OVER_QUERY_LIMIT',
36
+ request_denied: 'REQUEST_DENIED',
37
+ invalid_request: 'INVALID_REQUEST',
38
+ unknown: 'UNKNOWN_ERROR'
39
+ }.freeze
40
+
8
41
  GOOGLE_ADDRESS_SEGMENTS = %i(
9
42
  city country_long_name country_short_name county lat lng postal_code
10
43
  state_long_name state_short_name
@@ -18,60 +51,65 @@ class GoogleMapsGeocoder
18
51
  ).freeze
19
52
 
20
53
  # Returns the complete formatted address with standardized abbreviations.
54
+ #
55
+ # @return [String] the complete formatted address
56
+ # @example
57
+ # chez_barack.formatted_address
58
+ # => "1600 Pennsylvania Avenue Northwest, President's Park,
59
+ # Washington, DC 20500, USA"
21
60
  attr_reader :formatted_address
61
+
22
62
  # Returns the formatted street address with standardized abbreviations.
63
+ #
64
+ # @return [String] the formatted street address
65
+ # @example
66
+ # chez_barack.formatted_street_address
67
+ # => "1600 Pennsylvania Avenue"
23
68
  attr_reader :formatted_street_address
24
69
  # Self-explanatory
25
70
  attr_reader(*GOOGLE_ADDRESS_SEGMENTS)
26
71
 
27
- # Instance Methods: Overrides ================================================
28
-
29
- # Geocodes the specified address and wraps the results in a geocoder object.
30
- #
31
- # ==== Attributes
32
- #
33
- # * +data+ - a geocodable address
72
+ # Geocodes the specified address and wraps the results in a GoogleMapsGeocoder
73
+ # object.
34
74
  #
35
- # ==== Examples
36
- #
37
- # white_house = GoogleMapsGeocoder.new('1600 Pennsylvania Washington')
38
- # white_house.formatted_address
39
- # => "1600 Pennsylvania Avenue Northwest, President's Park,
40
- # Washington, DC 20500, USA"
75
+ # @param data [String] a geocodable address
76
+ # @return [GoogleMapsGeocoder] the Google Maps result for the specified
77
+ # address
78
+ # @example
79
+ # chez_barack = GoogleMapsGeocoder.new '1600 Pennsylvania Ave'
41
80
  def initialize(data)
42
81
  @json = data.is_a?(String) ? json_from_url(data) : data
43
- fail "Geocoding \"#{data}\" exceeded query limit! Google returned...\n"\
44
- "#{@json.inspect}" if @json.blank? || @json['status'] != 'OK'
82
+ handle_error if @json.blank? || @json['status'] != 'OK'
45
83
  set_attributes_from_json
46
84
  logger.info('GoogleMapsGeocoder') do
47
85
  "Geocoded \"#{data}\" => \"#{formatted_address}\""
48
86
  end
49
87
  end
50
88
 
51
- # Instance Methods ===========================================================
52
-
53
89
  # Returns true if the address Google returns is an exact match.
54
90
  #
55
- # ==== Examples
56
- #
57
- # white_house = GoogleMapsGeocoder.new('1600 Pennsylvania Ave')
58
- # white_house.exact_match?
91
+ # @return [boolean] whether the Google Maps result is an exact match
92
+ # @example
93
+ # chez_barack.exact_match?
59
94
  # => true
60
95
  def exact_match?
61
- !self.partial_match?
96
+ !partial_match?
62
97
  end
63
98
 
64
99
  # Returns true if the address Google returns isn't an exact match.
65
100
  #
66
- # ==== Examples
67
- #
68
- # white_house = GoogleMapsGeocoder.new('1600 Pennsylvania Washington')
69
- # white_house.exact_match?
70
- # => false
101
+ # @return [boolean] whether the Google Maps result is a partial match
102
+ # @example
103
+ # GoogleMapsGeocoder.new('1600 Pennsylvania Washington').partial_match?
104
+ # => true
71
105
  def partial_match?
72
106
  @json['results'][0]['partial_match'] == true
73
107
  end
74
108
 
109
+ def self.error_class_name(key)
110
+ "google_maps_geocoder/#{key}_error".classify.constantize
111
+ end
112
+
75
113
  private
76
114
 
77
115
  def api_key
@@ -88,11 +126,23 @@ class GoogleMapsGeocoder
88
126
 
89
127
  def json_from_url(url)
90
128
  uri = URI.parse query_url(url)
129
+
91
130
  logger.debug('GoogleMapsGeocoder') { uri }
131
+
92
132
  response = http(uri).request(Net::HTTP::Get.new(uri.request_uri))
93
133
  ActiveSupport::JSON.decode response.body
94
134
  end
95
135
 
136
+ def handle_error
137
+ status = @json['status']
138
+ message = GeocodingError.new(@json).message
139
+
140
+ # for status codes see https://developers.google.com/maps/documentation/geocoding/intro#StatusCodes
141
+ ERROR_STATUSES.each do |key, value|
142
+ raise GoogleMapsGeocoder.error_class_name(key), message if status == value
143
+ end
144
+ end
145
+
96
146
  def logger
97
147
  @logger ||= Logger.new STDERR
98
148
  end
@@ -1,4 +1,4 @@
1
1
  # A simple PORO wrapper for geocoding with Google Maps.
2
2
  class GoogleMapsGeocoder
3
- VERSION = '0.4.0.pre1'.freeze unless defined?(GoogleMapsGeocoder::VERSION)
3
+ VERSION = '0.5.0'.freeze unless defined?(GoogleMapsGeocoder::VERSION)
4
4
  end
@@ -75,10 +75,24 @@ describe GoogleMapsGeocoder do
75
75
  subject { @exact_match }
76
76
 
77
77
  it do
78
- expect(subject.send :query_url, nil).to eq(
78
+ expect(subject.send(:query_url, nil)).to eq(
79
79
  'https://maps.googleapis.com/maps/api/geocode/json?address='\
80
80
  '&sensor=false&key=INVALID_KEY'
81
81
  )
82
82
  end
83
83
  end
84
+
85
+ context 'with google returns empty results' do
86
+ let(:results_hash) { { 'results' => [] } }
87
+
88
+ GoogleMapsGeocoder::ERROR_STATUSES.each do |key, value|
89
+ it "raises #{key} error" do
90
+ allow_any_instance_of(GoogleMapsGeocoder).to receive(:json_from_url)\
91
+ .and_return results_hash.merge('status' => value)
92
+
93
+ expect { GoogleMapsGeocoder.new('anything') }.to \
94
+ raise_error(GoogleMapsGeocoder.error_class_name(key))
95
+ end
96
+ end
97
+ end
84
98
  end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,11 @@
1
+ require 'codeclimate-test-reporter'
2
+ CodeClimate::TestReporter.start
1
3
  require 'coveralls'
2
4
  Coveralls.wear!
5
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
6
+ CodeClimate::TestReporter::Formatter,
7
+ Coveralls::SimpleCov::Formatter
8
+ ]
3
9
  require 'rubygems'
4
10
  require 'bundler'
5
11
  begin
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google_maps_geocoder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0.pre1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roderick Monje
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-28 00:00:00.000000000 Z
11
+ date: 2016-04-25 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: codeclimate-test-reporter
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: coveralls
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -128,12 +142,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
128
142
  version: '0'
129
143
  required_rubygems_version: !ruby/object:Gem::Requirement
130
144
  requirements:
131
- - - ">"
145
+ - - ">="
132
146
  - !ruby/object:Gem::Version
133
- version: 1.3.1
147
+ version: '0'
134
148
  requirements: []
135
149
  rubyforge_project:
136
- rubygems_version: 2.4.6
150
+ rubygems_version: 2.4.5
137
151
  signing_key:
138
152
  specification_version: 4
139
153
  summary: A simple PORO wrapper for geocoding with Google Maps.