geocoder 1.5.0 → 1.6.1

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.
Files changed (52) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +23 -2
  3. data/LICENSE +1 -1
  4. data/README.md +15 -17
  5. data/examples/autoexpire_cache_redis.rb +2 -0
  6. data/lib/geocoder/calculations.rb +1 -1
  7. data/lib/geocoder/ip_address.rb +13 -0
  8. data/lib/geocoder/lookup.rb +6 -4
  9. data/lib/geocoder/lookups/baidu_ip.rb +1 -1
  10. data/lib/geocoder/lookups/ban_data_gouv_fr.rb +13 -0
  11. data/lib/geocoder/lookups/base.rb +7 -2
  12. data/lib/geocoder/lookups/bing.rb +2 -1
  13. data/lib/geocoder/lookups/esri.rb +38 -13
  14. data/lib/geocoder/lookups/freegeoip.rb +7 -7
  15. data/lib/geocoder/lookups/here.rb +28 -22
  16. data/lib/geocoder/lookups/ip2location.rb +7 -14
  17. data/lib/geocoder/lookups/ipapi_com.rb +2 -1
  18. data/lib/geocoder/lookups/ipdata_co.rb +5 -4
  19. data/lib/geocoder/lookups/ipgeolocation.rb +51 -0
  20. data/lib/geocoder/lookups/ipinfo_io.rb +2 -11
  21. data/lib/geocoder/lookups/ipregistry.rb +68 -0
  22. data/lib/geocoder/lookups/ipstack.rb +2 -2
  23. data/lib/geocoder/lookups/maxmind.rb +2 -2
  24. data/lib/geocoder/lookups/maxmind_geoip2.rb +4 -7
  25. data/lib/geocoder/lookups/osmnames.rb +57 -0
  26. data/lib/geocoder/lookups/pelias.rb +2 -3
  27. data/lib/geocoder/lookups/pickpoint.rb +1 -1
  28. data/lib/geocoder/lookups/pointpin.rb +3 -3
  29. data/lib/geocoder/lookups/smarty_streets.rb +13 -3
  30. data/lib/geocoder/lookups/telize.rb +2 -2
  31. data/lib/geocoder/lookups/tencent.rb +59 -0
  32. data/lib/geocoder/lookups/yandex.rb +2 -2
  33. data/lib/geocoder/query.rb +14 -0
  34. data/lib/geocoder/railtie.rb +1 -1
  35. data/lib/geocoder/results/baidu.rb +0 -4
  36. data/lib/geocoder/results/ban_data_gouv_fr.rb +1 -1
  37. data/lib/geocoder/results/here.rb +4 -1
  38. data/lib/geocoder/results/ipgeolocation.rb +59 -0
  39. data/lib/geocoder/results/ipregistry.rb +308 -0
  40. data/lib/geocoder/results/osmnames.rb +56 -0
  41. data/lib/geocoder/results/smarty_streets.rb +48 -18
  42. data/lib/geocoder/results/tencent.rb +72 -0
  43. data/lib/geocoder/sql.rb +4 -4
  44. data/lib/geocoder/stores/active_record.rb +1 -1
  45. data/lib/geocoder/version.rb +1 -1
  46. data/lib/hash_recursive_merge.rb +1 -2
  47. data/lib/maxmind_database.rb +3 -3
  48. metadata +12 -13
  49. data/lib/geocoder/lookups/geocoder_us.rb +0 -51
  50. data/lib/geocoder/lookups/mapzen.rb +0 -15
  51. data/lib/geocoder/results/geocoder_us.rb +0 -39
  52. data/lib/geocoder/results/mapzen.rb +0 -5
@@ -19,15 +19,16 @@ module Geocoder::Lookup
19
19
  end
20
20
 
21
21
  def query_url_params(query)
22
- {
23
- key: configuration.api_key ? configuration.api_key : "demo",
24
- format: "json",
25
- ip: query.sanitized_text
26
- }.merge(super)
22
+ params = super
23
+ if configuration.has_key?(:package)
24
+ params.merge!(package: configuration[:package])
25
+ end
26
+ params
27
27
  end
28
28
 
29
29
  def results(query)
