geocoder 1.2.12 → 1.3.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 +4 -4
- data/CHANGELOG.md +23 -0
- data/README.md +50 -6
- data/lib/geocoder/calculations.rb +1 -1
- data/lib/geocoder/configuration.rb +0 -1
- data/lib/geocoder/lookup.rb +6 -4
- data/lib/geocoder/lookups/geoip2.rb +10 -5
- data/lib/geocoder/lookups/geoportail_lu.rb +65 -0
- data/lib/geocoder/lookups/mapbox.rb +53 -0
- data/lib/geocoder/lookups/maxmind_local.rb +1 -1
- data/lib/geocoder/lookups/telize.rb +10 -3
- data/lib/geocoder/results/esri.rb +22 -6
- data/lib/geocoder/results/geoip2.rb +12 -8
- data/lib/geocoder/results/geoportail_lu.rb +69 -0
- data/lib/geocoder/results/google.rb +8 -0
- data/lib/geocoder/results/mapbox.rb +55 -0
- data/lib/geocoder/stores/active_record.rb +5 -0
- data/lib/geocoder/stores/mongo_base.rb +0 -44
- data/lib/geocoder/version.rb +1 -1
- data/lib/tasks/geocoder.rake +12 -3
- metadata +7 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e7a2b3e33175d20be86a8eaf6c74d6178bc71991
|
|
4
|
+
data.tar.gz: d0dc03b689fbc43f16ae9395c7f743a3dd7876bd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cb9f5c459af278bd20438a714475dece555b72222c34eab8c8fb61f6ddfc695848d330e9b84f366c8d67e5f253bda7d5e61020ab46382f8fbb40c8b7a9a58e82
|
|
7
|
+
data.tar.gz: ca02902240f5287a570ee05b0bc3b0300708200108b09543763e761ad1f0a2371355ef651471cdf96ce5cdabf104a39aedb04ef684e4f02aa3023911c27d7c4a
|
data/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,29 @@ 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.3.0 (2016 Jan 31)
|
|
7
|
+
-------------------
|
|
8
|
+
* Lazy load lookups to reduce memory footprint (thanks github.com/TrangPham).
|
|
9
|
+
* Add :geoportail_lu lookup (Luxembourg only) (thanks github.com/mdebo).
|
|
10
|
+
* Maxmind local query performance improvement (thanks github.com/vojtad).
|
|
11
|
+
* Remove deprecated Mongo near query methods (please use Mongo-native methods instead).
|
|
12
|
+
|
|
13
|
+
1.2.14 (2015 Dec 27)
|
|
14
|
+
--------------------
|
|
15
|
+
* Fix bug in :geoip2 lookup (thanks github.com/mromulus).
|
|
16
|
+
|
|
17
|
+
1.2.13 (2015 Dec 15)
|
|
18
|
+
--------------------
|
|
19
|
+
* Update :telize IP lookup to reflect new URL (thanks github.com/jfredrickson).
|
|
20
|
+
* Add reverse geocode rake task (thanks github.com/FanaHOVA).
|
|
21
|
+
* Fix reversed coordinates array with Mapbox (thanks github.com/marcusat).
|
|
22
|
+
* Fix missing city name in some cases with ESRI (thanks github.com/roybotnik).
|
|
23
|
+
* Prevent re-opening of DB file on every read with :geoip2 (thanks github.com/oogali).
|
|
24
|
+
|
|
25
|
+
1.2.12 (2015 Oct 29)
|
|
26
|
+
--------------------
|
|
27
|
+
* Fix Ruby 1.9.3 incompatibility (remove non-existent timeout classes) (thanks github.com/roychri).
|
|
28
|
+
|
|
6
29
|
1.2.11 (2015 Sep 10)
|
|
7
30
|
--------------------
|
|
8
31
|
* 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
|
|
@@ -609,6 +637,16 @@ Data Science Toolkit provides an API whose reponse format is like Google's but w
|
|
|
609
637
|
* **Terms of Service**: http://www.itella.fi/liitteet/palvelutjatuotteet/yhteystietopalvelut/Postinumeropalvelut-Palvelukuvausjakayttoehdot.pdf
|
|
610
638
|
* **Limitations**: ?
|
|
611
639
|
|
|
640
|
+
#### Geoportail.lu (`:geoportail_lu`)
|
|
641
|
+
|
|
642
|
+
* **API key**: none
|
|
643
|
+
* **Quota**: none
|
|
644
|
+
* **Region**: LU
|
|
645
|
+
* **SSL support**: yes
|
|
646
|
+
* **Languages**: en
|
|
647
|
+
* **Documentation**: http://wiki.geoportail.lu/doku.php?id=en:api
|
|
648
|
+
* **Terms of Service**: http://wiki.geoportail.lu/doku.php?id=en:mcg_1
|
|
649
|
+
* **Limitations**: ?
|
|
612
650
|
|
|
613
651
|
#### PostcodeAnywhere Uk (`:postcode_anywhere_uk`)
|
|
614
652
|
|
|
@@ -653,14 +691,15 @@ This uses the PostcodeAnywhere UK Geocode service, this will geocode any string
|
|
|
653
691
|
|
|
654
692
|
#### Telize (`:telize`)
|
|
655
693
|
|
|
656
|
-
* **API key**:
|
|
657
|
-
* **Quota**:
|
|
694
|
+
* **API key**: required
|
|
695
|
+
* **Quota**: 1,000/day for $7/mo through 100,000/day for $100/mo
|
|
658
696
|
* **Region**: world
|
|
659
|
-
* **SSL support**:
|
|
697
|
+
* **SSL support**: yes
|
|
660
698
|
* **Languages**: English
|
|
661
|
-
* **Documentation**:
|
|
699
|
+
* **Documentation**: https://market.mashape.com/fcambus/telize
|
|
662
700
|
* **Terms of Service**: ?
|
|
663
701
|
* **Limitations**: ?
|
|
702
|
+
* **Notes**: To use Telize set `Geocoder.configure(:ip_lookup => :telize, :api_key => "your_api_key")`.
|
|
664
703
|
|
|
665
704
|
#### MaxMind Legacy Web Services (`:maxmind`)
|
|
666
705
|
|
|
@@ -895,6 +934,9 @@ Now, any time Geocoder looks up "New York, NY" its results array will contain on
|
|
|
895
934
|
]
|
|
896
935
|
)
|
|
897
936
|
|
|
937
|
+
Note:
|
|
938
|
+
Keys must be strings not symbols when calling `add_stub` or `set_default_stub`. For example `'latitude' =>` not `:latitude =>`.
|
|
939
|
+
|
|
898
940
|
|
|
899
941
|
Command Line Interface
|
|
900
942
|
----------------------
|
|
@@ -1070,7 +1112,9 @@ If anyone has a more elegant solution to this problem I am very interested in se
|
|
|
1070
1112
|
Contributing
|
|
1071
1113
|
------------
|
|
1072
1114
|
|
|
1073
|
-
Contributions are welcome via pull requests
|
|
1115
|
+
Contributions are welcome via Github pull requests. If you are new to the project and looking for a way to get involved, try picking up an issue with a "beginner-task" label. Hints about what needs to be done are usually provided.
|
|
1116
|
+
|
|
1117
|
+
For all contributions, please respect the following guidelines:
|
|
1074
1118
|
|
|
1075
1119
|
* Each pull request should implement ONE feature or bugfix. If you want to add or fix more than one thing, submit more than one pull request.
|
|
1076
1120
|
* Do not commit changes to files that are irrelevant to your feature or bugfix (eg: `.gitignore`).
|
|
@@ -263,7 +263,7 @@ module Geocoder
|
|
|
263
263
|
end
|
|
264
264
|
|
|
265
265
|
##
|
|
266
|
-
# Given a start point,
|
|
266
|
+
# Given a start point, heading (in degrees), and distance, provides
|
|
267
267
|
# an endpoint.
|
|
268
268
|
# The starting point is given in the same way that points are given to all
|
|
269
269
|
# Geocoder methods that accept points as arguments. It can be:
|
data/lib/geocoder/lookup.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require "geocoder/lookups/test"
|
|
2
|
+
|
|
1
3
|
module Geocoder
|
|
2
4
|
module Lookup
|
|
3
5
|
extend self
|
|
@@ -32,6 +34,7 @@ module Geocoder
|
|
|
32
34
|
:geocoder_us,
|
|
33
35
|
:yandex,
|
|
34
36
|
:nominatim,
|
|
37
|
+
:mapbox,
|
|
35
38
|
:mapquest,
|
|
36
39
|
:opencagedata,
|
|
37
40
|
:ovi,
|
|
@@ -41,6 +44,7 @@ module Geocoder
|
|
|
41
44
|
:smarty_streets,
|
|
42
45
|
:okf,
|
|
43
46
|
:postcode_anywhere_uk,
|
|
47
|
+
:geoportail_lu,
|
|
44
48
|
:test
|
|
45
49
|
]
|
|
46
50
|
end
|
|
@@ -82,6 +86,8 @@ module Geocoder
|
|
|
82
86
|
#
|
|
83
87
|
def spawn(name)
|
|
84
88
|
if all_services.include?(name)
|
|
89
|
+
name = name.to_s
|
|
90
|
+
require "geocoder/lookups/#{name}"
|
|
85
91
|
Geocoder::Lookup.const_get(classify_name(name)).new
|
|
86
92
|
else
|
|
87
93
|
valids = all_services.map(&:inspect).join(", ")
|
|
@@ -98,7 +104,3 @@ module Geocoder
|
|
|
98
104
|
end
|
|
99
105
|
end
|
|
100
106
|
end
|
|
101
|
-
|
|
102
|
-
Geocoder::Lookup.all_services.each do |name|
|
|
103
|
-
require "geocoder/lookups/#{name}"
|
|
104
|
-
end
|
|
@@ -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,13 +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
|
|
39
|
+
|
|
40
|
+
result = @mmdb.lookup(query.to_s)
|
|
36
41
|
result.nil? ? [] : [result]
|
|
37
42
|
end
|
|
38
43
|
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
require 'geocoder/lookups/base'
|
|
2
|
+
require "geocoder/results/geoportail_lu"
|
|
3
|
+
|
|
4
|
+
module Geocoder
|
|
5
|
+
module Lookup
|
|
6
|
+
class GeoportailLu < Base
|
|
7
|
+
|
|
8
|
+
def name
|
|
9
|
+
"Geoportail.lu"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def query_url(query)
|
|
13
|
+
url_base_path(query) + url_query_string(query)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def url_base_path(query)
|
|
19
|
+
query.reverse_geocode? ? reverse_geocode_url_base_path : search_url_base_path
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def search_url_base_path
|
|
23
|
+
"#{protocol}://api.geoportail.lu/geocoder/search?"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def reverse_geocode_url_base_path
|
|
27
|
+
"#{protocol}://api.geoportail.lu/geocoder/reverseGeocode?"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def query_url_geoportail_lu_params(query)
|
|
31
|
+
query.reverse_geocode? ? reverse_geocode_params(query) : search_params(query)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def search_params(query)
|
|
35
|
+
{
|
|
36
|
+
queryString: query.sanitized_text
|
|
37
|
+
}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def reverse_geocode_params(query)
|
|
41
|
+
lat_lon = query.coordinates
|
|
42
|
+
{
|
|
43
|
+
lat: lat_lon.first,
|
|
44
|
+
lon: lat_lon.last
|
|
45
|
+
}
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def query_url_params(query)
|
|
49
|
+
query_url_geoportail_lu_params(query).merge(super)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def results(query)
|
|
53
|
+
return [] unless doc = fetch_data(query)
|
|
54
|
+
if doc['success'] == true
|
|
55
|
+
result = doc['results']
|
|
56
|
+
else
|
|
57
|
+
result = []
|
|
58
|
+
raise_error(Geocoder::Error) ||
|
|
59
|
+
warn("Geportail.lu Geocoding API error")
|
|
60
|
+
end
|
|
61
|
+
result
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
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
|
|
@@ -36,7 +36,7 @@ module Geocoder::Lookup
|
|
|
36
36
|
addr = IPAddr.new(query.text).to_i
|
|
37
37
|
q = "SELECT l.country, l.region, l.city, l.latitude, l.longitude
|
|
38
38
|
FROM maxmind_geolite_city_location l WHERE l.loc_id = (SELECT b.loc_id FROM maxmind_geolite_city_blocks b
|
|
39
|
-
WHERE b.start_ip_num <= #{addr} AND #{addr} <= b.end_ip_num
|
|
39
|
+
WHERE b.start_ip_num <= #{addr} AND #{addr} <= b.end_ip_num)"
|
|
40
40
|
format_result(q, [:country_name, :region_name, :city_name, :latitude, :longitude])
|
|
41
41
|
elsif configuration[:package] == :country
|
|
42
42
|
addr = IPAddr.new(query.text).to_i
|
|
@@ -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
|
|
@@ -4,12 +4,16 @@ module Geocoder::Result
|
|
|
4
4
|
class Esri < Base
|
|
5
5
|
|
|
6
6
|
def address
|
|
7
|
-
|
|
8
|
-
attributes[
|
|
7
|
+
address_key = reverse_geocode? ? 'Address' : 'Match_addr'
|
|
8
|
+
attributes[address_key]
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def city
|
|
12
|
-
|
|
12
|
+
if !reverse_geocode? && is_city?
|
|
13
|
+
place_name
|
|
14
|
+
else
|
|
15
|
+
attributes['City']
|
|
16
|
+
end
|
|
13
17
|
end
|
|
14
18
|
|
|
15
19
|
def state_code
|
|
@@ -19,8 +23,8 @@ module Geocoder::Result
|
|
|
19
23
|
alias_method :state, :state_code
|
|
20
24
|
|
|
21
25
|
def country
|
|
22
|
-
|
|
23
|
-
attributes[
|
|
26
|
+
country_key = reverse_geocode? ? "CountryCode" : "Country"
|
|
27
|
+
attributes[country_key]
|
|
24
28
|
end
|
|
25
29
|
|
|
26
30
|
alias_method :country_code, :country
|
|
@@ -29,6 +33,15 @@ module Geocoder::Result
|
|
|
29
33
|
attributes['Postal']
|
|
30
34
|
end
|
|
31
35
|
|
|
36
|
+
def place_name
|
|
37
|
+
place_name_key = reverse_geocode? ? "Address" : "PlaceName"
|
|
38
|
+
attributes[place_name_key]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def place_type
|
|
42
|
+
reverse_geocode? ? "Address" : attributes['Type']
|
|
43
|
+
end
|
|
44
|
+
|
|
32
45
|
def coordinates
|
|
33
46
|
[geometry["y"], geometry["x"]]
|
|
34
47
|
end
|
|
@@ -47,5 +60,8 @@ module Geocoder::Result
|
|
|
47
60
|
@data['locations'].nil?
|
|
48
61
|
end
|
|
49
62
|
|
|
63
|
+
def is_city?
|
|
64
|
+
['City', 'State Capital', 'National Capital'].include?(place_type)
|
|
65
|
+
end
|
|
50
66
|
end
|
|
51
|
-
end
|
|
67
|
+
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,69 @@
|
|
|
1
|
+
require 'geocoder/results/base'
|
|
2
|
+
|
|
3
|
+
module Geocoder::Result
|
|
4
|
+
class GeoportailLu < Base
|
|
5
|
+
|
|
6
|
+
def coordinates
|
|
7
|
+
geomlonlat['coordinates'].reverse if geolocalized?
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def address
|
|
11
|
+
full_address
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def city
|
|
15
|
+
try_to_extract 'locality', detailled_address
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def state
|
|
19
|
+
'Luxembourg'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def state_code
|
|
23
|
+
'LU'
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def postal_code
|
|
27
|
+
try_to_extract 'zip', detailled_address
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def street_address
|
|
31
|
+
[street_number, street].compact.join(' ')
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def street_number
|
|
35
|
+
try_to_extract 'postnumber', detailled_address
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def street
|
|
39
|
+
try_to_extract 'street', detailled_address
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def full_address
|
|
43
|
+
data['address']
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def geomlonlat
|
|
47
|
+
data['geomlonlat']
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def detailled_address
|
|
51
|
+
data['AddressDetails']
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
alias_method :country, :state
|
|
55
|
+
alias_method :province, :state
|
|
56
|
+
alias_method :country_code, :state_code
|
|
57
|
+
alias_method :province_code, :state_code
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def geolocalized?
|
|
62
|
+
try_to_extract('coordinates', geomlonlat).present?
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def try_to_extract(key, nullable_hash)
|
|
66
|
+
nullable_hash.try(:[], key)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
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
|
|
@@ -11,38 +11,6 @@ module Geocoder::Store
|
|
|
11
11
|
scope :not_geocoded, lambda {
|
|
12
12
|
where(geocoder_options[:coordinates] => nil)
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
scope :near, lambda{ |location, *args|
|
|
16
|
-
warn "DEPRECATION WARNING: The .near method will be removed for MongoDB-backed models in Geocoder 1.3.0. Please use MongoDB's built-in query language instead."
|
|
17
|
-
coords = Geocoder::Calculations.extract_coordinates(location)
|
|
18
|
-
|
|
19
|
-
# no results if no lat/lon given
|
|
20
|
-
return where(:id => false) unless coords.is_a?(Array)
|
|
21
|
-
|
|
22
|
-
radius = args.size > 0 ? args.shift : 20
|
|
23
|
-
options = args.size > 0 ? args.shift : {}
|
|
24
|
-
options[:units] ||= geocoder_options[:units]
|
|
25
|
-
|
|
26
|
-
# Use BSON::OrderedHash if Ruby's hashes are unordered.
|
|
27
|
-
# Conditions must be in order required by indexes (see mongo gem).
|
|
28
|
-
version = RUBY_VERSION.split('.').map { |i| i.to_i }
|
|
29
|
-
empty = version[0] < 2 && version[1] < 9 ? BSON::OrderedHash.new : {}
|
|
30
|
-
|
|
31
|
-
conds = empty.clone
|
|
32
|
-
field = geocoder_options[:coordinates]
|
|
33
|
-
conds[field] = empty.clone
|
|
34
|
-
conds[field]["$nearSphere"] = coords.reverse
|
|
35
|
-
|
|
36
|
-
if radius
|
|
37
|
-
conds[field]["$maxDistance"] = \
|
|
38
|
-
Geocoder::Calculations.distance_to_radians(radius, options[:units])
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
if obj = options[:exclude]
|
|
42
|
-
conds[:_id.ne] = obj.id
|
|
43
|
-
end
|
|
44
|
-
where(conds)
|
|
45
|
-
}
|
|
46
14
|
end
|
|
47
15
|
end
|
|
48
16
|
|
|
@@ -56,18 +24,6 @@ module Geocoder::Store
|
|
|
56
24
|
coords.is_a?(Array) ? coords.reverse : []
|
|
57
25
|
end
|
|
58
26
|
|
|
59
|
-
##
|
|
60
|
-
# Get nearby geocoded objects.
|
|
61
|
-
# Takes the same options hash as the near class method (scope).
|
|
62
|
-
# Returns nil if the object is not geocoded.
|
|
63
|
-
#
|
|
64
|
-
def nearbys(radius = 20, options = {})
|
|
65
|
-
warn "DEPRECATION WARNING: The #nearbys method will be removed for MongoDB-backed models in Geocoder 1.3.0. Please use MongoDB's built-in query language instead."
|
|
66
|
-
return nil unless geocoded?
|
|
67
|
-
options.merge!(:exclude => self) unless send(self.class.primary_key).nil?
|
|
68
|
-
self.class.near(self, radius, options)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
27
|
##
|
|
72
28
|
# Look up coordinates and assign to +latitude+ and +longitude+ attributes
|
|
73
29
|
# (or other as specified in +geocoded_by+). Returns coordinates (array).
|
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.
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex Reisner
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2016-01-31 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,
|
|
@@ -57,10 +57,12 @@ files:
|
|
|
57
57
|
- lib/geocoder/lookups/geocoder_us.rb
|
|
58
58
|
- lib/geocoder/lookups/geocodio.rb
|
|
59
59
|
- lib/geocoder/lookups/geoip2.rb
|
|
60
|
+
- lib/geocoder/lookups/geoportail_lu.rb
|
|
60
61
|
- lib/geocoder/lookups/google.rb
|
|
61
62
|
- lib/geocoder/lookups/google_places_details.rb
|
|
62
63
|
- lib/geocoder/lookups/google_premier.rb
|
|
63
64
|
- lib/geocoder/lookups/here.rb
|
|
65
|
+
- lib/geocoder/lookups/mapbox.rb
|
|
64
66
|
- lib/geocoder/lookups/mapquest.rb
|
|
65
67
|
- lib/geocoder/lookups/maxmind.rb
|
|
66
68
|
- lib/geocoder/lookups/maxmind_geoip2.rb
|
|
@@ -95,10 +97,12 @@ files:
|
|
|
95
97
|
- lib/geocoder/results/geocoder_us.rb
|
|
96
98
|
- lib/geocoder/results/geocodio.rb
|
|
97
99
|
- lib/geocoder/results/geoip2.rb
|
|
100
|
+
- lib/geocoder/results/geoportail_lu.rb
|
|
98
101
|
- lib/geocoder/results/google.rb
|
|
99
102
|
- lib/geocoder/results/google_places_details.rb
|
|
100
103
|
- lib/geocoder/results/google_premier.rb
|
|
101
104
|
- lib/geocoder/results/here.rb
|
|
105
|
+
- lib/geocoder/results/mapbox.rb
|
|
102
106
|
- lib/geocoder/results/mapquest.rb
|
|
103
107
|
- lib/geocoder/results/maxmind.rb
|
|
104
108
|
- lib/geocoder/results/maxmind_geoip2.rb
|
|
@@ -146,7 +150,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
146
150
|
version: '0'
|
|
147
151
|
requirements: []
|
|
148
152
|
rubyforge_project:
|
|
149
|
-
rubygems_version: 2.
|
|
153
|
+
rubygems_version: 2.5.1
|
|
150
154
|
signing_key:
|
|
151
155
|
specification_version: 4
|
|
152
156
|
summary: Complete geocoding solution for Ruby.
|