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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0ac038477cf014a8e62f7fec0e684f851cb55bbb
4
- data.tar.gz: 3abbf824220bd221ecd033e75c7c14a8ece6057a
3
+ metadata.gz: 2184f181fb0c642d0cc02774bcd2208e325b8dc8
4
+ data.tar.gz: 7b0da04b5c05f0b9afe9182e00ee6099a83adc45
5
5
  SHA512:
6
- metadata.gz: 42d47442e4839e84bcb0d98c28591ddeb1df2c63d19b1400736c1f90523f32e84b80990efb714551592a8614704a234c24533398c81c48052654aaf2f83d3d7f
7
- data.tar.gz: b51c9a638a256db67d025e8ab67001fcb7a482dcae9206931b957952aa215e27c635044c829eecd20043dd901b5a683248155a403baa5f1057954c1711439c3d
6
+ metadata.gz: fd8d36a0c7fb2cabda97f03baa19c68d4106bca4e5c8eb1e987ac0156393fa1c05f67d235020ca332cd3557c77411cbfd8d601add3b8820dcfffd0359a30a19a
7
+ data.tar.gz: 05a0eb39a8f575083f3ff20fbe93c209afcb533313c531bee25462b1e6f25bed6da7f2d47ffcb296923d933786249309d8f07e66cb23d0e271da9cf7962c53c8
@@ -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.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.
@@ -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**: none
657
- * **Quota**: none
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**: no
687
+ * **SSL support**: yes
660
688
  * **Languages**: English
661
- * **Documentation**: http://www.telize.com/
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
 
@@ -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
@@ -32,6 +32,7 @@ module Geocoder
32
32
  :geocoder_us,
33
33
  :yandex,
34
34
  :nominatim,
35
+ :mapbox,
35
36
  :mapquest,
36
37
  :opencagedata,
37
38
  :ovi,
@@ -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
- 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
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}://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
@@ -9,7 +9,11 @@ module Geocoder::Result
9
9
  end
10
10
 
11
11
  def city
12
- attributes['City']
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('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,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
@@ -1,3 +1,3 @@
1
1
  module Geocoder
2
- VERSION = "1.2.12"
2
+ VERSION = "1.2.13"
3
3
  end
@@ -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.12
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-10-29 00:00:00.000000000 Z
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