geocoder 1.4.3 → 1.5.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.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +43 -0
  3. data/README.md +364 -880
  4. data/examples/autoexpire_cache_redis.rb +3 -3
  5. data/lib/generators/geocoder/config/templates/initializer.rb +3 -2
  6. data/lib/generators/geocoder/maxmind/geolite_city_generator.rb +2 -0
  7. data/lib/generators/geocoder/maxmind/geolite_country_generator.rb +2 -0
  8. data/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb +1 -1
  9. data/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb +1 -1
  10. data/lib/generators/geocoder/migration_version.rb +15 -0
  11. data/lib/geocoder/cache.rb +6 -2
  12. data/lib/geocoder/cli.rb +2 -2
  13. data/lib/geocoder/configuration.rb +2 -2
  14. data/lib/geocoder/exceptions.rb +1 -1
  15. data/lib/geocoder/ip_address.rb +1 -1
  16. data/lib/geocoder/lookup.rb +9 -4
  17. data/lib/geocoder/lookups/amap.rb +63 -0
  18. data/lib/geocoder/lookups/baidu.rb +14 -10
  19. data/lib/geocoder/lookups/baidu_ip.rb +6 -35
  20. data/lib/geocoder/lookups/ban_data_gouv_fr.rb +4 -4
  21. data/lib/geocoder/lookups/base.rb +22 -4
  22. data/lib/geocoder/lookups/bing.rb +13 -12
  23. data/lib/geocoder/lookups/db_ip_com.rb +52 -0
  24. data/lib/geocoder/lookups/dstk.rb +4 -2
  25. data/lib/geocoder/lookups/esri.rb +1 -16
  26. data/lib/geocoder/lookups/freegeoip.rb +11 -2
  27. data/lib/geocoder/lookups/geocoder_ca.rb +4 -4
  28. data/lib/geocoder/lookups/geocoder_us.rb +17 -9
  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 +13 -9
  32. data/lib/geocoder/lookups/google_places_details.rb +4 -4
  33. data/lib/geocoder/lookups/google_places_search.rb +4 -4
  34. data/lib/geocoder/lookups/google_premier.rb +11 -1
  35. data/lib/geocoder/lookups/here.rb +4 -4
  36. data/lib/geocoder/lookups/ip2location.rb +74 -0
  37. data/lib/geocoder/lookups/ipapi_com.rb +7 -12
  38. data/lib/geocoder/lookups/ipdata_co.rb +61 -0
  39. data/lib/geocoder/lookups/ipinfo_io.rb +10 -19
  40. data/lib/geocoder/lookups/ipstack.rb +63 -0
  41. data/lib/geocoder/lookups/latlon.rb +4 -4
  42. data/lib/geocoder/lookups/location_iq.rb +26 -8
  43. data/lib/geocoder/lookups/mapbox.rb +12 -6
  44. data/lib/geocoder/lookups/mapquest.rb +4 -5
  45. data/lib/geocoder/lookups/maxmind.rb +4 -4
  46. data/lib/geocoder/lookups/maxmind_geoip2.rb +4 -0
  47. data/lib/geocoder/lookups/nominatim.rb +17 -5
  48. data/lib/geocoder/lookups/opencagedata.rb +7 -6
  49. data/lib/geocoder/lookups/pelias.rb +6 -6
  50. data/lib/geocoder/lookups/pickpoint.rb +41 -0
  51. data/lib/geocoder/lookups/pointpin.rb +7 -6
  52. data/lib/geocoder/lookups/postcode_anywhere_uk.rb +4 -5
  53. data/lib/geocoder/lookups/postcodes_io.rb +31 -0
  54. data/lib/geocoder/lookups/smarty_streets.rb +8 -8
  55. data/lib/geocoder/lookups/telize.rb +24 -4
  56. data/lib/geocoder/lookups/yandex.rb +10 -6
  57. data/lib/geocoder/models/active_record.rb +4 -3
  58. data/lib/geocoder/request.rb +32 -0
  59. data/lib/geocoder/results/amap.rb +87 -0
  60. data/lib/geocoder/results/baidu.rb +10 -10
  61. data/lib/geocoder/results/base.rb +13 -1
  62. data/lib/geocoder/results/bing.rb +1 -1
  63. data/lib/geocoder/results/db_ip_com.rb +58 -0
  64. data/lib/geocoder/results/freegeoip.rb +0 -5
  65. data/lib/geocoder/results/geocoder_ca.rb +3 -3
  66. data/lib/geocoder/results/geoip2.rb +24 -10
  67. data/lib/geocoder/results/geoportail_lu.rb +5 -3
  68. data/lib/geocoder/results/google.rb +16 -5
  69. data/lib/geocoder/results/here.rb +8 -0
  70. data/lib/geocoder/results/ip2location.rb +22 -0
  71. data/lib/geocoder/results/ipdata_co.rb +40 -0
  72. data/lib/geocoder/results/ipstack.rb +60 -0
  73. data/lib/geocoder/results/maxmind.rb +0 -5
  74. data/lib/geocoder/results/maxmind_local.rb +0 -5
  75. data/lib/geocoder/results/nominatim.rb +12 -0
  76. data/lib/geocoder/results/opencagedata.rb +12 -2
  77. data/lib/geocoder/results/pickpoint.rb +6 -0
  78. data/lib/geocoder/results/postcodes_io.rb +40 -0
  79. data/lib/geocoder/results/smarty_streets.rb +7 -1
  80. data/lib/geocoder/results/telize.rb +0 -5
  81. data/lib/geocoder/results/test.rb +1 -1
  82. data/lib/geocoder/sql.rb +2 -2
  83. data/lib/geocoder/stores/active_record.rb +15 -4
  84. data/lib/geocoder/stores/base.rb +1 -2
  85. data/lib/geocoder/version.rb +1 -1
  86. data/lib/tasks/geocoder.rake +11 -3
  87. metadata +27 -10
  88. data/lib/geocoder/lookups/okf.rb +0 -44
  89. data/lib/geocoder/lookups/ovi.rb +0 -62
  90. data/lib/geocoder/results/okf.rb +0 -106
  91. data/lib/geocoder/results/ovi.rb +0 -71
