geocoder 1.3.4 → 1.3.5

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: d790b89d4257ea08df5cc44f42b141e528ab807b
4
- data.tar.gz: d9b4a0cbe6b3f4c709040e9b784cb8e605e5b9ce
3
+ metadata.gz: b7f44c3ea3ee0cecd7dfaa73c96393864f578c01
4
+ data.tar.gz: 39a47431d911edda32bd8182cb051c5af49dbad0
5
5
  SHA512:
6
- metadata.gz: ecfc4e757b64650f23cb1cbba2aa7294395c5cb1deff2e30f52639951c7392104c4cca299655062558540147ffab088a4d66de5da37cde17e2c0de7cfc60ab61
7
- data.tar.gz: 6e60f809ce62c62bbe05522ceb1adeb5f8e6fbbff9e6eea61d934d1362afdc8123525ca30674c000f92b440182a3e6b038b0389a37128dd5a9d5e5bfb715c33b
6
+ metadata.gz: d463d7fd2cfad2c24e5d2c7a37cb5e11285a07291f6dd0a758547727beb0651d06c2165455794e9ce26229ec067a3084dd25b4a28f11b1bc18ea9992b7164795
7
+ data.tar.gz: e17a5c5e8dff69d558f56a1c4510988c68df7c538fb42897b43f95b9b2a410a3e19c83b72eb44af176c09879c3fc5f6dcb49dc6d41a378c734b070a6d4af18af
@@ -3,10 +3,19 @@ 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.5 (2016 May 27)
7
+ -------------------
8
+ * Fix Rails 5 ActionDispatch include issue (thanks github.com/alepore).
9
+ * Fix bug that caused :esri lookup to ignore certain configured parameters (thanks github.com/aaronpk).
10
+ * Add reverse geocoding support to :pelias/:mapzen (thanks github.com/shinyaK14).
11
+ * Add support for custom host with :telize (thanks github.com/jwaldrip).
12
+ * Change the way :esri lookup generates cache keys for improved performance (thanks github.com/aaronpk).
13
+ * Improve HTTPS connections with :google (thanks github.com/jlhonora).
14
+
6
15
  1.3.4 (2016 Apr 14)
7
16
  -------------------
8
17
  * Update :freegeoip host (old one is down).
9
- * Add ip-api.com IP address lookup (thanks github.com/piotrgorecki).
18
+ * Add IP lookup :ipapi_com (thanks github.com/piotrgorecki).
10
19
 
11
20
  1.3.3 (2016 Apr 4)
12
21
  ------------------
data/README.md CHANGED
@@ -11,7 +11,7 @@ Compatibility
11
11
 
12
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
- * 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).
14
+ * Supports Rails 3, 4, and 5. 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.
16
16
 
17
17
 
