geocoder 1.4.9 → 1.6.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +60 -0
  3. data/LICENSE +1 -1
  4. data/README.md +350 -979
  5. data/bin/console +13 -0
  6. data/examples/autoexpire_cache_redis.rb +2 -0
  7. data/lib/easting_northing.rb +171 -0
  8. data/lib/generators/geocoder/config/templates/initializer.rb +1 -1
  9. data/lib/geocoder/cache.rb +4 -0
  10. data/lib/geocoder/calculations.rb +1 -1
  11. data/lib/geocoder/cli.rb +2 -2
  12. data/lib/geocoder/configuration.rb +3 -2
  13. data/lib/geocoder/configuration_hash.rb +4 -4
  14. data/lib/geocoder/exceptions.rb +1 -1
  15. data/lib/geocoder/ip_address.rb +16 -2
  16. data/lib/geocoder/lookup.rb +9 -5
  17. data/lib/geocoder/lookups/abstract_api.rb +46 -0
  18. data/lib/geocoder/lookups/amap.rb +7 -3
  19. data/lib/geocoder/lookups/baidu.rb +14 -10
  20. data/lib/geocoder/lookups/baidu_ip.rb +7 -36
  21. data/lib/geocoder/lookups/ban_data_gouv_fr.rb +18 -5
  22. data/lib/geocoder/lookups/base.rb +27 -4
  23. data/lib/geocoder/lookups/bing.rb +10 -13
  24. data/lib/geocoder/lookups/db_ip_com.rb +9 -6
  25. data/lib/geocoder/lookups/dstk.rb +4 -2
  26. data/lib/geocoder/lookups/esri.rb +44 -28
  27. data/lib/geocoder/lookups/freegeoip.rb +11 -7
  28. data/lib/geocoder/lookups/geocoder_ca.rb +4 -4
  29. data/lib/geocoder/lookups/geocodio.rb +5 -5
  30. data/lib/geocoder/lookups/geoportail_lu.rb +7 -7
  31. data/lib/geocoder/lookups/google.rb +15 -10
  32. data/lib/geocoder/lookups/google_places_details.rb +11 -17
  33. data/lib/geocoder/lookups/google_places_search.rb +30 -4
  34. data/lib/geocoder/lookups/google_premier.rb +14 -0
  35. data/lib/geocoder/lookups/here.rb +29 -23
  36. data/lib/geocoder/lookups/ip2location.rb +67 -0
  37. data/lib/geocoder/lookups/ipapi_com.rb +9 -13
  38. data/lib/geocoder/lookups/ipdata_co.rb +9 -4
  39. data/lib/geocoder/lookups/ipgeolocation.rb +51 -0
  40. data/lib/geocoder/lookups/ipinfo_io.rb +11 -29
  41. data/lib/geocoder/lookups/ipregistry.rb +68 -0
  42. data/lib/geocoder/lookups/ipstack.rb +11 -12
  43. data/lib/geocoder/lookups/latlon.rb +5 -6
  44. data/lib/geocoder/lookups/location_iq.rb +10 -4
  45. data/lib/geocoder/lookups/mapbox.rb +7 -6
  46. data/lib/geocoder/lookups/mapquest.rb +4 -5
  47. data/lib/geocoder/lookups/maxmind.rb +6 -6
  48. data/lib/geocoder/lookups/maxmind_geoip2.rb +8 -7
  49. data/lib/geocoder/lookups/maxmind_local.rb +7 -1
  50. data/lib/geocoder/lookups/nationaal_georegister_nl.rb +38 -0
  51. data/lib/geocoder/lookups/nominatim.rb +4 -4
  52. data/lib/geocoder/lookups/opencagedata.rb +6 -5
  53. data/lib/geocoder/lookups/osmnames.rb +57 -0
  54. data/lib/geocoder/lookups/pelias.rb +8 -9
  55. data/lib/geocoder/lookups/pickpoint.rb +9 -3
  56. data/lib/geocoder/lookups/pointpin.rb +10 -9
  57. data/lib/geocoder/lookups/postcode_anywhere_uk.rb +4 -5
  58. data/lib/geocoder/lookups/postcodes_io.rb +6 -3
  59. data/lib/geocoder/lookups/smarty_streets.rb +26 -11
  60. data/lib/geocoder/lookups/telize.rb +24 -4
  61. data/lib/geocoder/lookups/tencent.rb +59 -0
  62. data/lib/geocoder/lookups/test.rb +4 -0
  63. data/lib/geocoder/lookups/uk_ordnance_survey_names.rb +59 -0
  64. data/lib/geocoder/lookups/yandex.rb +7 -8
  65. data/lib/geocoder/query.rb +14 -0
  66. data/lib/geocoder/railtie.rb +1 -1
  67. data/lib/geocoder/results/abstract_api.rb +146 -0
  68. data/lib/geocoder/results/baidu.rb +10 -14
  69. data/lib/geocoder/results/ban_data_gouv_fr.rb +27 -2
  70. data/lib/geocoder/results/base.rb +13 -1
  71. data/lib/geocoder/results/bing.rb +1 -1
  72. data/lib/geocoder/results/db_ip_com.rb +1 -6
  73. data/lib/geocoder/results/freegeoip.rb +0 -5
  74. data/lib/geocoder/results/geocoder_ca.rb +3 -3
  75. data/lib/geocoder/results/geoip2.rb +0 -4
  76. data/lib/geocoder/results/geoportail_lu.rb +5 -3
  77. data/lib/geocoder/results/here.rb +4 -1
  78. data/lib/geocoder/results/ip2location.rb +22 -0
  79. data/lib/geocoder/results/ipdata_co.rb +0 -5
  80. data/lib/geocoder/results/ipgeolocation.rb +59 -0
  81. data/lib/geocoder/results/ipregistry.rb +304 -0
  82. data/lib/geocoder/results/maxmind.rb +0 -5
  83. data/lib/geocoder/results/maxmind_local.rb +0 -5
  84. data/lib/geocoder/results/nationaal_georegister_nl.rb +62 -0
  85. data/lib/geocoder/results/nominatim.rb +4 -0
  86. data/lib/geocoder/results/osmnames.rb +56 -0
  87. data/lib/geocoder/results/smarty_streets.rb +48 -18
  88. data/lib/geocoder/results/telize.rb +0 -5
  89. data/lib/geocoder/results/tencent.rb +72 -0
  90. data/lib/geocoder/results/test.rb +1 -1
  91. data/lib/geocoder/results/uk_ordnance_survey_names.rb +59 -0
  92. data/lib/geocoder/results/yandex.rb +217 -59
  93. data/lib/geocoder/sql.rb +4 -4
  94. data/lib/geocoder/stores/active_record.rb +1 -3
  95. data/lib/geocoder/util.rb +29 -0
  96. data/lib/geocoder/version.rb +1 -1
  97. data/lib/maxmind_database.rb +3 -3
  98. metadata +27 -23
  99. data/lib/geocoder/lookups/geocoder_us.rb +0 -43
  100. data/lib/geocoder/lookups/mapzen.rb +0 -15
  101. data/lib/geocoder/lookups/okf.rb +0 -44
  102. data/lib/geocoder/lookups/ovi.rb +0 -62
  103. data/lib/geocoder/results/geocoder_us.rb +0 -39
  104. data/lib/geocoder/results/mapzen.rb +0 -5
  105. data/lib/geocoder/results/okf.rb +0 -106
  106. data/lib/geocoder/results/ovi.rb +0 -71
  107. data/lib/hash_recursive_merge.rb +0 -74
