geocoder 1.2.11 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5648fa768c84d9f5af64d9c377423d8c03567692
4
- data.tar.gz: 670746d024b95d37411459e09bdffe69a8e50f65
3
+ metadata.gz: e7a2b3e33175d20be86a8eaf6c74d6178bc71991
4
+ data.tar.gz: d0dc03b689fbc43f16ae9395c7f743a3dd7876bd
5
5
  SHA512:
6
- metadata.gz: 214ae40b18a556baca80fc3531cadd8250f87c22bd1c4f3e5d2227f3297754a13b799b40bb7833e02a9663162e85e427b48800f418211ad71243a1f6f204acfa
7
- data.tar.gz: a1a399fbb540520d9e6ae4ffb4d4fa72318388f07746203340b972b5670753129ae52160f8673298a9a2732b31224761d88c00156ef954043c3332fdbc2634cf
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.0.x, 2.1.x, JRuby, and Rubinius.
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.
@@ -47,7 +47,7 @@ Your model must have two attributes (database columns) for storing latitude and
47
47
  rails generate migration AddLatitudeAndLongitudeToModel latitude:float longitude:float
48
48
  rake db:migrate
49
49
 
50
- For reverse geocoding your model must provide a method that returns an address. This can be a single attribute, but it can also be a method that returns a string assembled from different attributes (eg: `city`, `state`, and `country`).
50
+ For geocoding your model must provide a method that returns an address. This can be a single attribute, but it can also be a method that returns a string assembled from different attributes (eg: `city`, `state`, and `country`).
51
51
 
52
52
  Next, your model must tell Geocoder which method returns your object's geocodable address:
53
53
 
@@ -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?
@@ -294,7 +308,7 @@ Every `Geocoder::Result` object, `result`, provides the following data:
294
308
 
295
309
  * `result.latitude` - float
296
310
  * `result.longitude` - float
297
- * `result.coordinates` - array of the above two
311
+ * `result.coordinates` - array of the above two in the form of `[lat,lon]`
298
312
  * `result.address` - string
299
313
  * `result.city` - string
300
314
  * `result.state` - string
