geocoder 1.2.12 → 1.2.13
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of geocoder might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +34 -5
- data/lib/geocoder/configuration.rb +0 -1
- data/lib/geocoder/lookup.rb +1 -0
- data/lib/geocoder/lookups/geoip2.rb +10 -6
- data/lib/geocoder/lookups/mapbox.rb +53 -0
- data/lib/geocoder/lookups/telize.rb +10 -3
- data/lib/geocoder/results/esri.rb +9 -2
- data/lib/geocoder/results/geoip2.rb +12 -8
- data/lib/geocoder/results/mapbox.rb +55 -0
- data/lib/geocoder/stores/active_record.rb +5 -0
- data/lib/geocoder/version.rb +1 -1
- data/lib/tasks/geocoder.rake +12 -3
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2184f181fb0c642d0cc02774bcd2208e325b8dc8
|
4
|
+
data.tar.gz: 7b0da04b5c05f0b9afe9182e00ee6099a83adc45
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd8d36a0c7fb2cabda97f03baa19c68d4106bca4e5c8eb1e987ac0156393fa1c05f67d235020ca332cd3557c77411cbfd8d601add3b8820dcfffd0359a30a19a
|
7
|
+
data.tar.gz: 05a0eb39a8f575083f3ff20fbe93c209afcb533313c531bee25462b1e6f25bed6da7f2d47ffcb296923d933786249309d8f07e66cb23d0e271da9cf7962c53c8
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,18 @@ Changelog
|
|
3
3
|
|
4
4
|
Major changes to Geocoder for each release. Please see the Git log for complete list of changes.
|
5
5
|
|
6
|
+
1.2.13 (2015 Dec 15)
|
7
|
+
--------------------
|
8
|
+
* Update :telize IP lookup to reflect new URL (thanks github.com/jfredrickson).
|
9
|
+
* Add reverse geocode rake task (thanks github.com/FanaHOVA).
|
10
|
+
* Fix reversed coordinates array with Mapbox (thanks github.com/marcusat).
|
11
|
+
* Fix missing city name in some cases with ESRI (thanks github.com/roybotnik).
|
12
|
+
* Prevent re-opening of DB file on every read with :geoip2 (thanks github.com/oogali).
|
13
|
+
|
14
|
+
1.2.12 (2015 Oct 29)
|
15
|
+
--------------------
|
16
|
+
* Fix Ruby 1.9.3 incompatibility (remove non-existent timeout classes) (thanks github.com/roychri).
|
17
|
+
|
6
18
|
1.2.11 (2015 Sep 10)
|
7
19
|
--------------------
|
8
20
|
* Fix load issue on Ruby 1.9.3.
|
data/README.md
CHANGED
@@ -9,7 +9,7 @@ _Please note that this README is for the current `HEAD` and may document feature
|
|
9
9
|
Compatibility
|
10
10
|
-------------
|
11
11
|
|
12
|
-
* Supports multiple Ruby versions: Ruby 1.9.3, 2.
|
12
|
+
* Supports multiple Ruby versions: Ruby 1.9.3, 2.x, JRuby, and Rubinius.
|
13
13
|
* Supports multiple databases: MySQL, PostgreSQL, SQLite, and MongoDB (1.7.0 and higher).
|
14
14
|
* Supports Rails 3 and 4. If you need to use it with Rails 2 please see the `rails2` branch (no longer maintained, limited feature set).
|
15
15
|
* Works very well outside of Rails, you just need to install either the `json` (for MRI) or `json_pure` (for JRuby) gem.
|
@@ -106,6 +106,10 @@ If you have just added geocoding to an existing application with a lot of object
|
|
106
106
|
|
107
107
|
rake geocode:all CLASS=YourModel
|
108
108
|
|
109
|
+
If you need reverse geocoding instead, call the task with REVERSE=true:
|
110
|
+
|
111
|
+
rake geocode:all CLASS=YourModel REVERSE=true
|
112
|
+
|
109
113
|
Geocoder will print warnings if you exceed the rate limit for your geocoding service. Some services — Google notably — enforce a per-second limit in addition to a per-day limit. To avoid exceeding the per-second limit, you can add a `SLEEP` option to pause between requests for a given amount of time. You can also load objects in batches to save memory, for example:
|
110
114
|
|
111
115
|
rake geocode:all CLASS=YourModel SLEEP=0.25 BATCH=100
|
@@ -140,6 +144,12 @@ See _Advanced Geocoding_ below for more information about `Geocoder::Result` obj
|
|
140
144
|
Location-Aware Database Queries
|
141
145
|
-------------------------------
|
142
146
|
|
147
|
+
### For Mongo-backed models:
|
148
|
+
|
149
|
+
Please use MongoDB's [geospatial query language](https://docs.mongodb.org/manual/reference/command/geoNear/). Mongoid also provides [a DSL](http://mongoid.github.io/en/mongoid/docs/querying.html#geo_near) for doing near queries.
|
150
|
+
|
151
|
+
### For ActiveRecord models:
|
152
|
+
|
143
153
|
To find objects by location, use the following scopes:
|
144
154
|
|
145
155
|
Venue.near('Omaha, NE, US', 20) # venues within 20 miles of Omaha
|
@@ -149,6 +159,10 @@ To find objects by location, use the following scopes:
|
|
149
159
|
Venue.geocoded # venues with coordinates
|
150
160
|
Venue.not_geocoded # venues without coordinates
|
151
161
|
|
162
|
+
by default, objects are ordered by distance. To remove the ORDER BY clause use the following:
|
163
|
+
|
164
|
+
Venue.near('Omaha', 20, :order => false)
|
165
|
+
|
152
166
|
With geocoded objects you can do things like this:
|
153
167
|
|
154
168
|
if obj.geocoded?
|
@@ -500,6 +514,20 @@ The [Google Places Details API](https://developers.google.com/places/documentati
|
|
500
514
|
* **Terms of Service**: http://geocoder.us/terms.shtml
|
501
515
|
* **Limitations**: ?
|
502
516
|
|
517
|
+
#### Mapbox (`:mapbox`)
|
518
|
+
|
519
|
+
* **API key**: required
|
520
|
+
* **Dataset**: Uses `mapbox.places` dataset by default. Specific the `mapbox.places-permanent` dataset by setting: `Geocoder.configure(:mapbox => {:dataset => "mapbox.places-permanent"})`
|
521
|
+
* **Key signup**: https://www.mapbox.com/pricing/
|
522
|
+
* **Quota**: depends on plan
|
523
|
+
* **Region**: complete coverage of US and Canada, partial coverage elsewhere (see for details: https://www.mapbox.com/developers/api/geocoding/#coverage)
|
524
|
+
* **SSL support**: yes
|
525
|
+
* **Languages**: English
|
526
|
+
* **Documentation**: https://www.mapbox.com/developers/api/geocoding/
|
527
|
+
* **Terms of Service**: https://www.mapbox.com/tos/
|
528
|
+
* **Limitations**: For `mapbox.places` dataset, must be displayed on a Mapbox map; Cache results for up to 30 days. For `mapbox.places-permanent` dataset, depends on plan.
|
529
|
+
* **Notes**: Currently in public beta.
|
530
|
+
|
503
531
|
#### Mapquest (`:mapquest`)
|
504
532
|
|
505
533
|
* **API key**: required
|
@@ -653,14 +681,15 @@ This uses the PostcodeAnywhere UK Geocode service, this will geocode any string
|
|
653
681
|
|
654
682
|
#### Telize (`:telize`)
|
655
683
|
|
656
|
-
* **API key**:
|
657
|
-
* **Quota**:
|
684
|
+
* **API key**: required
|
685
|
+
* **Quota**: 1,000/day for $7/mo through 100,000/day for $100/mo
|
658
686
|
* **Region**: world
|
659
|
-
* **SSL support**:
|
687
|
+
* **SSL support**: yes
|
660
688
|
* **Languages**: English
|
661
|
-
* **Documentation**:
|
689
|
+
* **Documentation**: https://market.mashape.com/fcambus/telize
|
662
690
|
* **Terms of Service**: ?
|
663
691
|
* **Limitations**: ?
|
692
|
+
* **Notes**: To use Telize set `Geocoder.configure(:ip_lookup => :telize, :api_key => "your_api_key")`.
|
664
693
|
|
665
694
|
#### MaxMind Legacy Web Services (`:maxmind`)
|
666
695
|
|
data/lib/geocoder/lookup.rb
CHANGED
@@ -4,6 +4,8 @@ require 'geocoder/results/geoip2'
|
|
4
4
|
module Geocoder
|
5
5
|
module Lookup
|
6
6
|
class Geoip2 < Base
|
7
|
+
attr_reader :gem_name
|
8
|
+
|
7
9
|
def initialize
|
8
10
|
unless configuration[:file].nil?
|
9
11
|
begin
|
@@ -12,6 +14,8 @@ module Geocoder
|
|
12
14
|
rescue LoadError
|
13
15
|
raise "Could not load Maxmind DB dependency. To use the GeoIP2 lookup you must add the #{@gem_name} gem to your Gemfile or have it installed in your system."
|
14
16
|
end
|
17
|
+
|
18
|
+
@mmdb = db_class.new(configuration[:file].to_s)
|
15
19
|
end
|
16
20
|
super
|
17
21
|
end
|
@@ -26,14 +30,14 @@ module Geocoder
|
|
26
30
|
|
27
31
|
private
|
28
32
|
|
33
|
+
def db_class
|
34
|
+
gem_name == 'hive_geoip2' ? Hive::GeoIP2 : MaxMindDB
|
35
|
+
end
|
36
|
+
|
29
37
|
def results(query)
|
30
38
|
return [] unless configuration[:file]
|
31
|
-
|
32
|
-
|
33
|
-
else
|
34
|
-
result = MaxMindDB.new(configuration[:file].to_s).lookup(query.to_s)
|
35
|
-
end
|
36
|
-
result.nil? ? [] : [result]
|
39
|
+
|
40
|
+
Array(@mmdb.lookup(query.to_s))
|
37
41
|
end
|
38
42
|
end
|
39
43
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'geocoder/lookups/base'
|
2
|
+
require "geocoder/results/mapbox"
|
3
|
+
|
4
|
+
module Geocoder::Lookup
|
5
|
+
class Mapbox < Base
|
6
|
+
|
7
|
+
def name
|
8
|
+
"Mapbox"
|
9
|
+
end
|
10
|
+
|
11
|
+
def query_url(query)
|
12
|
+
"#{protocol}://api.mapbox.com/geocoding/v5/#{dataset}/#{url_query_string(query)}.json?access_token=#{configuration.api_key}"
|
13
|
+
end
|
14
|
+
|
15
|
+
private # ---------------------------------------------------------------
|
16
|
+
|
17
|
+
def results(query)
|
18
|
+
return [] unless data = fetch_data(query)
|
19
|
+
if data['features']
|
20
|
+
sort_relevant_feature(data['features'])
|
21
|
+
elsif data['message'] =~ /Invalid\sToken/
|
22
|
+
raise_error(Geocoder::InvalidApiKey, data['message'])
|
23
|
+
else
|
24
|
+
[]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def url_query_string(query)
|
29
|
+
require 'cgi' unless defined?(CGI) && defined?(CGI.escape)
|
30
|
+
if query.reverse_geocode?
|
31
|
+
lat,lon = query.coordinates
|
32
|
+
"#{CGI.escape lon},#{CGI.escape lat}"
|
33
|
+
else
|
34
|
+
CGI.escape query.text.to_s
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def dataset
|
39
|
+
configuration[:dataset] || "mapbox.places"
|
40
|
+
end
|
41
|
+
|
42
|
+
def supported_protocols
|
43
|
+
[:https]
|
44
|
+
end
|
45
|
+
|
46
|
+
def sort_relevant_feature(features)
|
47
|
+
# Sort by descending relevance; Favor original order for equal relevance (eg occurs for reverse geocoding)
|
48
|
+
features.sort_by do |feature|
|
49
|
+
[feature["relevance"],-features.index(feature)]
|
50
|
+
end.reverse
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -8,13 +8,16 @@ module Geocoder::Lookup
|
|
8
8
|
"Telize"
|
9
9
|
end
|
10
10
|
|
11
|
+
def required_api_key_parts
|
12
|
+
["key"]
|
13
|
+
end
|
14
|
+
|
11
15
|
def query_url(query)
|
12
|
-
"#{protocol}://
|
16
|
+
"#{protocol}://telize-v1.p.mashape.com/geoip/#{query.sanitized_text}?mashape-key=#{api_key}"
|
13
17
|
end
|
14
18
|
|
15
|
-
# currently doesn't support HTTPS
|
16
19
|
def supported_protocols
|
17
|
-
[:
|
20
|
+
[:https]
|
18
21
|
end
|
19
22
|
|
20
23
|
private # ---------------------------------------------------------------
|
@@ -36,5 +39,9 @@ module Geocoder::Lookup
|
|
36
39
|
def reserved_result(ip)
|
37
40
|
{"message" => "Input string is not a valid IP address", "code" => 401}
|
38
41
|
end
|
42
|
+
|
43
|
+
def api_key
|
44
|
+
configuration.api_key
|
45
|
+
end
|
39
46
|
end
|
40
47
|
end
|
@@ -9,7 +9,11 @@ module Geocoder::Result
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def city
|
12
|
-
|
12
|
+
if !reverse_geocode? && is_city?
|
13
|
+
attributes['PlaceName']
|
14
|
+
else
|
15
|
+
attributes['City']
|
16
|
+
end
|
13
17
|
end
|
14
18
|
|
15
19
|
def state_code
|
@@ -47,5 +51,8 @@ module Geocoder::Result
|
|
47
51
|
@data['locations'].nil?
|
48
52
|
end
|
49
53
|
|
54
|
+
def is_city?
|
55
|
+
['City', 'State Capital', 'National Capital'].include?(attributes['Type'])
|
56
|
+
end
|
50
57
|
end
|
51
|
-
end
|
58
|
+
end
|
@@ -13,35 +13,35 @@ module Geocoder
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def latitude
|
16
|
-
data.fetch('location',{}).fetch('latitude',0.0)
|
16
|
+
data.fetch('location', {}).fetch('latitude', 0.0)
|
17
17
|
end
|
18
18
|
|
19
19
|
def longitude
|
20
|
-
data.fetch('location',{}).fetch('longitude',0.0)
|
20
|
+
data.fetch('location', {}).fetch('longitude', 0.0)
|
21
21
|
end
|
22
22
|
|
23
23
|
def city
|
24
|
-
data.fetch('city', {}).fetch('names', {}).fetch(
|
24
|
+
data.fetch('city', {}).fetch('names', {}).fetch(locale, '')
|
25
25
|
end
|
26
26
|
|
27
27
|
def state
|
28
|
-
data.fetch('subdivisions',[]).fetch(0,{}).fetch('names',{}).fetch(
|
28
|
+
data.fetch('subdivisions', []).fetch(0, {}).fetch('names', {}).fetch(locale, '')
|
29
29
|
end
|
30
30
|
|
31
31
|
def state_code
|
32
|
-
data.fetch('subdivisions',[]).fetch(0,{}).fetch('iso_code','')
|
32
|
+
data.fetch('subdivisions', []).fetch(0, {}).fetch('iso_code', '')
|
33
33
|
end
|
34
34
|
|
35
35
|
def country
|
36
|
-
data.fetch('country', {}).fetch('names',{}).fetch(
|
36
|
+
data.fetch('country', {}).fetch('names', {}).fetch(locale, '')
|
37
37
|
end
|
38
38
|
|
39
39
|
def country_code
|
40
|
-
data.fetch('country',{}).fetch('iso_code','')
|
40
|
+
data.fetch('country', {}).fetch('iso_code', '')
|
41
41
|
end
|
42
42
|
|
43
43
|
def postal_code
|
44
|
-
data.fetch('postal',{}).fetch('code','')
|
44
|
+
data.fetch('postal', {}).fetch('code', '')
|
45
45
|
end
|
46
46
|
|
47
47
|
def self.response_attributes
|
@@ -59,6 +59,10 @@ module Geocoder
|
|
59
59
|
def data
|
60
60
|
@data.to_hash
|
61
61
|
end
|
62
|
+
|
63
|
+
def locale
|
64
|
+
@locale ||= Geocoder.config[:language].to_s
|
65
|
+
end
|
62
66
|
end
|
63
67
|
end
|
64
68
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'geocoder/results/base'
|
2
|
+
|
3
|
+
module Geocoder::Result
|
4
|
+
class Mapbox < Base
|
5
|
+
|
6
|
+
def latitude
|
7
|
+
@latitude ||= @data["geometry"]["coordinates"].last.to_f
|
8
|
+
end
|
9
|
+
|
10
|
+
def longitude
|
11
|
+
@longitude ||= @data["geometry"]["coordinates"].first.to_f
|
12
|
+
end
|
13
|
+
|
14
|
+
def coordinates
|
15
|
+
[latitude, longitude]
|
16
|
+
end
|
17
|
+
|
18
|
+
def place_name
|
19
|
+
@data['text']
|
20
|
+
end
|
21
|
+
|
22
|
+
def street
|
23
|
+
@data['properties']['address']
|
24
|
+
end
|
25
|
+
|
26
|
+
def city
|
27
|
+
@data['context'].map { |c| c['text'] if c['id'] =~ /place/ }.compact.first
|
28
|
+
end
|
29
|
+
|
30
|
+
def state
|
31
|
+
@data['context'].map { |c| c['text'] if c['id'] =~ /region/ }.compact.first
|
32
|
+
end
|
33
|
+
|
34
|
+
alias_method :state_code, :state
|
35
|
+
|
36
|
+
def postal_code
|
37
|
+
@data['context'].map { |c| c['text'] if c['id'] =~ /postcode/ }.compact.first
|
38
|
+
end
|
39
|
+
|
40
|
+
def country
|
41
|
+
@data['context'].map { |c| c['text'] if c['id'] =~ /country/ }.compact.first
|
42
|
+
end
|
43
|
+
|
44
|
+
alias_method :country_code, :country
|
45
|
+
|
46
|
+
def neighborhood
|
47
|
+
@data['context'].map { |c| c['text'] if c['id'] =~ /neighborhood/ }.compact.first
|
48
|
+
end
|
49
|
+
|
50
|
+
def address
|
51
|
+
[place_name, street, city, state, postal_code, country].compact.join(", ")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
@@ -28,6 +28,11 @@ module Geocoder::Store
|
|
28
28
|
"OR #{table_name}.#{geocoder_options[:longitude]} IS NULL")
|
29
29
|
}
|
30
30
|
|
31
|
+
# scope: not-reverse geocoded objects
|
32
|
+
scope :not_reverse_geocoded, lambda {
|
33
|
+
where("#{table_name}.#{geocoder_options[:fetched_address]} IS NULL")
|
34
|
+
}
|
35
|
+
|
31
36
|
##
|
32
37
|
# Find all objects within a radius of the given location.
|
33
38
|
# Location may be either a string to geocode or an array of
|
data/lib/geocoder/version.rb
CHANGED
data/lib/tasks/geocoder.rake
CHANGED
@@ -4,13 +4,22 @@ namespace :geocode do
|
|
4
4
|
class_name = ENV['CLASS'] || ENV['class']
|
5
5
|
sleep_timer = ENV['SLEEP'] || ENV['sleep']
|
6
6
|
batch = ENV['BATCH'] || ENV['batch']
|
7
|
+
reverse = ENV['REVERSE'] || ENV['reverse']
|
7
8
|
raise "Please specify a CLASS (model)" unless class_name
|
8
9
|
klass = class_from_string(class_name)
|
9
10
|
batch = batch.to_i unless batch.nil?
|
11
|
+
reverse = false unless reverse.to_s.downcase == 'true'
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
|
13
|
+
if reverse
|
14
|
+
klass.not_reverse_geocoded.find_each(batch_size: batch) do |obj|
|
15
|
+
obj.reverse_geocode; obj.save
|
16
|
+
sleep(sleep_timer.to_f) unless sleep_timer.nil?
|
17
|
+
end
|
18
|
+
else
|
19
|
+
klass.not_geocoded.find_each(batch_size: batch) do |obj|
|
20
|
+
obj.geocode; obj.save
|
21
|
+
sleep(sleep_timer.to_f) unless sleep_timer.nil?
|
22
|
+
end
|
14
23
|
end
|
15
24
|
end
|
16
25
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: geocoder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Reisner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-12-15 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Provides object geocoding (by street or IP address), reverse geocoding
|
14
14
|
(coordinates to street address), distance queries for ActiveRecord and Mongoid,
|
@@ -61,6 +61,7 @@ files:
|
|
61
61
|
- lib/geocoder/lookups/google_places_details.rb
|
62
62
|
- lib/geocoder/lookups/google_premier.rb
|
63
63
|
- lib/geocoder/lookups/here.rb
|
64
|
+
- lib/geocoder/lookups/mapbox.rb
|
64
65
|
- lib/geocoder/lookups/mapquest.rb
|
65
66
|
- lib/geocoder/lookups/maxmind.rb
|
66
67
|
- lib/geocoder/lookups/maxmind_geoip2.rb
|
@@ -99,6 +100,7 @@ files:
|
|
99
100
|
- lib/geocoder/results/google_places_details.rb
|
100
101
|
- lib/geocoder/results/google_premier.rb
|
101
102
|
- lib/geocoder/results/here.rb
|
103
|
+
- lib/geocoder/results/mapbox.rb
|
102
104
|
- lib/geocoder/results/mapquest.rb
|
103
105
|
- lib/geocoder/results/maxmind.rb
|
104
106
|
- lib/geocoder/results/maxmind_geoip2.rb
|