@@ -8,47 +8,29 @@ module Geocoder::Lookup
8
8
  "Ipinfo.io"
9
9
  end
10
10
 
11
- def query_url(query)
12
- if configuration.api_key
13
- "#{protocol}://ipinfo.io/#{query.sanitized_text}/geo?" + url_query_string(query)
14
- else
15
- "#{protocol}://ipinfo.io/#{query.sanitized_text}/geo"
16
- end
17
- end
11
+ private # ---------------------------------------------------------------
18
12
 
19
- # HTTPS available only for paid plans
20
- def supported_protocols
21
- if configuration.api_key
22
- [:http, :https]
23
- else
24
- [:http]
25
- end
13
+ def base_query_url(query)
14
+ url = "#{protocol}://ipinfo.io/#{query.sanitized_text}/geo"
15
+ url << "?" if configuration.api_key
16
+ url
26
17
  end
27
18
 
28
- private # ---------------------------------------------------------------
29
-
30
19
  def results(query)
31
- # don't look up a loopback address, just return the stored result
32
- return [reserved_result(query.text)] if query.loopback_ip_address?
33
- if (doc = fetch_data(query)).nil? or doc['code'] == 401 or empty_result?(doc)
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?
22
+
23
+ if !(doc = fetch_data(query)).is_a?(Hash) or doc['error']
34
24
  []