30
- return [reserved_result(query.text)] if query.loopback_ip_address?
30
+ # don't look up a loopback or private address, just return the stored result
31
+ return [reserved_result(query.text)] if query.internal_ip_address?
31
32
  return [] unless doc = fetch_data(query)
32
33
  if doc["response"] == "INVALID ACCOUNT"
33
34
  raise_error(Geocoder::InvalidApiKey) || Geocoder.log(:warn, "INVALID ACCOUNT")
@@ -62,13 +63,5 @@ module Geocoder::Lookup
62
63
  }
63
64
  end
64
65
 
65
- def query_url_params(query)
66
- params = super
67
- if configuration.has_key?(:package)
68
- params.merge!(package: configuration[:package])
69
- end
70
- params
71
- end
72
-
73
66
  end
74
67
  end
@@ -34,7 +34,8 @@ module Geocoder::Lookup
34
34
  end
35
35
 
36
36
  def results(query)
37
- return [reserved_result(query.text)] if query.loopback_ip_address?
37
+ # don't look up a loopback or private address, just return the stored result
38
+ return [reserved_result(query.text)] if query.internal_ip_address?
38
39
 
39
40
  return [] unless doc = fetch_data(query)
40
41
 
@@ -13,7 +13,9 @@ module Geocoder::Lookup
13
13
  end
14
14
 
15
15
  def query_url(query)
16
- "#{protocol}://#{host}/#{query.sanitized_text}"
16
+ # Ipdata.co requires that the API key be sent as a query parameter.
17
+ # It no longer supports API keys sent as headers.
18
+ "#{protocol}://#{host}/#{query.sanitized_text}?api-key=#{configuration.api_key}"
17
19
  end
18
20
 
19
21
  private # ---------------------------------------------------------------
@@ -23,9 +25,8 @@ module Geocoder::Lookup
23
25
  end
24
26
 
25
27
  def results(query)
26
- Geocoder.configure(:ipdata_co => {:http_headers => { "api-key" => configuration.api_key }}) if configuration.api_key
27
- # don't look up a loopback address, just return the stored result
28
- return [reserved_result(query.text)] if query.loopback_ip_address?
28
+ # don't look up a loopback or private address, just return the stored result
29
+ return [reserved_result(query.text)] if query.internal_ip_address?
29
30
  # note: Ipdata.co returns plain text on bad request
30
31
  (doc = fetch_data(query)) ? [doc] : []
31
32
  end
@@ -0,0 +1,51 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/ipgeolocation'
3
+
4
+
5
+ module Geocoder::Lookup
6
+ class Ipgeolocation < Base
7
+
8
+ ERROR_CODES = {
9
+ 400 => Geocoder::RequestDenied, # subscription is paused
10
+ 401 => Geocoder::InvalidApiKey, # missing/invalid API key
11
+ 403 => Geocoder::InvalidRequest, # invalid IP address
12
+ 404 => Geocoder::InvalidRequest, # not found
13
+ 423 => Geocoder::InvalidRequest # bogon/reserved IP address
14
+ }
15
+ ERROR_CODES.default = Geocoder::Error
16
+
17
+ def name
18
+ "Ipgeolocation"
19
+ end
20
+
21
+ def supported_protocols
22
+ [:https]
23
+ end
24
+
25
+ private # ----------------------------------------------------------------
26
+
27
+ def base_query_url(query)
28
+ "#{protocol}://api.ipgeolocation.io/ipgeo?"
29
+ end
30
+ def query_url_params(query)
31
+ {
32
+ ip: query.sanitized_text,
33
+ apiKey: configuration.api_key
34
+ }.merge(super)
35
+ end
36
+
37
+ def results(query)
38
+ # don't look up a loopback or private address, just return the stored result
39
+ return [reserved_result(query.text)] if query.internal_ip_address?
40
+ [fetch_data(query)]
41
+ end
42
+
43
+ def reserved_result(ip)
44
+ {
45
+ "ip" => ip,
46
+ "country_name" => "Reserved",
47
+ "country_code2" => "RD"
48
+ }
49
+ end
50
+ end
51
+ end
@@ -8,15 +8,6 @@ module Geocoder::Lookup
8
8
  "Ipinfo.io"
9
9
  end
10
10
 