@@ -555,15 +555,15 @@ The [Google Places Details API](https://developers.google.com/places/documentati
555
555
 
556
556
  #### ESRI (`:esri`)
557
557
 
558
- * **API key**: none
558
+ * **API key**: optional (set `Geocoder.configure(:esri => {:api_key => ["client_id", "client_secret"]})`)
559
559
  * **Quota**: Required for some scenarios (see Terms of Service)
560
560
  * **Region**: world
561
561
  * **SSL support**: yes
562
562
  * **Languages**: English
563
- * **Documentation**: http://resources.arcgis.com/en/help/arcgis-online-geocoding-rest-api/
563
+ * **Documentation**: https://developers.arcgis.com/rest/geocode/api-reference/overview-world-geocoding-service.htm
564
564
  * **Terms of Service**: http://www.esri.com/legal/software-license
565
- * **Limitations**: ?
566
- * **Notes**: You can specify which projection you want to use by setting, for example: `Geocoder.configure(:esri => {:outSR => 102100})`.
565
+ * **Limitations**: Requires API key if results will be stored. Using API key will also remove rate limit.
566
+ * **Notes**: You can specify which projection you want to use by setting, for example: `Geocoder.configure(:esri => {:outSR => 102100})`. If you will store results, set the flag and provide API key: `Geocoder.configure(:esri => {:api_key => ["client_id", "client_secret"], :for_storage => true})`. If you want to, you can also supply an ESRI token directly: `Geocoder.configure(:esri => {:token => Geocoder::EsriToken.new('TOKEN', Time.now + 1.day})`
567
567
 
568
568
  #### Mapzen (`:mapzen`)
569
569
 
@@ -38,6 +38,14 @@ module Geocoder
38
38
  data
39
39
  end
40
40
 
41
+ ##
42
+ # Merge the given hash into a lookup's existing configuration.
43
+ #
44
+ def self.merge_into_lookup_config(lookup_name, options)
45
+ base = Geocoder.config[lookup_name]
46
+ Geocoder.configure(lookup_name => base.merge(options))
47
+ end
48
+
41
49
  class Configuration
42
50
  include Singleton
43
51
 
@@ -0,0 +1,38 @@
1
+ module Geocoder
2
+ class EsriToken
3
+ attr_accessor :value, :expires_at
4
+
5
+ def initialize(value, expires_at)
6
+ @value = value
7
+ @expires_at = expires_at
8
+ end
9
+
10
+ def to_s
11
+ @value
12
+ end
13
+
14
+ def active?
15
+ @expires_at > Time.now
16
+ end
17
+
18
+ def self.generate_token(client_id, client_secret, expires=1440)
19
+ # creates a new token that will expire in 1 day by default
20
+ getToken = Net::HTTP.post_form URI('https://www.arcgis.com/sharing/rest/oauth2/token'),
21
+ f: 'json',
22
+ client_id: client_id,
23
+ client_secret: client_secret,
24
+ grant_type: 'client_credentials',
25
+ expiration: expires # (minutes) max: 20160, default: 1 day
26
+
27
+ response = JSON.parse(getToken.body)
28
+
29
+ if response['error']
30
+ Geocoder.log(:warn, response['error'])
31
+ else
32
+ token_value = response['access_token']
33
+ expires_at = Time.now + (expires * 60)
34
+ new(token_value, expires_at)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -274,6 +274,7 @@ module Geocoder
274
274
  uri = URI.parse(query_url(query))
275
275
  Geocoder.log(:debug, "Geocoder: HTTP request being made for #{uri.to_s}")
276
276
  http_client.start(uri.host, uri.port, use_ssl: use_ssl?, open_timeout: configuration.timeout, read_timeout: configuration.timeout) do |client|
277
+ configure_ssl!(client) if use_ssl?
277
278
  req = Net::HTTP::Get.new(uri.request_uri, configuration.http_headers)
278
279
  if configuration.basic_auth[:user] and configuration.basic_auth[:password]
279
280
  req.basic_auth(
@@ -297,6 +298,8 @@ module Geocoder
297
298
  end
298
299
  end
299
300
 
301
+ def configure_ssl!(client); end
302
+
300
303
  def check_api_key_configuration!(query)
301
304
  key_parts = query.lookup.required_api_key_parts
302
305
  if key_parts.size > Array(configuration.api_key).size
@@ -1,5 +1,6 @@
1
1
  require 'geocoder/lookups/base'
2
2
  require "geocoder/results/esri"
3
+ require 'geocoder/esri_token'
3
4
 
4
5
  module Geocoder::Lookup
5
6
  class Esri < Base
@@ -9,14 +10,16 @@ module Geocoder::Lookup
9
10
  end
10
11
 
11
12
  def query_url(query)
12
- search_keyword = query.reverse_geocode? ? "reverseGeocode" : "find"
13
-
14
- "#{protocol}://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/#{search_keyword}?" +
15
- url_query_string(query)
13
+ base_query_url(query) + url_query_string(query)
16
14
  end
17
15
 
18
16
  private # ---------------------------------------------------------------
19
17
 
18
+ def base_query_url(query)
19
+ action = query.reverse_geocode? ? "reverseGeocode" : "find"
20
+ "#{protocol}://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/#{action}?"
21
+ end
22
+
20
23
  def results(query)
21
24
  return [] unless doc = fetch_data(query)
22
25
 
@@ -31,6 +34,17 @@ module Geocoder::Lookup
31
34
  end
32
35
  end
33
36
 
37
+ def cache_key(query)
38
+ base_query_url(query) + hash_to_query(cache_key_params(query))
39
+ end
40
+
41
+ def cache_key_params(query)
42
+ # omit api_key and token because they may vary among requests
43
+ query_url_params(query).reject do |key,value|
44
+ [:api_key, :token].include?(key)
45
+ end
46
+ end
47
+
34
48
  def query_url_params(query)
35
49
  params = {
36
50
  :f => "pjson",
@@ -41,8 +55,31 @@ module Geocoder::Lookup
41
55
  else
42
56
  params[:text] = query.sanitized_text
43
57
  end
58
+ params[:token] = token
59
+ params[:forStorage] = configuration[:for_storage] if configuration[:for_storage]
60
+ params[:sourceCountry] = configuration[:source_country] if configuration[:source_country]
44
61
  params.merge(super)
45
62
  end
46
63
 
64
+ def token
65
+ create_and_save_token! if !valid_token_configured? and configuration.api_key
66
+ configuration[:token].to_s unless configuration[:token].nil?
67
+ end
68
+
69
+ def valid_token_configured?
70
+ !configuration[:token].nil? and configuration[:token].active?
71
+ end
72
+
73
+ def create_and_save_token!
74
+ save_token!(create_token)
75
+ end
76
+
77
+ def create_token
78
+ Geocoder::EsriToken.generate_token(*configuration.api_key)
79
+ end
80
+
81
+ def save_token!(token_instance)
82
+ Geocoder.merge_into_lookup_config(:esri, token: token_instance)
83
+ end
47
84
  end
48
85
  end
@@ -27,6 +27,17 @@ module Geocoder::Lookup
27
27
 
28
28
  private # ---------------------------------------------------------------
29
29
 
30
+ def configure_ssl!(client)
31
+ client.instance_eval {
32
+ @ssl_context = OpenSSL::SSL::SSLContext.new
33
+ options = OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3
34
+ if OpenSSL::SSL.const_defined?('OP_NO_COMPRESSION')
35
+ options |= OpenSSL::SSL::OP_NO_COMPRESSION
36
+ end
37
+ @ssl_context.set_params({options: options})
38
+ }
39
+ end
40
+
30
41
  def valid_response?(response)
31
42
  json = parse_json(response.body)
32
43
  status = json["status"] if json
@@ -65,6 +76,9 @@ module Geocoder::Lookup
65
76
  unless (components = query.options[:components]).nil?
66
77
  params[:components] = components.is_a?(Array) ? components.join("|") : components
67
78
  end
79
+ unless (result_type = query.options[:result_type]).nil?
80
+ params[:result_type] = result_type.is_a?(Array) ? result_type.join("|") : result_type
81
+ end
68
82
  params
69
83
  end
70
84
 
@@ -9,7 +9,8 @@ module Geocoder::Lookup
9
9
  end
10
10
 
11
11
  def query_url(query)
12
- url_ = "#{protocol}://ip-api.com/json/#{query.sanitized_text}"
12
+ domain = configuration.api_key ? "pro.ip-api.com" : "ip-api.com"
13
+ url_ = "#{protocol}://#{domain}/json/#{query.sanitized_text}"
13
14
 
14
15
  if (params = url_query_string(query)) && !params.empty?
15
16
  url_ + "?" + params
@@ -29,17 +30,32 @@ module Geocoder::Lookup
29
30
 
30
31
  private
31
32
 
33
+ def parse_raw_data(raw_data)
34
+ if raw_data.chomp == "invalid key"
35
+ invalid_key_result
36
+ else
37
+ super(raw_data)
38
+ end
39
+ end
40
+
32
41
  def results(query)
33
42
  return [reserved_result(query.text)] if query.loopback_ip_address?
34
43
 
35
- (doc = fetch_data(query)) ? [doc] : []
44
+ return [] unless doc = fetch_data(query)
45
+
46
+ if doc["message"] == "invalid key"
47
+ raise_error(Geocoder::InvalidApiKey) || Geocoder.log(:warn, "Invalid API key.")
48
+ return []
49
+ else
50
+ return [doc]
51
+ end
36
52
  end
37
53
 
38
54
  def reserved_result(query)
39
55
  {
40
56
  "message" => "reserved range",
41
57
  "query" => query,
42
- "status" => fail,
58
+ "status" => "fail",
43
59
  "ip" => query,
44
60
  "city" => "",
45
61
  "region_code" => "",
@@ -53,6 +69,12 @@ module Geocoder::Lookup
53
69
  }
54
70
  end
55
71
 
72
+ def invalid_key_result
73
+ {
74
+ "message" => "invalid key"
75
+ }
76
+ end
77
+
56
78
  def query_url_params(query)
57
79
  params = {}
58
80
  params.merge!(fields: configuration[:fields]) if configuration.has_key?(:fields)
@@ -23,11 +23,19 @@ module Geocoder::Lookup
23
23
  private
24
24
 
25
25
  def query_url_params(query)
26
- {
26
+ params = {
27
27
  api_key: configuration.api_key,
28
- text: query.text,
29
28
  size: 1
30
- }.merge(super(query))
29
+ }.merge(super)
30
+
31
+ if query.reverse_geocode?
32
+ lat,lon = query.coordinates
33
+ params[:'point.lat'] = lat
34
+ params[:'point.lon'] = lon
35
+ else
36
+ params[:text] = query.text
37
+ end
38
+ params
31
39
  end
32
40
 
33
41
  def results(query)
@@ -9,15 +9,22 @@ module Geocoder::Lookup
9
9
  end
10
10
 
11
11
  def required_api_key_parts
12
- ["key"]
12
+ configuration[:host] ? [] : ["key"]
13
13
  end
14
14
 
15
15
  def query_url(query)
16
- "#{protocol}://telize-v1.p.mashape.com/geoip/#{query.sanitized_text}?mashape-key=#{api_key}"
16
+ if configuration[:host]
17
+ "#{protocol}://#{configuration[:host]}/geoip/#{query.sanitized_text}"
18
+ else
19
+ "#{protocol}://telize-v1.p.mashape.com/geoip/#{query.sanitized_text}?mashape-key=#{api_key}"
20
+ end
17
21
  end
18
22
 
19
23
  def supported_protocols
20
- [:https]
24
+ [].tap do |array|
25
+ array << :https
26
+ array << :http if configuration[:host]
27
+ end
21
28
  end
22
29
 
23
30
  private # ---------------------------------------------------------------
@@ -43,5 +50,6 @@ module Geocoder::Lookup
43
50
  def api_key
44
51
  configuration.api_key
45
52
  end
53
+
46
54
  end
47
55
  end
@@ -78,6 +78,6 @@ module Geocoder
78
78
  end
79
79
  end
80
80
 
81
- if defined?(Rack) and defined?(Rack::Request)
82
- Rack::Request.send :include, Geocoder::Request
81
+ if defined?(ActionDispatch::Request)
82
+ ActionDispatch::Request.include Geocoder::Request
83
83
  end
@@ -9,15 +9,9 @@ module Geocoder
9
9
  end
10
10
 
11
11
  def coordinates
12
- [latitude, longitude]
13
- end
14
-
15
- def latitude
16
- data.fetch('location', {}).fetch('latitude', 0.0)
17
- end
18
-
19
- def longitude
20
- data.fetch('location', {}).fetch('longitude', 0.0)
12
+ %w[latitude longitude].map do |l|
13
+ data.fetch('location', {}).fetch(l, 0.0)
14
+ end
21
15
  end
22
16
 
23
17
  def city
@@ -3,14 +3,6 @@ require 'geocoder/results/base'
3
3
  module Geocoder::Result
4
4
  class IpapiCom < Base
5
5
 
6
- def latitude
7
- lat
8
- end
9
-
10
- def longitude
11
- lon
12
- end
13
-
14
6
  def coordinates
15
7
  [lat, lon]
16
8
  end
@@ -7,16 +7,8 @@ module Geocoder::Result
7
7
  "#{city} #{postal_code}, #{country}".sub(/^[ ,]*/, "")
8
8
  end
9
9
 
10
- def latitude
11
- @data['loc'].split(',')[0].to_f
12
- end
13
-
14
- def longitude
15
- @data['loc'].split(',')[1].to_f
16
- end
17
-
18
10
  def coordinates
19
- [latitude, longitude]
11
+ @data['loc'].split(",").map(&:to_f)
20
12
  end
21
13
 
22
14
  def city
@@ -3,16 +3,8 @@ require 'geocoder/results/base'
3
3
  module Geocoder::Result
4
4
  class Mapbox < Base
5
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
6
  def coordinates
15
- [latitude, longitude]
7
+ @data["geometry"]["coordinates"].reverse.map(&:to_f)
16
8
  end
17
9
 
18
10
  def place_name
@@ -2,16 +2,9 @@ require 'geocoder/results/base'
2
2
 
3
3
  module Geocoder::Result
4
4
  class Mapquest < Base
5
- def latitude
6
- @data["latLng"]["lat"]
7
- end
8
-
9
- def longitude
10
- @data["latLng"]["lng"]
11
- end
12
5
 
13
6
  def coordinates
14
- [latitude, longitude]
7
+ %w[lat lng].map{ |l| @data["latLng"][l] }
15
8
  end
16
9
 
17
10
  def city
@@ -1,3 +1,3 @@
1
1
  module Geocoder
2
- VERSION = "1.3.4"
2
+ VERSION = "1.3.5"
3
3
  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.3.4
4
+ version: 1.3.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Reisner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-14 00:00:00.000000000 Z
11
+ date: 2016-05-27 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,
@@ -41,6 +41,7 @@ files:
41
41
  - lib/geocoder/cli.rb
42
42
  - lib/geocoder/configuration.rb
43
43
  - lib/geocoder/configuration_hash.rb
44
+ - lib/geocoder/esri_token.rb
44
45
  - lib/geocoder/exceptions.rb
45
46
  - lib/geocoder/ip_address.rb
46
47
  - lib/geocoder/kernel_logger.rb
@@ -157,7 +158,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
157
158
  version: '0'
158
159
  requirements: []
159
160
  rubyforge_project:
160
- rubygems_version: 2.4.5
161
+ rubygems_version: 2.5.1
161
162
  signing_key:
162
163
  specification_version: 4
163
164
  summary: Complete geocoding solution for Ruby.