@@ -8,20 +8,28 @@ module Geocoder::Lookup
8
8
  "Geocoder.us"
9
9
  end
10
10
 
11
- def supported_protocols
12
- [:http]
13
- end
11
+ def supported_protocols
12
+ [:http]
13
+ end
14
+
15
+ private # ----------------------------------------------------------------
16
+
17
+ def base_query_url(query)
18
+ base_query_url_with_optional_key(configuration.api_key)
19
+ end
14
20
 
15
- def query_url(query)
21
+ def cache_key(query)
22
+ base_query_url_with_optional_key(nil) + url_query_string(query)
23
+ end
24
+
25
+ def base_query_url_with_optional_key(key = nil)
26
+ base = "#{protocol}://"
16
27
  if configuration.api_key
17
- "#{protocol}://#{configuration.api_key}@geocoder.us/member/service/csv/geocode?" + url_query_string(query)
18
- else
19
- "#{protocol}://geocoder.us/service/csv/geocode?" + url_query_string(query)
28
+ base << "#{configuration.api_key}@"
20
29
  end
30
+ base + "geocoder.us/member/service/csv/geocode?"
21
31
  end
22
32
 
23
- private
24
-
25
33
  def results(query)
26
34
  return [] unless doc = fetch_data(query)
27
35
  if doc[0].to_s =~ /^(\d+)\:/
@@ -8,11 +8,6 @@ module Geocoder::Lookup
8
8
  "Geocodio"
9
9
  end
10
10
 
11
- def query_url(query)
12
- path = query.reverse_geocode? ? "reverse" : "geocode"
13
- "#{protocol}://api.geocod.io/v1/#{path}?#{url_query_string(query)}"
14
- end
15
-
16
11
  def results(query)
17
12
  return [] unless doc = fetch_data(query)
18
13
  return doc["results"] if doc['error'].nil?
@@ -32,6 +27,11 @@ module Geocoder::Lookup
32
27
 
33
28
  private # ---------------------------------------------------------------
34
29
 
30
+ def base_query_url(query)
31
+ path = query.reverse_geocode? ? "reverse" : "geocode"
32
+ "#{protocol}://api.geocod.io/v1.3/#{path}?"
33
+ end
34
+
35
35
  def query_url_params(query)