@@ -351,6 +365,10 @@ Please see the [source code for each lookup](https://github.com/alexreisner/geoc
351
365
  # with Nominatim:
352
366
  Geocoder.search("Paris", :params => {:countrycodes => "gb,de,fr,es,us"})
353
367
 
368
+ Or, to search within a particular region with Google:
369
+
370
+ Geocoder.search("...", :params => {:region => "..."})
371
+
354
372
  You can also configure multiple geocoding services at once, like this:
355
373
 
356
374
  Geocoder.configure(
@@ -464,9 +482,9 @@ The [Google Places Details API](https://developers.google.com/places/documentati
464
482
 
465
483
  #### Yandex (`:yandex`)
466
484
 
467
- * **API key**: none
485
+ * **API key**: optional, but without it lookup is territorially limited
468
486
  * **Quota**: 25000 requests / day
469
- * **Region**: world
487
+ * **Region**: world with API key. Otherwise restricted to Russia, Ukraine, Belarus, Kazakhstan, Georgia, Abkhazia, South Ossetia, Armenia, Azerbaijan, Moldova, Turkmenistan, Tajikistan, Uzbekistan, Kyrgyzstan and Turkey
470
488
  * **SSL support**: HTTPS only
471
489
  * **Languages**: Russian, Belarusian, Ukrainian, English, Turkish (only for maps of Turkey)
472
490
  * **Documentation**: http://api.yandex.com.tr/maps/doc/intro/concepts/intro.xml
@@ -496,10 +514,24 @@ The [Google Places Details API](https://developers.google.com/places/documentati
496
514
  * **Terms of Service**: http://geocoder.us/terms.shtml
497
515
  * **Limitations**: ?
498
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
+
499
531
  #### Mapquest (`:mapquest`)
500
532
 
501
533
  * **API key**: required
502
- * **Key signup**: http://developer.mapquest.com/web/products/open
534
+ * **Key signup**: https://developer.mapquest.com/plans
503
535
  * **Quota**: ?
504
536
  * **HTTP Headers**: when using the licensed API you can specify a referer like so:
505
537
  `Geocoder.configure(:http_headers => { "Referer" => "http://foo.com" })`
@@ -605,6 +637,16 @@ Data Science Toolkit provides an API whose reponse format is like Google's but w
605
637
  * **Terms of Service**: http://www.itella.fi/liitteet/palvelutjatuotteet/yhteystietopalvelut/Postinumeropalvelut-Palvelukuvausjakayttoehdot.pdf
606
638
  * **Limitations**: ?
607
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**: ?
608
650
 
609
651
  #### PostcodeAnywhere Uk (`:postcode_anywhere_uk`)
610
652
 
@@ -649,14 +691,15 @@ This uses the PostcodeAnywhere UK Geocode service, this will geocode any string
649
691
 
650
692
  #### Telize (`:telize`)
651
693
 
652
- * **API key**: none
653
- * **Quota**: none
694
+ * **API key**: required
695
+ * **Quota**: 1,000/day for $7/mo through 100,000/day for $100/mo
654
696
  * **Region**: world
655
- * **SSL support**: no
697
+ * **SSL support**: yes
656
698
  * **Languages**: English
657
- * **Documentation**: http://www.telize.com/
699
+ * **Documentation**: https://market.mashape.com/fcambus/telize
658
700
  * **Terms of Service**: ?
659
701
  * **Limitations**: ?
702
+ * **Notes**: To use Telize set `Geocoder.configure(:ip_lookup => :telize, :api_key => "your_api_key")`.
660
703
 
661
704
  #### MaxMind Legacy Web Services (`:maxmind`)
662
705
 
@@ -891,6 +934,9 @@ Now, any time Geocoder looks up "New York, NY" its results array will contain on
891
934
  ]
892
935
  )
893
936
 
937
+ Note:
938
+ Keys must be strings not symbols when calling `add_stub` or `set_default_stub`. For example `'latitude' =>` not `:latitude =>`.
939
+
894
940
 
895
941
  Command Line Interface
896
942
  ----------------------
@@ -1066,7 +1112,9 @@ If anyone has a more elegant solution to this problem I am very interested in se
1066
1112
  Contributing
1067
1113
  ------------
1068
1114
 
1069
- Contributions are welcome via pull requests on Github. Please respect the following guidelines:
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:
1070
1118
 
1071
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.
1072
1120
  * Do not commit changes to files that are irrelevant to your feature or bugfix (eg: `.gitignore`).
@@ -1075,6 +1123,7 @@ Contributions are welcome via pull requests on Github. Please respect the follow
1075
1123
  * Remember: Geocoder needs to run outside of Rails. Don't assume things like ActiveSupport are available.
1076
1124
  * Be willing to accept criticism and work on improving your code; Geocoder is used by thousands of developers and care must be taken not to introduce bugs.
1077
1125
  * Be aware that the pull request review process is not immediate, and is generally proportional to the size of the pull request.
1126
+ * If your pull request is merged, please do not ask for an immediate release of the gem. There are many factors contributing to when releases occur (remember that they affect thousands of apps with Geocoder in their Gemfiles). If necessary, please install from the Github source until the next official release.
1078
1127
 
1079
1128
 
1080
1129
  Copyright (c) 2009-15 Alex Reisner, released under the MIT license
@@ -1,21 +1,21 @@
1
1
  Geocoder.configure(
2
- # geocoding options
3
- # :timeout => 3, # geocoding service timeout (secs)
4
- # :lookup => :google, # name of geocoding service (symbol)
5
- # :language => :en, # ISO-639 language code
6
- # :use_https => false, # use HTTPS for lookup requests? (if supported)
7
- # :http_proxy => nil, # HTTP proxy server (user:pass@host:port)
8
- # :https_proxy => nil, # HTTPS proxy server (user:pass@host:port)
9
- # :api_key => nil, # API key for geocoding service
10
- # :cache => nil, # cache object (must respond to #[], #[]=, and #keys)
11
- # :cache_prefix => "geocoder:", # prefix (string) to use for all cache keys
2
+ # Geocoding options
3
+ # timeout: 3, # geocoding service timeout (secs)
4
+ # lookup: :google, # name of geocoding service (symbol)
5
+ # language: :en, # ISO-639 language code
6
+ # use_https: false, # use HTTPS for lookup requests? (if supported)
7
+ # http_proxy: nil, # HTTP proxy server (user:pass@host:port)
8
+ # https_proxy: nil, # HTTPS proxy server (user:pass@host:port)
9
+ # api_key: nil, # API key for geocoding service
10
+ # cache: nil, # cache object (must respond to #[], #[]=, and #keys)
11
+ # cache_prefix: 'geocoder:', # prefix (string) to use for all cache keys
12
12
 
13
- # exceptions that should not be rescued by default
13
+ # Exceptions that should not be rescued by default
14
14
  # (if you want to implement custom error handling);
15
15
  # supports SocketError and TimeoutError
16
- # :always_raise => [],
16
+ # always_raise: [],
17
17
 
18
- # calculation options
19
- # :units => :mi, # :km for kilometers or :mi for miles
20
- # :distances => :linear # :spherical or :linear
18
+ # Calculation options
19
+ # units: :mi, # :km for kilometers or :mi for miles
20
+ # distances: :linear # :spherical or :linear
21
21
  )
@@ -237,11 +237,14 @@ module Geocoder
237
237
  #
238
238
  # * <tt>:units</tt> - <tt>:mi</tt> or <tt>:km</tt>
239
239
  # Use Geocoder.configure(:units => ...) to configure default units.
240
+ # * <tt>:seed</tt> - The seed for the random number generator
240
241
  def random_point_near(center, radius, options = {})
241
242
 
242
243
  # set default options
243
244
  options[:units] ||= Geocoder.config.units
244
245
 
246
+ random = Random.new(options[:seed] || Random.new_seed)
247
+
245
248
  # convert to coordinate arrays
246
249
  center = extract_coordinates(center)
247
250
 
@@ -249,18 +252,18 @@ module Geocoder
249
252
  max_degree_delta = 360.0 * (radius / earth_circumference)
250
253
 
251
254
  # random bearing in radians
252
- theta = 2 * Math::PI * rand
255
+ theta = 2 * Math::PI * random.rand
253
256
 
254
257
  # random radius, use the square root to ensure a uniform
255
258
  # distribution of points over the circle
256
- r = Math.sqrt(rand) * max_degree_delta
259
+ r = Math.sqrt(random.rand) * max_degree_delta
257
260
 
258
261
  delta_lat, delta_long = [r * Math.cos(theta), r * Math.sin(theta)]
259
262
  [center[0] + delta_lat, center[1] + delta_long]
260
263
  end
261
264
 
262
265
  ##
263
- # Given a start point, distance, and heading (in degrees), provides
266
+ # Given a start point, heading (in degrees), and distance, provides
264
267
  # an endpoint.
265
268
  # The starting point is given in the same way that points are given to all
266
269
  # Geocoder methods that accept points as arguments. It can be:
@@ -125,6 +125,5 @@ module Geocoder
125
125
  end
126
126
  EOS
127
127
  end.join("\n\n"))
128
-
129
128
  end
130
129
  end
@@ -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
@@ -190,7 +190,7 @@ module Geocoder
190
190
  else
191
191
  JSON.parse(data)
192
192
  end
193
- rescue => err
193
+ rescue
194
194
  raise_error(ResponseParseError.new(data)) or Geocoder.log(:warn, "Geocoding API's response was not valid JSON: #{data}")
195
195
  end
196
196
 
@@ -283,7 +283,7 @@ module Geocoder
283
283
  end
284
284
  client.request(req)
285
285
  end
286
- rescue Net::OpenTimeout, Net::ReadTimeout
286
+ rescue Timeout::Error
287
287
  raise Geocoder::LookupTimeout
288
288
  end
289
289
 
@@ -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
- if @gem_name == 'hive_geoip2'
32
- result = Hive::GeoIP2.lookup(query.to_s, configuration[:file].to_s)
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 LIMIT 1)"
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}://www.telize.com/geoip/#{query.sanitized_text}"
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
- [:http]
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
- address = reverse_geocode? ? 'Address' : 'Match_addr'
8
- attributes[address]
7
+ address_key = reverse_geocode? ? 'Address' : 'Match_addr'
8
+ attributes[address_key]
9
9
  end