11
- # HTTPS available only for paid plans
12
- def supported_protocols
13
- if configuration.api_key
14
- [:http, :https]
15
- else
16
- [:http]
17
- end
18
- end
19
-
20
11
  private # ---------------------------------------------------------------
21
12
 
22
13
  def base_query_url(query)
@@ -26,8 +17,8 @@ module Geocoder::Lookup
26
17
  end
27
18
 
28
19
  def results(query)
29
- # don't look up a loopback address, just return the stored result
30
- return [reserved_result(query.text)] if query.loopback_ip_address?
20
+ # don't look up a loopback or private address, just return the stored result
21
+ return [reserved_result(query.text)] if query.internal_ip_address?
31
22
 
32
23
  if !(doc = fetch_data(query)).is_a?(Hash) or doc['error']
33
24
  []
@@ -0,0 +1,68 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/ipregistry'
3
+
4
+ module Geocoder::Lookup
5
+ class Ipregistry < Base
6
+
7
+ ERROR_CODES = {
8
+ 400 => Geocoder::InvalidRequest,
9
+ 401 => Geocoder::InvalidRequest,
10
+ 402 => Geocoder::OverQueryLimitError,
11
+ 403 => Geocoder::InvalidApiKey,
12
+ 451 => Geocoder::RequestDenied,
13
+ 500 => Geocoder::Error
14
+ }
15
+ ERROR_CODES.default = Geocoder::Error
16
+
17
+ def name
18
+ "Ipregistry"
19
+ end
20
+
21
+ def supported_protocols
22
+ [:https, :http]
23
+ end
24
+
25
+ private
26
+
27
+ def base_query_url(query)
28
+ "#{protocol}://#{host}/#{query.sanitized_text}?"
29
+ end
30
+
31
+ def cache_key(query)
32
+ query_url(query)
33
+ end
34
+
35
+ def host
36
+ configuration[:host] || "api.ipregistry.co"
37
+ end
38
+
39
+ def query_url_params(query)
40
+ {
41
+ key: configuration.api_key
42
+ }.merge(super)
43
+ end
44
+
45
+ def results(query)
46
+ # don't look up a loopback or private address, just return the stored result
47
+ return [reserved_result(query.text)] if query.internal_ip_address?
48
+
49
+ return [] unless (doc = fetch_data(query))
50
+
51
+ if (error = doc['error'])
52
+ code = error['code']
53
+ msg = error['message']
54
+ raise_error(ERROR_CODES[code], msg ) || Geocoder.log(:warn, "Ipregistry API error: #{msg}")
55
+ return []
56
+ end
57
+ [doc]
58
+ end
59
+
60
+ def reserved_result(ip)
61
+ {
62
+ "ip" => ip,
63
+ "country_name" => "Reserved",
64
+ "country_code" => "RD"
65
+ }
66
+ end
67
+ end
68
+ end
@@ -34,8 +34,8 @@ module Geocoder::Lookup
34
34
  end
35
35
 
36
36
  def results(query)
37
- # don't look up a loopback address, just return the stored result
38
- return [reserved_result(query.text)] if query.loopback_ip_address?
37
+ # don't look up a loopback or private address, just return the stored result
38
+ return [reserved_result(query.text)] if query.internal_ip_address?
39
39
 
40
40
  return [] unless doc = fetch_data(query)
41
41
 
@@ -57,8 +57,8 @@ module Geocoder::Lookup
57
57
  end
58
58
 
59
59
  def results(query)
60
- # don't look up a loopback address, just return the stored result
61
- return [reserved_result] if query.loopback_ip_address?
60
+ # don't look up a loopback or private address, just return the stored result
61
+ return [reserved_result] if query.internal_ip_address?
62
62
  doc = fetch_data(query)
63
63
  if doc and doc.is_a?(Array)
64
64
  if !data_contains_error?(doc)
@@ -32,11 +32,7 @@ module Geocoder::Lookup
32
32
  return s
33
33
  else