35
25
  else
36
26
  [doc]
37
27
  end
38
28
  end
39
29
 
40
- def empty_result?(doc)
41
- !doc.is_a?(Hash) or doc.keys == ["ip"]
42
- end
43
-
44
30
  def reserved_result(ip)
45
31
  {
46
- "ip" => ip,
47
- "city" => "",
48
- "region" => "",
49
- "country" => "",
50
- "loc" => "0,0",
51
- "postal" => ""
32
+ "ip" => ip,
33
+ "bogon" => true
52
34
  }
53
35
  end
54
36
 
@@ -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
@@ -21,18 +21,21 @@ module Geocoder::Lookup
21
21
  "Ipstack"
22
22
  end
23
23
 
24
- def query_url(query)
25
- extra_params = url_query_string(query)
26
- url = "#{protocol}://#{host}/#{query.sanitized_text}?access_key=#{api_key}"
27
- url << "&#{extra_params}" unless extra_params.empty?
28
- url
24
+ private # ----------------------------------------------------------------
25
+
26
+ def base_query_url(query)
27
+ "#{protocol}://#{host}/#{query.sanitized_text}?"
29
28
  end
30
29
 
31
- private
30
+ def query_url_params(query)
31
+ {
32
+ access_key: configuration.api_key
33
+ }.merge(super)
34
+ end
32
35
 
33
36
  def results(query)
34
- # don't look up a loopback address, just return the stored result
35
- 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?
36
39
 
37
40
  return [] unless doc = fetch_data(query)
38
41
 
@@ -56,9 +59,5 @@ module Geocoder::Lookup
56
59
  def host
57
60
  configuration[:host] || "api.ipstack.com"
58
61
  end
59
-
60
- def api_key
61
- configuration.api_key
62
- end
63
62
  end
64
63
  end
@@ -12,12 +12,12 @@ module Geocoder::Lookup
12
12
  ["api_key"]
13
13
  end
14
14
 
15
- def query_url(query)
16
- "#{protocol}://latlon.io/api/v1/#{'reverse_' if query.reverse_geocode?}geocode?#{url_query_string(query)}"
17
- end
18
-
19
15
  private # ---------------------------------------------------------------
20
16
 
17
+ def base_query_url(query)
18
+ "#{protocol}://latlon.io/api/v1/#{'reverse_' if query.reverse_geocode?}geocode?"
19
+ end
20
+
21
21
  def results(query)
22
22
  return [] unless doc = fetch_data(query)
23
23
  if doc['error'].nil?
@@ -25,8 +25,7 @@ module Geocoder::Lookup
25
25
  # The API returned a 404 response, which indicates no results found
26
26
  elsif doc['error']['type'] == 'api_error'
27
27
  []
28
- elsif
29
- doc['error']['type'] == 'authentication_error'
28
+ elsif doc['error']['type'] == 'authentication_error'
30
29
  raise_error(Geocoder::InvalidApiKey) ||
31
30
  Geocoder.log(:warn, "LatLon.io service error: invalid API key.")
32
31
  else
@@ -10,13 +10,19 @@ module Geocoder::Lookup
10
10
  def required_api_key_parts
11
11
  ["api_key"]
12
12
  end