36
36
  {
37
37
  :api_key => configuration.api_key,
@@ -9,14 +9,14 @@ module Geocoder
9
9
  "Geoportail.lu"
10
10
  end
11
11
 
12
- def query_url(query)
13
- url_base_path(query) + url_query_string(query)
14
- end
15
-
16
- private
12
+ private # ---------------------------------------------------------------
17
13
 
18
- def url_base_path(query)
19
- query.reverse_geocode? ? reverse_geocode_url_base_path : search_url_base_path
14
+ def base_query_url(query)
15
+ if query.reverse_geocode?
16
+ reverse_geocode_url_base_path
17
+ else
18
+ search_url_base_path
19
+ end
20
20
  end
21
21
 
22
22
  def search_url_base_path
@@ -21,12 +21,12 @@ module Geocoder::Lookup
21
21
  end
22
22
  end
23
23
 
24
- def query_url(query)
25
- "#{protocol}://maps.googleapis.com/maps/api/geocode/json?" + url_query_string(query)
26
- end
27
-
28
24
  private # ---------------------------------------------------------------
29
25
 
26
+ def base_query_url(query)
27
+ "#{protocol}://maps.googleapis.com/maps/api/geocode/json?"
28
+ end
29
+
30
30
  def configure_ssl!(client)
31
31
  client.instance_eval {
32
32
  @ssl_context = OpenSSL::SSL::SSLContext.new
@@ -52,21 +52,25 @@ module Geocoder::Lookup
52
52
  raise_error(Geocoder::OverQueryLimitError) ||
53
53
  Geocoder.log(:warn, "#{name} API error: over query limit.")
54
54
  when "REQUEST_DENIED"
55
- raise_error(Geocoder::RequestDenied) ||
56
- Geocoder.log(:warn, "#{name} API error: request denied.")
55
+ raise_error(Geocoder::RequestDenied, doc['error_message']) ||
56
+ Geocoder.log(:warn, "#{name} API error: request denied (#{doc['error_message']}).")
57
57
  when "INVALID_REQUEST"
58
- raise_error(Geocoder::InvalidRequest) ||
59
- Geocoder.log(:warn, "#{name} API error: invalid request.")
58
+ raise_error(Geocoder::InvalidRequest, doc['error_message']) ||
59
+ Geocoder.log(:warn, "#{name} API error: invalid request (#{doc['error_message']}).")
60
60
  end
61
61
  return []
62
62
  end
63
63
 
64
64
  def query_url_google_params(query)
65
65
  params = {
66
- (query.reverse_geocode? ? :latlng : :address) => query.sanitized_text,
67
66
  :sensor => "false",
68
67
  :language => (query.language || configuration.language)
69
68
  }
69
+ if query.options[:google_place_id]
70
+ params[:place_id] = query.sanitized_text
71
+ else
72
+ params[(query.reverse_geocode? ? :latlng : :address)] = query.sanitized_text
73
+ end
70
74
  unless (bounds = query.options[:bounds]).nil?
71
75
  params[:bounds] = bounds.map{ |point| "%f,%f" % point }.join('|')
72
76
  end
@@ -16,12 +16,12 @@ module Geocoder
16
16
  [:https]
17
17
  end
18
18
 
19
- def query_url(query)
20
- "#{protocol}://maps.googleapis.com/maps/api/place/details/json?#{url_query_string(query)}"
21
- end
22
-
23
19
  private
24
20
 
21
+ def base_query_url(query)
22
+ "#{protocol}://maps.googleapis.com/maps/api/place/details/json?"
23
+ end
24
+
25
25
  def results(query)
26
26
  return [] unless doc = fetch_data(query)
27
27
 
@@ -16,12 +16,12 @@ module Geocoder
16
16
  [:https]
17
17
  end
18
18
 
19
- def query_url(query)
20
- "#{protocol}://maps.googleapis.com/maps/api/place/textsearch/json?#{url_query_string(query)}"
21
- end
22
-
23
19
  private
24
20
 
21
+ def base_query_url(query)
22
+ "#{protocol}://maps.googleapis.com/maps/api/place/textsearch/json?"
23
+ end
24
+
25
25
  def query_url_google_params(query)
26
26
  {
27
27
  query: query.text,
@@ -11,7 +11,7 @@ module Geocoder::Lookup
11
11
  end
12
12
 
13
13
  def required_api_key_parts
14
- ["private key", "client", "channel"]
14
+ ["private key"]
15
15
  end
16
16
 
17
17
  def query_url(query)
@@ -21,6 +21,16 @@ module Geocoder::Lookup
21
21
 
22
22
  private # ---------------------------------------------------------------
23
23
 
24
+ def cache_key(query)
25
+ "#{protocol}://maps.googleapis.com/maps/api/geocode/json?" + hash_to_query(cache_key_params(query))
26
+ end
27
+
28
+ def cache_key_params(query)
29
+ query_url_google_params(query).merge(super).reject do |k,v|
30
+ [:key, :client, :channel].include?(k)
31
+ end
32
+ end
33
+
24
34
  def query_url_params(query)
25
35
  query_url_google_params(query).merge(super).merge(
26
36
  :key => nil, # don't use param inherited from Google lookup
@@ -12,12 +12,12 @@ module Geocoder::Lookup
12
12
  ["app_id", "app_code"]
13
13
  end
14
14
 
15
- def query_url(query)
16
- "#{protocol}://#{if query.reverse_geocode? then 'reverse.' end}geocoder.api.here.com/6.2/#{if query.reverse_geocode? then 'reverse' end}geocode.json?" + url_query_string(query)
17
- end
18
-
19
15
  private # ---------------------------------------------------------------
20
16
 
17
+ def base_query_url(query)
18
+ "#{protocol}://#{if query.reverse_geocode? then 'reverse.' end}geocoder.api.here.com/6.2/#{if query.reverse_geocode? then 'reverse' end}geocode.json?"
19
+ end
20
+
21
21
  def results(query)
22
22
  return [] unless doc = fetch_data(query)
23
23
  return [] unless doc['Response'] && doc['Response']['View']
@@ -0,0 +1,74 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/ip2location'
3
+
4
+ module Geocoder::Lookup
5
+ class Ip2location < Base
6
+
7
+ def name
8
+ "IP2LocationApi"
9
+ end
10
+
11
+ def supported_protocols
12
+ [:http, :https]
13
+ end
14
+
15
+ private # ----------------------------------------------------------------
16
+
17
+ def base_query_url(query)
18
+ "#{protocol}://api.ip2location.com/?"
19
+ end
20
+
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)
27
+ end
28
+
29
+ def results(query)
30
+ return [reserved_result(query.text)] if query.loopback_ip_address?
31
+ return [] unless doc = fetch_data(query)
32
+ if doc["response"] == "INVALID ACCOUNT"
33
+ raise_error(Geocoder::InvalidApiKey) || Geocoder.log(:warn, "INVALID ACCOUNT")
34
+ return []
35
+ else
36
+ return [doc]
37
+ end
38
+ end
39
+
40
+ def reserved_result(query)
41
+ {
42
+ "country_code" => "INVALID IP ADDRESS",
43
+ "country_name" => "INVALID IP ADDRESS",
44
+ "region_name" => "INVALID IP ADDRESS",
45
+ "city_name" => "INVALID IP ADDRESS",
46
+ "latitude" => "INVALID IP ADDRESS",
47
+ "longitude" => "INVALID IP ADDRESS",
48
+ "zip_code" => "INVALID IP ADDRESS",
49
+ "time_zone" => "INVALID IP ADDRESS",
50
+ "isp" => "INVALID IP ADDRESS",
51
+ "domain" => "INVALID IP ADDRESS",
52
+ "net_speed" => "INVALID IP ADDRESS",
53
+ "idd_code" => "INVALID IP ADDRESS",
54
+ "area_code" => "INVALID IP ADDRESS",
55
+ "weather_station_code" => "INVALID IP ADDRESS",
56
+ "weather_station_name" => "INVALID IP ADDRESS",
57
+ "mcc" => "INVALID IP ADDRESS",
58
+ "mnc" => "INVALID IP ADDRESS",
59
+ "mobile_brand" => "INVALID IP ADDRESS",
60
+ "elevation" => "INVALID IP ADDRESS",
61
+ "usage_type" => "INVALID IP ADDRESS"
62
+ }
63
+ end
64
+
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
+ end
74
+ end
@@ -8,17 +8,6 @@ module Geocoder::Lookup
8
8
  "ip-api.com"
9
9
  end
10
10
 
11
- def query_url(query)
12
- domain = configuration.api_key ? "pro.ip-api.com" : "ip-api.com"
13
- url_ = "#{protocol}://#{domain}/json/#{query.sanitized_text}"
14
-
15
- if (params = url_query_string(query)) && !params.empty?
16
- url_ + "?" + params
17
- else
18
- url_
19
- end
20
- end
21
-
22
11
  def supported_protocols
23
12
  if configuration.api_key
24
13
  [:http, :https]
@@ -27,8 +16,14 @@ module Geocoder::Lookup
27
16
  end
28
17
  end
29
18
 
19
+ private # ----------------------------------------------------------------
30
20
 
31
- private
21
+ def base_query_url(query)
22
+ domain = configuration.api_key ? "pro.ip-api.com" : "ip-api.com"
23
+ url = "#{protocol}://#{domain}/json/#{query.sanitized_text}"
24
+ url << "?" if not url_query_string(query).empty?
25
+ url
26
+ end
32
27
 
33
28
  def parse_raw_data(raw_data)
34
29
  if raw_data.chomp == "invalid key"
@@ -0,0 +1,61 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/ipdata_co'
3
+
4
+ module Geocoder::Lookup
5
+ class IpdataCo < Base
6
+
7
+ def name
8
+ "ipdata.co"
9
+ end
10
+
11
+ def supported_protocols
12
+ [:https]
13
+ end
14
+
15
+ def query_url(query)
16
+ "#{protocol}://#{host}/#{query.sanitized_text}"
17
+ end
18
+
19
+ private # ---------------------------------------------------------------
20
+
21
+ def cache_key(query)
22
+ query_url(query)
23
+ end
24
+
25
+ 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?
29
+ # note: Ipdata.co returns plain text on bad request
30
+ (doc = fetch_data(query)) ? [doc] : []
31
+ end
32
+
33
+ def reserved_result(ip)
34
+ {
35
+ "ip" => ip,
36
+ "city" => "",
37
+ "region_code" => "",
38
+ "region_name" => "",
39
+ "metrocode" => "",
40
+ "zipcode" => "",
41
+ "latitude" => "0",
42
+ "longitude" => "0",
43
+ "country_name" => "Reserved",
44
+ "country_code" => "RD"
45
+ }
46
+ end
47
+
48
+ def host
49
+ "api.ipdata.co"
50
+ end
51
+
52
+ def check_response_for_errors!(response)
53
+ if response.code.to_i == 403
54
+ raise_error(Geocoder::RequestDenied) ||
55
+ Geocoder.log(:warn, "Geocoding API error: 403 API key does not exist")
56
+ else
57
+ super(response)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -8,14 +8,6 @@ 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
18
-
19
11
  # HTTPS available only for paid plans
20
12
  def supported_protocols
21
13
  if configuration.api_key
@@ -27,28 +19,27 @@ module Geocoder::Lookup
27
19
 
28
20
  private # ---------------------------------------------------------------
29
21
 
22
+ def base_query_url(query)
23
+ url = "#{protocol}://ipinfo.io/#{query.sanitized_text}/geo"
24
+ url << "?" if configuration.api_key
25
+ url
26
+ end
27
+
30
28
  def results(query)
31
29
  # don't look up a loopback address, just return the stored result
32
30
  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)
31
+
32
+ if !(doc = fetch_data(query)).is_a?(Hash) or doc['error']
34
33
  []
35
34
  else
36
35
  [doc]
37
36
  end
38
37
  end
39
38
 
40
- def empty_result?(doc)
41
- !doc.is_a?(Hash) or doc.keys == ["ip"]
42
- end
43
-
44
39
  def reserved_result(ip)
45
40
  {
46
- "ip" => ip,
47
- "city" => "",
48
- "region" => "",
49
- "country" => "",
50
- "loc" => "0,0",
51
- "postal" => ""
41
+ "ip" => ip,
42
+ "bogon" => true
52
43
  }
53
44
  end
54
45
 
@@ -0,0 +1,63 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/ipstack'
3
+
4
+ module Geocoder::Lookup
5
+ class Ipstack < Base
6
+
7
+ ERROR_CODES = {
8
+ 404 => Geocoder::InvalidRequest,
9
+ 101 => Geocoder::InvalidApiKey,
10
+ 102 => Geocoder::Error,
11
+ 103 => Geocoder::InvalidRequest,
12
+ 104 => Geocoder::OverQueryLimitError,
13
+ 105 => Geocoder::RequestDenied,
14
+ 301 => Geocoder::InvalidRequest,
15
+ 302 => Geocoder::InvalidRequest,
16
+ 303 => Geocoder::RequestDenied,
17
+ }
18
+ ERROR_CODES.default = Geocoder::Error
19
+
20
+ def name
21
+ "Ipstack"
22
+ end
23
+
24
+ private # ----------------------------------------------------------------
25
+
26
+ def base_query_url(query)
27
+ "#{protocol}://#{host}/#{query.sanitized_text}?"
28
+ end
29
+
30
+ def query_url_params(query)
31
+ {
32
+ access_key: configuration.api_key
33
+ }.merge(super)
34
+ end
35
+
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?
39
+
40
+ return [] unless doc = fetch_data(query)
41
+
42
+ if error = doc['error']
43
+ code = error['code']
44
+ msg = error['info']
45
+ raise_error(ERROR_CODES[code], msg ) || Geocoder.log(:warn, "Ipstack Geocoding API error: #{msg}")
46
+ return []
47
+ end
48
+ [doc]
49
+ end
50
+
51
+ def reserved_result(ip)
52
+ {
53
+ "ip" => ip,
54
+ "country_name" => "Reserved",
55
+ "country_code" => "RD"
56
+ }
57
+ end
58
+
59
+ def host
60
+ configuration[:host] || "api.ipstack.com"
61
+ end
62
+ end
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?
@@ -10,20 +10,38 @@ module Geocoder::Lookup
10
10
  def required_api_key_parts
11
11
  ["api_key"]
12
12
  end
13
-
14
- def query_url(query)
15
- method = query.reverse_geocode? ? "reverse.php" : "search.php"
16
- host = configuration[:host] || "locationiq.org/v1"
17
- "#{protocol}://#{host}/#{method}?key=#{configuration.api_key}&" + url_query_string(query)
13
+
14
+ private # ----------------------------------------------------------------
15
+
16
+ def base_query_url(query)
17
+ method = query.reverse_geocode? ? "reverse" : "search"
18
+ "#{protocol}://#{configured_host}/v1/#{method}.php?"
18
19
  end
19
20
 
20
- private
21
+ def query_url_params(query)
22
+ {
23
+ key: configuration.api_key
24
+ }.merge(super)
25
+ end
26
+
27
+ def configured_host
28
+ configuration[:host] || "locationiq.org"
29
+ end
21
30
 
22
31
  def results(query)
23
32
  return [] unless doc = fetch_data(query)
24
33
 
25
- if !doc.is_a?(Array) && doc['error'] =~ /Invalid\skey/
26
- raise_error(Geocoder::InvalidApiKey, doc['error'])
34
+ if !doc.is_a?(Array)
35
+ case doc['error']
36
+ when "Invalid key"
37
+ raise_error(Geocoder::InvalidApiKey, doc['error'])
38
+ when "Key not active - Please write to contact@unwiredlabs.com"
39
+ raise_error(Geocoder::RequestDenied, doc['error'])
40
+ when "Rate Limited"
41
+ raise_error(Geocoder::OverQueryLimitError, doc['error'])
42
+ when "Unknown error - Please try again after some time"
43
+ raise_error(Geocoder::InvalidRequest, doc['error'])
44
+ end
27
45
  end
28
46
 
29
47
  doc.is_a?(Array) ? doc : [doc]
@@ -8,12 +8,12 @@ module Geocoder::Lookup
8
8
  "Mapbox"
9
9
  end
10
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
11
  private # ---------------------------------------------------------------
16
12
 
13
+ def base_query_url(query)
14
+ "#{protocol}://api.mapbox.com/geocoding/v5/#{dataset}/#{mapbox_search_term(query)}.json?"
15
+ end
16
+
17
17
  def results(query)
18
18
  return [] unless data = fetch_data(query)
19
19
  if data['features']
@@ -25,13 +25,19 @@ module Geocoder::Lookup
25
25
  end
26
26
  end
27
27
 
28
- def url_query_string(query)
28
+ def query_url_params(query)
29
+ {access_token: configuration.api_key}.merge(super(query))
30
+ end
31
+
32
+ def mapbox_search_term(query)
29
33
  require 'cgi' unless defined?(CGI) && defined?(CGI.escape)
30
34
  if query.reverse_geocode?
31
35
  lat,lon = query.coordinates
32
36
  "#{CGI.escape lon},#{CGI.escape lat}"
33
37
  else
34
- 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
35
41
  end
36
42
  end
37
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
  #
@@ -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
  #