34
34
  raise(
35
- Geocoder::ConfigurationError,
36
- "When using MaxMind GeoIP2 you MUST specify a service name and basic_auth: " +
37
- "Geocoder.configure(:maxmind_geoip2 => {:service => ...}, " +
38
- ":basic_auth => {:user ..., :password => ...}), " +
39
- "where service is one of: #{services.inspect}"
35
+ Geocoder::ConfigurationError, "When using MaxMind GeoIP2 you must specify a service and credentials: Geocoder.configure(maxmind_geoip2: {service: ..., basic_auth: {user: ..., password: ...}}), where service is one of: #{services.inspect}"
40
36
  )
41
37
  end
42
38
  end
@@ -57,8 +53,9 @@ module Geocoder::Lookup
57
53
  end
58
54
 
59
55
  def results(query)
60
- # don't look up a loopback address
61
- return [] if query.loopback_ip_address?
56
+ # don't look up a loopback or private address, just return the stored result
57
+ return [] if query.internal_ip_address?
58
+
62
59
  doc = fetch_data(query)
63
60
  if doc
64
61
  if !data_contains_error?(doc)
@@ -0,0 +1,57 @@
1
+ require 'cgi'
2
+ require 'geocoder/lookups/base'
3
+ require 'geocoder/results/osmnames'
4
+
5
+ module Geocoder::Lookup
6
+ class Osmnames < Base
7
+
8
+ def name
9
+ 'OSM Names'
10
+ end
11
+
12
+ def required_api_key_parts
13
+ configuration[:host] ? [] : ['key']
14
+ end
15
+
16
+ def supported_protocols
17
+ [:https]
18
+ end
19
+
20
+ private
21
+
22
+ def base_query_url(query)
23
+ "#{base_url(query)}/#{params_url(query)}.js?"
24
+ end
25
+
26
+ def base_url(query)
27
+ host = configuration[:host] || 'geocoder.tilehosting.com'
28
+ "#{protocol}://#{host}"
29
+ end
30
+
31
+ def params_url(query)
32
+ method, args = 'q', CGI.escape(query.sanitized_text)
33
+ method, args = 'r', query.coordinates.join('/') if query.reverse_geocode?
34
+ "#{country_limited(query)}#{method}/#{args}"
35
+ end
36
+
37
+ def results(query)
38
+ return [] unless doc = fetch_data(query)
39
+ if (error = doc['message'])
40
+ raise_error(Geocoder::InvalidRequest, error) ||
41
+ Geocoder.log(:warn, "OSMNames Geocoding API error: #{error}")
42
+ else
43
+ return doc['results']
44
+ end
45
+ end
46
+
47
+ def query_url_params(query)
48
+ {
49
+ key: configuration.api_key
50
+ }.merge(super)
51
+ end
52
+
53
+ def country_limited(query)
54
+ "#{query.options[:country_code].downcase}/" if query.options[:country_code] && !query.reverse_geocode?
55
+ end
56
+ end
57
+ end
@@ -24,12 +24,11 @@ module Geocoder::Lookup
24
24
 
25
25
  def query_url_params(query)
26
26
  params = {
27
- api_key: configuration.api_key,
28
- size: 1
27
+ api_key: configuration.api_key
29
28
  }.merge(super)
30
29
 
31
30
  if query.reverse_geocode?
32
- lat,lon = query.coordinates
31
+ lat, lon = query.coordinates
33
32
  params[:'point.lat'] = lat
34
33
  params[:'point.lon'] = lon
35
34
  else
@@ -23,7 +23,7 @@ module Geocoder::Lookup
23
23
  end
24
24
 
25
25
  def query_url_params(query)