13
-
14
- def query_url(query)
13
+
14
+ private # ----------------------------------------------------------------
15
+
16
+ def base_query_url(query)
15
17
  method = query.reverse_geocode? ? "reverse" : "search"
16
- "#{protocol}://#{configured_host}/v1/#{method}.php?key=#{configuration.api_key}&" + url_query_string(query)
18
+ "#{protocol}://#{configured_host}/v1/#{method}.php?"
17
19
  end
18
20
 
19
- private
21
+ def query_url_params(query)
22
+ {
23
+ key: configuration.api_key
24
+ }.merge(super)
25
+ end
20
26
 
21
27
  def configured_host
22
28
  configuration[:host] || "locationiq.org"
@@ -8,13 +8,12 @@ module Geocoder::Lookup
8
8
  "Mapbox"
9
9
  end
10
10
 
11
- def query_url(query)
12
- path = "#{mapbox_search_term(query)}.json?#{url_query_string(query)}"
13
- "#{protocol}://api.mapbox.com/geocoding/v5/#{dataset}/#{path}"
14
- end
15
-
16
11
  private # ---------------------------------------------------------------
17
12
 
13
+ def base_query_url(query)
14
+ "#{protocol}://api.mapbox.com/geocoding/v5/#{dataset}/#{mapbox_search_term(query)}.json?"
15
+ end
16
+
18
17
  def results(query)
19
18
  return [] unless data = fetch_data(query)
20
19
  if data['features']
@@ -36,7 +35,9 @@ module Geocoder::Lookup
36
35
  lat,lon = query.coordinates
37
36
  "#{CGI.escape lon},#{CGI.escape lat}"
38
37
  else
39
- CGI.escape query.text.to_s
38
+ # truncate at first semicolon so Mapbox doesn't go into batch mode
39
+ # (see Github issue #1299)
40
+ CGI.escape query.text.to_s.split(';').first.to_s
40
41
  end
41
42
  end
42
43
 
@@ -13,14 +13,13 @@ module Geocoder::Lookup
13
13
  ["key"]
14
14
  end
15
15
 
16
- def query_url(query)
16
+ private # ---------------------------------------------------------------
17
+
18
+ def base_query_url(query)
17
19
  domain = configuration[:open] ? "open" : "www"
18
- url = "#{protocol}://#{domain}.mapquestapi.com/geocoding/v1/#{search_type(query)}?"
19
- url + url_query_string(query)
20
+ "#{protocol}://#{domain}.mapquestapi.com/geocoding/v1/#{search_type(query)}?"
20
21
  end
21
22
 
22
- private # ---------------------------------------------------------------
23
-
24
23
  def search_type(query)
25
24
  query.reverse_geocode? ? "reverse" : "address"
26
25
  end
@@ -9,12 +9,12 @@ module Geocoder::Lookup
9
9
  "MaxMind"
10
10
  end
11
11
 
12
- def query_url(query)
13
- "#{protocol}://geoip.maxmind.com/#{service_code}?" + url_query_string(query)
14
- end
15
-
16
12
  private # ---------------------------------------------------------------
17
13
 
14
+ def base_query_url(query)
15
+ "#{protocol}://geoip.maxmind.com/#{service_code}?"
16
+ end
17
+
18
18
  ##
19
19
  # Return the name of the configured service, or raise an exception.
20
20
  #
@@ -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)
@@ -20,6 +20,10 @@ module Geocoder::Lookup
20
20
 
21
21
  private # ---------------------------------------------------------------
22
22
 
23
+ def cache_key(query)
24
+ query_url(query)
25
+ end
26
+
23
27
  ##
24
28
  # Return the name of the configured service, or raise an exception.
25
29
  #
@@ -28,11 +32,7 @@ module Geocoder::Lookup
28
32
  return s
29
33
  else
30
34
  raise(
31
- Geocoder::ConfigurationError,
32
- "When using MaxMind GeoIP2 you MUST specify a service name and basic_auth: " +
33
- "Geocoder.configure(:maxmind_geoip2 => {:service => ...}, " +
34
- ":basic_auth => {:user ..., :password => ...}), " +
35
- "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}"
36
36
  )
