google_maps_geocoder 0.5.0 → 0.7.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/CONTRIBUTING.md +22 -0
- data/.github/ISSUE_TEMPLATE.md +17 -0
- data/.github/ISSUE_TEMPLATE/bug-report.md +23 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +16 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +9 -0
- data/.travis.yml +6 -2
- data/LICENSE.txt +2 -2
- data/README.md +30 -29
- data/google_maps_geocoder.gemspec +11 -9
- data/lib/google_maps_geocoder/google_maps_geocoder.rb +69 -76
- data/lib/google_maps_geocoder/version.rb +1 -1
- data/spec/lib/google_maps_geocoder_spec.rb +45 -70
- data/spec/spec_helper.rb +6 -7
- metadata +44 -28
- data/.ruby-version +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f3be1d4509e0cbff1372515f46008eb30b55ece2b38e78cf06fc3000789c28d5
|
4
|
+
data.tar.gz: 02acc59f6810f166810ab1bcb94db7548048a57745ed7a677d0cfda5217169c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e1be25f34ee9fc73c88727cfeee3c451d78cfacac4de57e0abf41ac1c04857abe0da878c1d8435492c6d5e2307fdbc372918123fc382f7543944e044dae0c38a
|
7
|
+
data.tar.gz: 4d3ca27704b9fd41cffd29bf40608793d3bfa166e5d9a215b3feaa95605443f2f128b3e08d948d62c9cc1fd782ac440cb651ba74958754a59b2f049484778443
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# How to contribute
|
2
|
+
|
3
|
+
## **Did you find a bug?**
|
4
|
+
|
5
|
+
1. **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/ivanoblomov/google_maps_geocoder/issues).
|
6
|
+
|
7
|
+
2. If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/ivanoblomov/google_maps_geocoder/issues/new). Be sure to include:
|
8
|
+
1. a **title and clear description**
|
9
|
+
2. as much **relevant information** as possible
|
10
|
+
3. a **code sample** or an **executable test case** demonstrating the expected behavior that is not occurring.
|
11
|
+
|
12
|
+
## **Did you write a patch that fixes a bug or adds a new feature?**
|
13
|
+
|
14
|
+
1. **Add specs** that either reproduces the bug or covers the new feature. In the former's case, *make sure it fails without the fix!*
|
15
|
+
|
16
|
+
2. **Confirm your last build passes** on [Travis CI](https://travis-ci.org/ivanoblomov/google_maps_geocoder/branches).
|
17
|
+
|
18
|
+
3. **Update the inline documentation.** Format it with [YARD](http://www.rubydoc.info/gems/yard/file/docs/GettingStarted.md). For example, see [`GoogleMapsGeocoder.new`](https://github.com/ivanoblomov/google_maps_geocoder/blob/github-templates/lib/google_maps_geocoder/google_maps_geocoder.rb#L43-L50).
|
19
|
+
|
20
|
+
4. [Open a pull request](https://github.com/ivanoblomov/google_maps_geocoder/compare) with the patch or feature. Follow the template's directions.
|
21
|
+
|
22
|
+
## Thanks for contributing!
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Description
|
2
|
+
|
3
|
+
Provide as much background as you need to get the implementer up to speed on the problem to be solved. This can also include screenshots and links to other issues or pull requests.
|
4
|
+
|
5
|
+
# Steps to Reproduce
|
6
|
+
|
7
|
+
Don't forget to point out the difference between what *should* happen and what *does* happen. Here's an example:
|
8
|
+
|
9
|
+
1. Try geocoding "1600 Pennsylvania Ave":
|
10
|
+
```ruby
|
11
|
+
white_house = GoogleMapsGeocoder.new('1600 Pennsylvania Ave')
|
12
|
+
```
|
13
|
+
2. The formatted address doesn't match the White House:
|
14
|
+
```ruby
|
15
|
+
white_house.formatted_address
|
16
|
+
=> "1600 Pennsylvania Ave, Charleston, WV 25302, USA"
|
17
|
+
```
|
@@ -0,0 +1,23 @@
|
|
1
|
+
---
|
2
|
+
name: Bug report
|
3
|
+
about: Create a report to help us improve
|
4
|
+
|
5
|
+
---
|
6
|
+
|
7
|
+
# Description
|
8
|
+
|
9
|
+
Provide as much background as you need to get the implementer up to speed on the problem to be solved. This can also include screenshots and links to other issues or pull requests.
|
10
|
+
|
11
|
+
# Steps to Reproduce
|
12
|
+
|
13
|
+
Don't forget to point out the difference between what *should* happen and what *does* happen. Here's an example:
|
14
|
+
|
15
|
+
1. Try geocoding "1600 Pennsylvania Ave":
|
16
|
+
```ruby
|
17
|
+
white_house = GoogleMapsGeocoder.new('1600 Pennsylvania Ave')
|
18
|
+
```
|
19
|
+
2. The formatted address doesn't match the White House:
|
20
|
+
```ruby
|
21
|
+
white_house.formatted_address
|
22
|
+
=> "1600 Pennsylvania Ave, Charleston, WV 25302, USA"
|
23
|
+
```
|
@@ -0,0 +1,16 @@
|
|
1
|
+
---
|
2
|
+
name: Feature request
|
3
|
+
about: Suggest an idea for this project
|
4
|
+
---
|
5
|
+
|
6
|
+
# Goal
|
7
|
+
Explain this issue's purpose. Focus on the problem that needs to be solved and *not* a particular solution. For example: "Make it easier for users to reset their passwords."
|
8
|
+
|
9
|
+
# Description
|
10
|
+
1. Provide as much background as you need to familiarize the implementer with the problem to be solved.
|
11
|
+
2. Include:
|
12
|
+
* screenshots
|
13
|
+
* links to other issues or pull requests
|
14
|
+
|
15
|
+
# Success Criteria
|
16
|
+
How would a stakeholder test whether the feature was completed successfully?
|
@@ -0,0 +1,9 @@
|
|
1
|
+
Closes: #
|
2
|
+
|
3
|
+
# Goal
|
4
|
+
What problem does this pull request solve? This should be close to the goal of the issue this pull request addresses.
|
5
|
+
|
6
|
+
# Approach
|
7
|
+
1. Describe the approach you chose to solve the above problem.
|
8
|
+
2. This will help code reviewers get oriented quickly.
|
9
|
+
3. It will also document for future maintainers exactly what changed (and why) when this PR was merged.
|
data/.travis.yml
CHANGED
data/LICENSE.txt
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c) 2011 Roderick Monje
|
1
|
+
Copyright (c) 2011-2017 Roderick Monje
|
2
2
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining
|
4
4
|
a copy of this software and associated documentation files (the
|
@@ -17,4 +17,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
17
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
18
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
19
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,32 +1,38 @@
|
|
1
1
|
# GoogleMapsGeocoder
|
2
2
|
|
3
|
-
[![Build Status](https://secure.travis-ci.org/ivanoblomov/google_maps_geocoder.
|
3
|
+
[![Build Status](https://secure.travis-ci.org/ivanoblomov/google_maps_geocoder.svg)](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
|
-
[![Coverage Status](https://coveralls.io/repos/ivanoblomov/google_maps_geocoder/badge.svg?branch=master
|
6
|
-
[![
|
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)
|
5
|
+
[![Coverage Status](https://coveralls.io/repos/github/ivanoblomov/google_maps_geocoder/badge.svg?branch=master)](https://coveralls.io/github/ivanoblomov/google_maps_geocoder?branch=master)
|
6
|
+
[![Inline docs](http://inch-ci.org/github/Ivanoblomov/google_maps_geocoder.svg?branch=master)](http://inch-ci.org/github/Ivanoblomov/google_maps_geocoder)
|
8
7
|
[![Gem Version](https://badge.fury.io/rb/google_maps_geocoder.svg)](http://badge.fury.io/rb/google_maps_geocoder)
|
8
|
+
[![security](https://hakiri.io/github/ivanoblomov/google_maps_geocoder/master.svg)](https://hakiri.io/github/ivanoblomov/google_maps_geocoder/master)
|
9
9
|
|
10
10
|
A simple Plain Old Ruby Object wrapper for geocoding with Google Maps.
|
11
11
|
|
12
12
|
## Installation
|
13
13
|
|
14
|
-
|
14
|
+
1. Set your Google Maps API key, which Google now requires, as an environment variable:
|
15
15
|
|
16
|
-
```
|
17
|
-
|
18
|
-
```
|
16
|
+
```bash
|
17
|
+
export GOOGLE_MAPS_API_KEY=[your key]
|
18
|
+
```
|
19
19
|
|
20
|
-
|
20
|
+
2. Add `GoogleMapsGeocoder` to your Gemfile and run `bundle`:
|
21
21
|
|
22
|
-
```ruby
|
23
|
-
|
24
|
-
```
|
22
|
+
```ruby
|
23
|
+
gem 'google_maps_geocoder'
|
24
|
+
```
|
25
|
+
|
26
|
+
Or try it out in `irb` with:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
require './lib/google_maps_geocoder/google_maps_geocoder'
|
30
|
+
```
|
25
31
|
|
26
32
|
## Ready to Go in One Step
|
27
33
|
|
28
34
|
```ruby
|
29
|
-
chez_barack = GoogleMapsGeocoder.new '1600 Pennsylvania
|
35
|
+
chez_barack = GoogleMapsGeocoder.new '1600 Pennsylvania DC'
|
30
36
|
```
|
31
37
|
|
32
38
|
## Usage
|
@@ -77,24 +83,19 @@ The complete, hopefully self-explanatory, API is:
|
|
77
83
|
* `GoogleMapsGeocoder#state_long_name`
|
78
84
|
* `GoogleMapsGeocoder#state_short_name`
|
79
85
|
|
80
|
-
|
81
|
-
|
82
|
-
To have GoogleMapsGeocoder use your Google Maps API key, set it as an environment variable:
|
83
|
-
|
84
|
-
```bash
|
85
|
-
export GOOGLE_MAPS_API_KEY=[your key]
|
86
|
-
```
|
86
|
+
For compatibility with [Geocoder](https://github.com/alexreisner/geocoder), the following aliases are also available:
|
87
87
|
|
88
|
-
|
88
|
+
* `GoogleMapsGeocoder#address`
|
89
|
+
* `GoogleMapsGeocoder#coordinates`
|
90
|
+
* `GoogleMapsGeocoder#country`
|
91
|
+
* `GoogleMapsGeocoder#country_code`
|
92
|
+
* `GoogleMapsGeocoder#latitude`
|
93
|
+
* `GoogleMapsGeocoder#longitude`
|
94
|
+
* `GoogleMapsGeocoder#state`
|
95
|
+
* `GoogleMapsGeocoder#state_code`
|
89
96
|
|
90
|
-
|
91
|
-
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
92
|
-
* Fork the project
|
93
|
-
* Start a feature/bugfix branch
|
94
|
-
* Commit and push until you are happy with your contribution
|
95
|
-
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
96
|
-
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
97
|
+
## [Contributing to GoogleMapsGeocoder](https://github.com/ivanoblomov/google_maps_geocoder/blob/master/.github/CONTRIBUTING.md)
|
97
98
|
|
98
99
|
## Copyright
|
99
100
|
|
100
|
-
Copyright
|
101
|
+
Copyright © 2011-2020 Roderick Monje. See [LICENSE.txt](https://github.com/ivanoblomov/google_maps_geocoder/blob/master/LICENSE.txt) for further details.
|
@@ -1,22 +1,24 @@
|
|
1
|
-
require File.expand_path
|
1
|
+
require File.expand_path('lib/google_maps_geocoder/version', __dir__)
|
2
2
|
Gem::Specification.new do |s|
|
3
3
|
s.name = 'google_maps_geocoder'
|
4
4
|
s.version = GoogleMapsGeocoder::VERSION.dup
|
5
|
+
s.licenses = ['MIT']
|
5
6
|
s.summary = 'A simple PORO wrapper for geocoding with Google Maps.'
|
6
7
|
s.description = 'Geocode a location without worrying about parsing Google '\
|
7
8
|
"Maps' response. GoogleMapsGeocoder wraps it in a plain-old "\
|
8
9
|
'Ruby object.'
|
9
|
-
s.homepage = '
|
10
|
+
s.homepage = 'https://github.com/ivanoblomov/google_maps_geocoder'
|
10
11
|
s.authors = ['Roderick Monje']
|
12
|
+
s.email = 'rod@foveacentral.com'
|
11
13
|
|
12
|
-
s.add_development_dependency 'codeclimate-test-reporter', '
|
13
|
-
s.add_development_dependency 'coveralls', '
|
14
|
-
s.add_development_dependency 'rake', '>=
|
15
|
-
s.add_development_dependency 'rspec', '
|
16
|
-
s.add_development_dependency 'rubocop', '
|
14
|
+
s.add_development_dependency 'codeclimate-test-reporter', '~> 0'
|
15
|
+
s.add_development_dependency 'coveralls', '~> 0'
|
16
|
+
s.add_development_dependency 'rake', '~> 12.3', '>= 12.3.3'
|
17
|
+
s.add_development_dependency 'rspec', '~> 3'
|
18
|
+
s.add_development_dependency 'rubocop', '~> 0.49.0'
|
17
19
|
|
18
|
-
s.add_runtime_dependency 'activesupport', '>=
|
19
|
-
s.add_runtime_dependency 'rack', '
|
20
|
+
s.add_runtime_dependency 'activesupport', '~> 4.1', '>= 4.1.11'
|
21
|
+
s.add_runtime_dependency 'rack', '~> 2.1.3'
|
20
22
|
|
21
23
|
s.files = `git ls-files`.split "\n"
|
22
24
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split "\n"
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'active_support'
|
2
|
-
require 'active_support/core_ext/string/inflections'
|
3
2
|
require 'logger'
|
4
3
|
require 'net/http'
|
5
4
|
require 'rack'
|
@@ -7,47 +6,19 @@ require 'rack'
|
|
7
6
|
# A simple PORO wrapper for geocoding with Google Maps.
|
8
7
|
#
|
9
8
|
# @example
|
10
|
-
# chez_barack = GoogleMapsGeocoder.new '1600 Pennsylvania
|
9
|
+
# chez_barack = GoogleMapsGeocoder.new '1600 Pennsylvania DC'
|
11
10
|
# chez_barack.formatted_address
|
12
11
|
# => "1600 Pennsylvania Avenue Northwest, President's Park,
|
13
12
|
# Washington, DC 20500, USA"
|
14
|
-
# rubocop:disable Metrics/ClassLength
|
15
13
|
class GoogleMapsGeocoder
|
16
|
-
|
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
|
-
|
41
|
-
GOOGLE_ADDRESS_SEGMENTS = %i(
|
14
|
+
GOOGLE_ADDRESS_SEGMENTS = %i[
|
42
15
|
city country_long_name country_short_name county lat lng postal_code
|
43
16
|
state_long_name state_short_name
|
44
|
-
|
45
|
-
|
17
|
+
].freeze
|
18
|
+
GOOGLE_MAPS_API = 'https://maps.googleapis.com/maps/api/geocode/json'.freeze
|
46
19
|
|
47
20
|
ALL_ADDRESS_SEGMENTS = (
|
48
|
-
GOOGLE_ADDRESS_SEGMENTS + %i
|
49
|
-
formatted_address formatted_street_address
|
50
|
-
)
|
21
|
+
GOOGLE_ADDRESS_SEGMENTS + %i[formatted_address formatted_street_address]
|
51
22
|
).freeze
|
52
23
|
|
53
24
|
# Returns the complete formatted address with standardized abbreviations.
|
@@ -64,28 +35,51 @@ class GoogleMapsGeocoder
|
|
64
35
|
# @return [String] the formatted street address
|
65
36
|
# @example
|
66
37
|
# chez_barack.formatted_street_address
|
67
|
-
# => "1600 Pennsylvania Avenue"
|
38
|
+
# => "1600 Pennsylvania Avenue Northwest"
|
68
39
|
attr_reader :formatted_street_address
|
69
40
|
# Self-explanatory
|
70
41
|
attr_reader(*GOOGLE_ADDRESS_SEGMENTS)
|
71
42
|
|
43
|
+
# Returns the formatted address as a comma-delimited string.
|
44
|
+
alias address formatted_address
|
45
|
+
# Returns the address' country as a full string.
|
46
|
+
alias country country_long_name
|
47
|
+
# Returns the address' country as an abbreviated string.
|
48
|
+
alias country_code country_short_name
|
49
|
+
# Returns the address' latitude as a float.
|
50
|
+
alias latitude lat
|
51
|
+
# Returns the address' longitude as a float.
|
52
|
+
alias longitude lng
|
53
|
+
# Returns the address' state as a full string.
|
54
|
+
alias state state_long_name
|
55
|
+
# Returns the address' state as an abbreviated string.
|
56
|
+
alias state_code state_short_name
|
57
|
+
|
72
58
|
# Geocodes the specified address and wraps the results in a GoogleMapsGeocoder
|
73
59
|
# object.
|
74
60
|
#
|
75
|
-
# @param
|
61
|
+
# @param address [String] a geocodable address
|
76
62
|
# @return [GoogleMapsGeocoder] the Google Maps result for the specified
|
77
63
|
# address
|
78
64
|
# @example
|
79
|
-
# chez_barack = GoogleMapsGeocoder.new '1600 Pennsylvania
|
80
|
-
def initialize(
|
81
|
-
@json =
|
82
|
-
|
65
|
+
# chez_barack = GoogleMapsGeocoder.new '1600 Pennsylvania DC'
|
66
|
+
def initialize(address)
|
67
|
+
@json = address.is_a?(String) ? google_maps_response(address) : address
|
68
|
+
status = @json && @json['status']
|
69
|
+
raise RuntimeError if status == 'OVER_QUERY_LIMIT'
|
70
|
+
raise GeocodingError, @json if @json.blank? || status != 'OK'
|
71
|
+
|
83
72
|
set_attributes_from_json
|
84
|
-
|
85
|
-
"Geocoded \"#{
|
73
|
+
Logger.new(STDERR).info('GoogleMapsGeocoder') do
|
74
|
+
"Geocoded \"#{address}\" => \"#{formatted_address}\""
|
86
75
|
end
|
87
76
|
end
|
88
77
|
|
78
|
+
# Returns the address' coordinates as an array of floats.
|
79
|
+
def coordinates
|
80
|
+
[lat, lng]
|
81
|
+
end
|
82
|
+
|
89
83
|
# Returns true if the address Google returns is an exact match.
|
90
84
|
#
|
91
85
|
# @return [boolean] whether the Google Maps result is an exact match
|
@@ -100,21 +94,48 @@ class GoogleMapsGeocoder
|
|
100
94
|
#
|
101
95
|
# @return [boolean] whether the Google Maps result is a partial match
|
102
96
|
# @example
|
103
|
-
# GoogleMapsGeocoder.new('1600 Pennsylvania
|
97
|
+
# GoogleMapsGeocoder.new('1600 Pennsylvania DC').partial_match?
|
104
98
|
# => true
|
105
99
|
def partial_match?
|
106
100
|
@json['results'][0]['partial_match'] == true
|
107
101
|
end
|
108
102
|
|
109
|
-
|
110
|
-
|
103
|
+
# A geocoding error returned by Google Maps.
|
104
|
+
class GeocodingError < StandardError
|
105
|
+
# Returns the complete JSON response from Google Maps as a Hash.
|
106
|
+
#
|
107
|
+
# @return [Hash] Google Maps' JSON response
|
108
|
+
# @example
|
109
|
+
# {
|
110
|
+
# "results" => [],
|
111
|
+
# "status" => "ZERO_RESULTS"
|
112
|
+
# }
|
113
|
+
attr_reader :json
|
114
|
+
|
115
|
+
# Initialize a GeocodingError wrapping the JSON returned by Google Maps.
|
116
|
+
#
|
117
|
+
# @param json [Hash] Google Maps' JSON response
|
118
|
+
# @return [GeocodingError] the geocoding error
|
119
|
+
def initialize(json = {})
|
120
|
+
@json = json
|
121
|
+
if (message = @json['error_message'])
|
122
|
+
Logger.new(STDERR).error(message)
|
123
|
+
end
|
124
|
+
super @json['status']
|
125
|
+
end
|
111
126
|
end
|
112
127
|
|
113
128
|
private
|
114
129
|
|
115
|
-
def
|
116
|
-
|
117
|
-
|
130
|
+
def google_maps_request(address)
|
131
|
+
"#{GOOGLE_MAPS_API}?address=#{Rack::Utils.escape address}"\
|
132
|
+
"&key=#{ENV['GOOGLE_MAPS_API_KEY']}"
|
133
|
+
end
|
134
|
+
|
135
|
+
def google_maps_response(address)
|
136
|
+
uri = URI.parse google_maps_request(address)
|
137
|
+
response = http(uri).request(Net::HTTP::Get.new(uri.request_uri))
|
138
|
+
ActiveSupport::JSON.decode response.body
|
118
139
|
end
|
119
140
|
|
120
141
|
def http(uri)
|
@@ -124,29 +145,6 @@ class GoogleMapsGeocoder
|
|
124
145
|
http
|
125
146
|
end
|
126
147
|
|
127
|
-
def json_from_url(url)
|
128
|
-
uri = URI.parse query_url(url)
|
129
|
-
|
130
|
-
logger.debug('GoogleMapsGeocoder') { uri }
|
131
|
-
|
132
|
-
response = http(uri).request(Net::HTTP::Get.new(uri.request_uri))
|
133
|
-
ActiveSupport::JSON.decode response.body
|
134
|
-
end
|
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
|
-
|
146
|
-
def logger
|
147
|
-
@logger ||= Logger.new STDERR
|
148
|
-
end
|
149
|
-
|
150
148
|
def parse_address_component_type(type, name = 'long_name')
|
151
149
|
address_component = @json['results'][0]['address_components'].detect do |ac|
|
152
150
|
ac['types'] && ac['types'].include?(type)
|
@@ -200,11 +198,6 @@ class GoogleMapsGeocoder
|
|
200
198
|
parse_address_component_type('administrative_area_level_1', 'short_name')
|
201
199
|
end
|
202
200
|
|
203
|
-
def query_url(query)
|
204
|
-
"#{GOOGLE_API_URI}?address=#{Rack::Utils.escape query}&sensor=false"\
|
205
|
-
"#{api_key}"
|
206
|
-
end
|
207
|
-
|
208
201
|
def set_attributes_from_json
|
209
202
|
ALL_ADDRESS_SEGMENTS.each do |segment|
|
210
203
|
instance_variable_set :"@#{segment}", send("parse_#{segment}")
|
@@ -1,10 +1,9 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
-
|
2
|
+
# rubocop:disable Metrics/BlockLength
|
3
3
|
describe GoogleMapsGeocoder do
|
4
4
|
before(:all) do
|
5
5
|
begin
|
6
|
-
@exact_match
|
7
|
-
@partial_match = GoogleMapsGeocoder.new('1600 Pennsylvania Washington')
|
6
|
+
@exact_match = GoogleMapsGeocoder.new('White House')
|
8
7
|
rescue SocketError
|
9
8
|
@no_network = true
|
10
9
|
rescue RuntimeError
|
@@ -17,82 +16,58 @@ describe GoogleMapsGeocoder do
|
|
17
16
|
pending 'waiting for query limit to pass' if @query_limit
|
18
17
|
end
|
19
18
|
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
describe '#new' do
|
20
|
+
context 'with "White House"' do
|
21
|
+
subject { @exact_match }
|
23
22
|
|
24
|
-
|
25
|
-
it { expect(subject.formatted_street_address).to eq '837 Union Street' }
|
26
|
-
it { expect(subject.city).to eq 'Brooklyn' }
|
27
|
-
it { expect(subject.county).to match(/Kings/) }
|
28
|
-
it { expect(subject.state_long_name).to eq 'New York' }
|
29
|
-
it { expect(subject.state_short_name).to eq 'NY' }
|
30
|
-
it { expect(subject.postal_code).to match(/112[0-9]{2}/) }
|
31
|
-
it { expect(subject.country_short_name).to eq 'US' }
|
32
|
-
it { expect(subject.country_long_name).to eq 'United States' }
|
33
|
-
it do
|
34
|
-
expect(subject.formatted_address)
|
35
|
-
.to match(/837 Union St, Brooklyn, NY 112[0-9]{2}, USA/)
|
36
|
-
end
|
37
|
-
end
|
23
|
+
it { should be_exact_match }
|
38
24
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
25
|
+
context 'address' do
|
26
|
+
it do
|
27
|
+
expect(subject.formatted_street_address)
|
28
|
+
.to eq '1600 Pennsylvania Avenue Northwest'
|
29
|
+
end
|
30
|
+
it { expect(subject.city).to eq 'Washington' }
|
31
|
+
it { expect(subject.state_long_name).to eq 'District of Columbia' }
|
32
|
+
it { expect(subject.state_short_name).to eq 'DC' }
|
33
|
+
it { expect(subject.postal_code).to eq '20500' }
|
34
|
+
it { expect(subject.country_short_name).to eq 'US' }
|
35
|
+
it { expect(subject.country_long_name).to eq 'United States' }
|
36
|
+
it do
|
37
|
+
expect(subject.formatted_address)
|
38
|
+
.to match(/1600 Pennsylvania Ave NW, Washington, DC 20500, USA/)
|
39
|
+
end
|
53
40
|
end
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
expect(subject.
|
62
|
-
|
41
|
+
context 'coordinates' do
|
42
|
+
it { expect(subject.lat).to be_within(0.005).of(38.8976633) }
|
43
|
+
it { expect(subject.lng).to be_within(0.005).of(-77.0365739) }
|
44
|
+
end
|
45
|
+
context 'Geocoder API' do
|
46
|
+
it { expect(subject.address).to eq subject.formatted_address }
|
47
|
+
it { expect(subject.coordinates).to eq [subject.lat, subject.lng] }
|
48
|
+
it { expect(subject.country).to eq subject.country_long_name }
|
49
|
+
it { expect(subject.country_code).to eq subject.country_short_name }
|
50
|
+
it { expect(subject.latitude).to eq subject.lat }
|
51
|
+
it { expect(subject.longitude).to eq subject.lng }
|
52
|
+
it { expect(subject.state).to eq subject.state_long_name }
|
53
|
+
it { expect(subject.state_code).to eq subject.state_short_name }
|
63
54
|
end
|
64
55
|
end
|
56
|
+
context 'when API key is invalid' do
|
57
|
+
before do
|
58
|
+
@key = ENV['GOOGLE_MAPS_API_KEY']
|
59
|
+
ENV['GOOGLE_MAPS_API_KEY'] = 'invalid_key'
|
60
|
+
end
|
65
61
|
|
66
|
-
|
67
|
-
it { expect(subject.lat).to be_within(0.005).of(38.8791981) }
|
68
|
-
it { expect(subject.lng).to be_within(0.005).of(-76.9818437) }
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
context "when ENV['GOOGLE_MAPS_API_KEY'] = 'INVALID_KEY'" do
|
73
|
-
before { ENV['GOOGLE_MAPS_API_KEY'] = 'INVALID_KEY' }
|
74
|
-
|
75
|
-
subject { @exact_match }
|
76
|
-
|
77
|
-
it do
|
78
|
-
expect(subject.send(:query_url, nil)).to eq(
|
79
|
-
'https://maps.googleapis.com/maps/api/geocode/json?address='\
|
80
|
-
'&sensor=false&key=INVALID_KEY'
|
81
|
-
)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
context 'with google returns empty results' do
|
86
|
-
let(:results_hash) { { 'results' => [] } }
|
62
|
+
after { ENV['GOOGLE_MAPS_API_KEY'] = @key }
|
87
63
|
|
88
|
-
|
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)
|
64
|
+
subject { GoogleMapsGeocoder.new('nowhere that comes to mind') }
|
92
65
|
|
93
|
-
|
94
|
-
|
66
|
+
it do
|
67
|
+
expect { subject }.to raise_error GoogleMapsGeocoder::GeocodingError,
|
68
|
+
'REQUEST_DENIED'
|
95
69
|
end
|
96
70
|
end
|
97
71
|
end
|
98
72
|
end
|
73
|
+
# rubocop:enable Metrics/BlockLength
|
data/spec/spec_helper.rb
CHANGED
@@ -1,18 +1,17 @@
|
|
1
|
-
require '
|
2
|
-
|
1
|
+
require 'simplecov'
|
2
|
+
SimpleCov.start
|
3
3
|
require 'coveralls'
|
4
4
|
Coveralls.wear!
|
5
|
-
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter
|
6
|
-
CodeClimate::TestReporter::Formatter,
|
5
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
|
7
6
|
Coveralls::SimpleCov::Formatter
|
8
|
-
|
7
|
+
)
|
9
8
|
require 'rubygems'
|
10
9
|
require 'bundler'
|
11
10
|
begin
|
12
11
|
Bundler.setup(:default, :development)
|
13
12
|
rescue Bundler::BundlerError => e
|
14
|
-
|
15
|
-
|
13
|
+
warn e.message
|
14
|
+
warn 'Run `bundle install` to install missing gems'
|
16
15
|
exit e.status_code
|
17
16
|
end
|
18
17
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
metadata
CHANGED
@@ -1,123 +1,139 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: google_maps_geocoder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roderick Monje
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-05-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: codeclimate-test-reporter
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: coveralls
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '12.3'
|
45
48
|
- - ">="
|
46
49
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
50
|
+
version: 12.3.3
|
48
51
|
type: :development
|
49
52
|
prerelease: false
|
50
53
|
version_requirements: !ruby/object:Gem::Requirement
|
51
54
|
requirements:
|
55
|
+
- - "~>"
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '12.3'
|
52
58
|
- - ">="
|
53
59
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
60
|
+
version: 12.3.3
|
55
61
|
- !ruby/object:Gem::Dependency
|
56
62
|
name: rspec
|
57
63
|
requirement: !ruby/object:Gem::Requirement
|
58
64
|
requirements:
|
59
|
-
- - "
|
65
|
+
- - "~>"
|
60
66
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
67
|
+
version: '3'
|
62
68
|
type: :development
|
63
69
|
prerelease: false
|
64
70
|
version_requirements: !ruby/object:Gem::Requirement
|
65
71
|
requirements:
|
66
|
-
- - "
|
72
|
+
- - "~>"
|
67
73
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
74
|
+
version: '3'
|
69
75
|
- !ruby/object:Gem::Dependency
|
70
76
|
name: rubocop
|
71
77
|
requirement: !ruby/object:Gem::Requirement
|
72
78
|
requirements:
|
73
|
-
- - "
|
79
|
+
- - "~>"
|
74
80
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
81
|
+
version: 0.49.0
|
76
82
|
type: :development
|
77
83
|
prerelease: false
|
78
84
|
version_requirements: !ruby/object:Gem::Requirement
|
79
85
|
requirements:
|
80
|
-
- - "
|
86
|
+
- - "~>"
|
81
87
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
88
|
+
version: 0.49.0
|
83
89
|
- !ruby/object:Gem::Dependency
|
84
90
|
name: activesupport
|
85
91
|
requirement: !ruby/object:Gem::Requirement
|
86
92
|
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '4.1'
|
87
96
|
- - ">="
|
88
97
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
98
|
+
version: 4.1.11
|
90
99
|
type: :runtime
|
91
100
|
prerelease: false
|
92
101
|
version_requirements: !ruby/object:Gem::Requirement
|
93
102
|
requirements:
|
103
|
+
- - "~>"
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '4.1'
|
94
106
|
- - ">="
|
95
107
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
108
|
+
version: 4.1.11
|
97
109
|
- !ruby/object:Gem::Dependency
|
98
110
|
name: rack
|
99
111
|
requirement: !ruby/object:Gem::Requirement
|
100
112
|
requirements:
|
101
|
-
- - "
|
113
|
+
- - "~>"
|
102
114
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
115
|
+
version: 2.1.3
|
104
116
|
type: :runtime
|
105
117
|
prerelease: false
|
106
118
|
version_requirements: !ruby/object:Gem::Requirement
|
107
119
|
requirements:
|
108
|
-
- - "
|
120
|
+
- - "~>"
|
109
121
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
122
|
+
version: 2.1.3
|
111
123
|
description: Geocode a location without worrying about parsing Google Maps' response.
|
112
124
|
GoogleMapsGeocoder wraps it in a plain-old Ruby object.
|
113
|
-
email:
|
125
|
+
email: rod@foveacentral.com
|
114
126
|
executables: []
|
115
127
|
extensions: []
|
116
128
|
extra_rdoc_files: []
|
117
129
|
files:
|
118
130
|
- ".document"
|
131
|
+
- ".github/CONTRIBUTING.md"
|
132
|
+
- ".github/ISSUE_TEMPLATE.md"
|
133
|
+
- ".github/ISSUE_TEMPLATE/bug-report.md"
|
134
|
+
- ".github/ISSUE_TEMPLATE/feature_request.md"
|
135
|
+
- ".github/PULL_REQUEST_TEMPLATE.md"
|
119
136
|
- ".gitignore"
|
120
|
-
- ".ruby-version"
|
121
137
|
- ".travis.yml"
|
122
138
|
- Gemfile
|
123
139
|
- LICENSE.txt
|
@@ -128,8 +144,9 @@ files:
|
|
128
144
|
- lib/google_maps_geocoder/version.rb
|
129
145
|
- spec/lib/google_maps_geocoder_spec.rb
|
130
146
|
- spec/spec_helper.rb
|
131
|
-
homepage:
|
132
|
-
licenses:
|
147
|
+
homepage: https://github.com/ivanoblomov/google_maps_geocoder
|
148
|
+
licenses:
|
149
|
+
- MIT
|
133
150
|
metadata: {}
|
134
151
|
post_install_message:
|
135
152
|
rdoc_options: []
|
@@ -146,8 +163,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
146
163
|
- !ruby/object:Gem::Version
|
147
164
|
version: '0'
|
148
165
|
requirements: []
|
149
|
-
|
150
|
-
rubygems_version: 2.4.5
|
166
|
+
rubygems_version: 3.1.2
|
151
167
|
signing_key:
|
152
168
|
specification_version: 4
|
153
169
|
summary: A simple PORO wrapper for geocoding with Google Maps.
|
data/.ruby-version
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
2.2.2
|