10
10
 
11
11
  def city
12
- attributes['City']
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
- country = reverse_geocode? ? "CountryCode" : "Country"
23
- attributes[country]
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('en', '')
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('en','')
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('en','')
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
@@ -120,5 +120,13 @@ module Geocoder::Result
120
120
  def precision
121
121
  geometry['location_type'] if geometry
122
122
  end
123
+
124
+ def partial_match
125
+ @data['partial_match']
126
+ end
127
+
128
+ def place_id
129
+ @data['place_id']
130
+ end
123
131
  end
124
132
  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
+
@@ -26,6 +26,10 @@ module Geocoder::Result
26
26
  @data['adminArea3']
27
27
  end
28
28
 
29
+ def county
30
+ @data['adminArea4']
31
+ end
32
+
29
33
  alias_method :state_code, :state
30
34
 
31
35
  #FIXME: these might not be right, unclear with MQ documentation
@@ -23,10 +23,6 @@ module Geocoder::Result
23
23
  @data['country_name']
24
24
  end
25
25
 
26
- def country_code
27
- @data['country_code']
28
- end
29
-
30
26
  def postal_code
31
27
  @data['postcode']
32
28
  end
@@ -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).
@@ -1,3 +1,3 @@
1
1
  module Geocoder
2
- VERSION = "1.2.11"
2
+ VERSION = "1.3.0"
3
3
  end
@@ -21,7 +21,7 @@ module Geocoder
21
21
  end
22
22
 
23
23
  def insert(package, dir = "tmp")
24
- data_files(package).each do |filepath,table|
24
+ data_files(package, dir).each do |filepath,table|
25
25
  print "Resetting table #{table}..."
26
26
  ActiveRecord::Base.connection.execute("DELETE FROM #{table}")
27
27
  puts "done"
@@ -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
- klass.not_geocoded.find_each(batch_size: batch) do |obj|
12
- obj.geocode; obj.save
13
- sleep(sleep_timer.to_f) unless sleep_timer.nil?
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.11
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: 2015-09-10 00:00:00.000000000 Z
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.4.5
153
+ rubygems_version: 2.5.1
150
154
  signing_key:
151
155
  specification_version: 4
152
156
  summary: Complete geocoding solution for Ruby.