37
37
  end
38
38
  end
@@ -53,8 +53,9 @@ module Geocoder::Lookup
53
53
  end
54
54
 
55
55
  def results(query)
56
- # don't look up a loopback address
57
- 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
+
58
59
  doc = fetch_data(query)
59
60
  if doc
60
61
  if !data_contains_error?(doc)
@@ -30,7 +30,13 @@ module Geocoder::Lookup
30
30
  def results(query)
31
31
  if configuration[:file]
32
32
  geoip_class = RUBY_PLATFORM == "java" ? JGeoIP : GeoIP
33
- result = geoip_class.new(configuration[:file]).city(query.to_s)
33
+ geoip_instance = geoip_class.new(configuration[:file])
34
+ result =
35
+ if configuration[:package] == :country
36
+ geoip_instance.country(query.to_s)
37
+ else
38
+ geoip_instance.city(query.to_s)
39
+ end
34
40
  result.nil? ? [] : [encode_hash(result.to_hash)]
35
41
  elsif configuration[:package] == :city
36
42
  addr = IPAddr.new(query.text).to_i
@@ -0,0 +1,38 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/nationaal_georegister_nl"
3
+
4
+ module Geocoder::Lookup
5
+ class NationaalGeoregisterNl < Base
6
+
7
+ def name
8
+ 'Nationaal Georegister Nederland'
9
+ end
10
+
11
+ private # ---------------------------------------------------------------
12
+
13
+ def cache_key(query)
14
+ base_query_url(query) + hash_to_query(query_url_params(query))
15
+ end
16
+
17
+ def base_query_url(query)
18
+ "#{protocol}://geodata.nationaalgeoregister.nl/locatieserver/v3/free?"
19
+ end
20
+
21
+ def valid_response?(response)
22
+ json = parse_json(response.body)
23
+ super(response) if json
24
+ end
25
+
26
+ def results(query)
27
+ return [] unless doc = fetch_data(query)
28
+ return doc['response']['docs']
29
+ end
30
+
31
+ def query_url_params(query)
32
+ {
33
+ fl: '*',
34
+ q: query.text
35
+ }.merge(super)
36
+ end
37
+ end
38
+ end
@@ -12,13 +12,13 @@ module Geocoder::Lookup
12
12
  "https://www.openstreetmap.org/?lat=#{coordinates[0]}&lon=#{coordinates[1]}&zoom=15&layers=M"
13
13
  end
14
14
 
15
- def query_url(query)
15
+ private # ---------------------------------------------------------------
16
+
17
+ def base_query_url(query)
16
18
  method = query.reverse_geocode? ? "reverse" : "search"
17
- "#{protocol}://#{configured_host}/#{method}?" + url_query_string(query)
19
+ "#{protocol}://#{configured_host}/#{method}?"
18
20
  end
19
21
 
20
- private # ---------------------------------------------------------------
21
-
22
22
  def configured_host
23
23
  configuration[:host] || "nominatim.openstreetmap.org"
24
24
  end
@@ -8,15 +8,15 @@ module Geocoder::Lookup
8
8
  "OpenCageData"
9
9
  end
10
10
 
11
- def query_url(query)
12
- "#{protocol}://api.opencagedata.com/geocode/v1/json?key=#{configuration.api_key}&#{url_query_string(query)}"
13
- end
14
-
15
11
  def required_api_key_parts
16
12
  ["key"]
17
13
  end
18
14
 
19
- private
15
+ private # ----------------------------------------------------------------
16
+
17
+ def base_query_url(query)
18
+ "#{protocol}://api.opencagedata.com/geocode/v1/json?"
19
+ end
20
20
 
21
21
  def results(query)
22
22
  return [] unless doc = fetch_data(query)
@@ -44,6 +44,7 @@ module Geocoder::Lookup
44
44
  def query_url_params(query)
45
45
  params = {
46
46
  :q => query.sanitized_text,
47
+ :key => configuration.api_key,
47
48
  :language => (query.language || configuration.language)
48
49
  }.merge(super)
49
50
 
@@ -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