26
- params = {
26
+ {
27
27
  key: configuration.api_key
28
28
  }.merge(super)
29
29
  end
@@ -23,8 +23,8 @@ module Geocoder::Lookup
23
23
  end
24
24
 
25
25
  def results(query)
26
- # don't look up a loopback address, just return the stored result
27
- return [] if query.loopback_ip_address?
26
+ # don't look up a loopback or private address, just return the stored result
27
+ return [] if query.internal_ip_address?
28
28
  doc = fetch_data(query)
29
29
  if doc and doc.is_a?(Hash)
30
30
  if !data_contains_error?(doc)
@@ -42,7 +42,7 @@ module Geocoder::Lookup
42
42
  raise_error(Geocoder::Error) || Geocoder.log(:warn, "Pointpin server error")
43
43
  end
44
44
  end
45
-
45
+
46
46
  return []
47
47
  end
48
48
 
@@ -8,7 +8,7 @@ module Geocoder::Lookup
8
8
  end
9
9
 
10
10
  def required_api_key_parts
11
- %w(auti-id auth-token)
11
+ %w(auth-id auth-token)
12
12
  end
13
13
 
14
14
  # required by API as of 26 March 2015
@@ -19,7 +19,9 @@ module Geocoder::Lookup
19
19
  private # ---------------------------------------------------------------
20
20
 
21
21
  def base_query_url(query)
22
- if zipcode_only?(query)
22
+ if international?(query)
23
+ "#{protocol}://international-street.api.smartystreets.com/verify?"
24
+ elsif zipcode_only?(query)
23
25
  "#{protocol}://us-zipcode.api.smartystreets.com/lookup?"
24
26
  else
25
27
  "#{protocol}://us-street.api.smartystreets.com/street-address?"
@@ -30,9 +32,17 @@ module Geocoder::Lookup
30
32
  !query.text.is_a?(Array) and query.to_s.strip =~ /\A\d{5}(-\d{4})?\Z/
31
33
  end
32
34
 
35
+ def international?(query)
36
+ !query.options[:country].nil?
37
+ end
38
+
33
39
  def query_url_params(query)
34
40
  params = {}
35
- if zipcode_only?(query)
41
+ if international?(query)
42
+ params[:freeform] = query.sanitized_text
43
+ params[:country] = query.options[:country]
44
+ params[:geocode] = true
45
+ elsif zipcode_only?(query)
36
46
  params[:zipcode] = query.sanitized_text
37
47
  else
38
48
  params[:street] = query.sanitized_text
@@ -34,8 +34,8 @@ module Geocoder::Lookup
34
34
  end
35
35
 
36
36
  def results(query)
37
- # don't look up a loopback address, just return the stored result
38
- return [reserved_result(query.text)] if query.loopback_ip_address?
37
+ # don't look up a loopback or private address, just return the stored result
38
+ return [reserved_result(query.text)] if query.internal_ip_address?
39
39
  if (doc = fetch_data(query)).nil? or doc['code'] == 401 or empty_result?(doc)
40
40
  []
41
41
  else
@@ -0,0 +1,59 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/tencent"
3
+
4
+ module Geocoder::Lookup
5
+ class Tencent < Base
6
+
7
+ def name
8
+ "Tencent"
9
+ end
10
+
11
+ def required_api_key_parts
12
+ ["key"]
13
+ end
14
+
15
+ def supported_protocols
16
+ [:https]
17
+ end
18
+
19
+ private # ---------------------------------------------------------------
20
+
21
+ def base_query_url(query)
22
+ "#{protocol}://apis.map.qq.com/ws/geocoder/v1/?"
23
+ end
24
+
25
+ def content_key
26
+ 'result'
27
+ end
28
+
29
+ def results(query, reverse = false)
30
+ return [] unless doc = fetch_data(query)
31
+ case doc['status']
32
+ when 0
33
+ return [doc[content_key]]
34
+ when 311
35
+ raise_error(Geocoder::InvalidApiKey, "invalid api key") ||
36
+ Geocoder.log(:warn, "#{name} Geocoding API error: invalid api key.")
37
+ when 310
38
+ raise_error(Geocoder::InvalidRequest, "invalid request.") ||
39
+ Geocoder.log(:warn, "#{name} Geocoding API error: invalid request, invalid parameters.")
40
+ when 306
41
+ raise_error(Geocoder::InvalidRequest, "invalid request.") ||
42
+ Geocoder.log(:warn, "#{name} Geocoding API error: invalid request, check response for more info.")
43
+ when 110
44
+ raise_error(Geocoder::RequestDenied, "request denied.") ||
45
+ Geocoder.log(:warn, "#{name} Geocoding API error: request source is not authorized.")
46
+ end
47
+ return []
48
+ end
49
+
50
+ def query_url_params(query)
51
+ {
52
+ (query.reverse_geocode? ? :location : :address) => query.sanitized_text,
53
+ :key => configuration.api_key,
54
+ :output => "json"
55
+ }.merge(super)
56
+ end
57
+
58
+ end
59
+ end