geocoder 1.1.9 → 1.2.0

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.

Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +9 -5
  4. data/CHANGELOG.md +19 -0
  5. data/README.md +175 -10
  6. data/Rakefile +1 -1
  7. data/gemfiles/Gemfile.mongoid-2.4.x +1 -0
  8. data/lib/generators/geocoder/maxmind/geolite_city_generator.rb +28 -0
  9. data/lib/generators/geocoder/maxmind/geolite_country_generator.rb +28 -0
  10. data/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb +27 -0
  11. data/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb +17 -0
  12. data/lib/geocoder.rb +4 -12
  13. data/lib/geocoder/cache.rb +3 -2
  14. data/lib/geocoder/calculations.rb +39 -0
  15. data/lib/geocoder/configuration.rb +1 -7
  16. data/lib/geocoder/ip_address.rb +12 -0
  17. data/lib/geocoder/lookup.rb +10 -1
  18. data/lib/geocoder/lookups/baidu.rb +7 -6
  19. data/lib/geocoder/lookups/baidu_ip.rb +54 -0
  20. data/lib/geocoder/lookups/base.rb +37 -9
  21. data/lib/geocoder/lookups/bing.rb +10 -5
  22. data/lib/geocoder/lookups/cloudmade.rb +35 -0
  23. data/lib/geocoder/lookups/freegeoip.rb +5 -1
  24. data/lib/geocoder/lookups/geocodio.rb +42 -0
  25. data/lib/geocoder/lookups/google_premier.rb +1 -1
  26. data/lib/geocoder/lookups/here.rb +62 -0
  27. data/lib/geocoder/lookups/mapquest.rb +2 -1
  28. data/lib/geocoder/lookups/maxmind_local.rb +58 -0
  29. data/lib/geocoder/lookups/nominatim.rb +8 -0
  30. data/lib/geocoder/lookups/smarty_streets.rb +45 -0
  31. data/lib/geocoder/lookups/yahoo.rb +1 -1
  32. data/lib/geocoder/models/active_record.rb +5 -3
  33. data/lib/geocoder/models/base.rb +1 -4
  34. data/lib/geocoder/models/mongo_base.rb +4 -2
  35. data/lib/geocoder/query.rb +4 -4
  36. data/lib/geocoder/railtie.rb +1 -1
  37. data/lib/geocoder/request.rb +10 -8
  38. data/lib/geocoder/results/baidu_ip.rb +62 -0
  39. data/lib/geocoder/results/cloudmade.rb +39 -0
  40. data/lib/geocoder/results/geocodio.rb +66 -0
  41. data/lib/geocoder/results/here.rb +62 -0
  42. data/lib/geocoder/results/maxmind_local.rb +49 -0
  43. data/lib/geocoder/results/smarty_streets.rb +106 -0
  44. data/lib/geocoder/results/test.rb +20 -3
  45. data/lib/geocoder/results/yandex.rb +7 -3
  46. data/lib/geocoder/sql.rb +16 -15
  47. data/lib/geocoder/stores/active_record.rb +6 -2
  48. data/lib/geocoder/stores/base.rb +8 -1
  49. data/lib/geocoder/version.rb +1 -1
  50. data/lib/maxmind_database.rb +109 -0
  51. data/lib/oauth_util.rb +1 -1
  52. data/lib/tasks/geocoder.rake +3 -1
  53. data/lib/tasks/maxmind.rake +73 -0
  54. data/test/fixtures/baidu_ip_202_198_16_3 +19 -0
  55. data/test/fixtures/baidu_ip_invalid_key +1 -0
  56. data/test/fixtures/baidu_ip_no_results +1 -0
  57. data/test/fixtures/cloudmade_invalid_key +1 -0
  58. data/test/fixtures/cloudmade_madison_square_garden +1 -0
  59. data/test/fixtures/cloudmade_no_results +1 -0
  60. data/test/fixtures/geocodio_1101_pennsylvania_ave +1 -0
  61. data/test/fixtures/geocodio_bad_api_key +3 -0
  62. data/test/fixtures/geocodio_invalid +4 -0
  63. data/test/fixtures/geocodio_no_results +1 -0
  64. data/test/fixtures/geocodio_over_query_limit +4 -0
  65. data/test/fixtures/here_madison_square_garden +72 -0
  66. data/test/fixtures/here_no_results +8 -0
  67. data/test/fixtures/nominatim_over_limit +1 -0
  68. data/test/fixtures/smarty_streets_11211 +1 -0
  69. data/test/fixtures/smarty_streets_madison_square_garden +47 -0
  70. data/test/fixtures/smarty_streets_no_results +1 -0
  71. data/test/fixtures/yandex_canada_rue_dupuis_14 +446 -0
  72. data/test/fixtures/yandex_new_york +1 -0
  73. data/test/integration/http_client_test.rb +25 -0
  74. data/test/mongoid_test_helper.rb +2 -2
  75. data/test/test_helper.rb +98 -30
  76. data/test/{active_record_test.rb → unit/active_record_test.rb} +4 -3
  77. data/test/{cache_test.rb → unit/cache_test.rb} +3 -1
  78. data/test/{calculations_test.rb → unit/calculations_test.rb} +22 -13
  79. data/test/{configuration_test.rb → unit/configuration_test.rb} +4 -27
  80. data/test/{error_handling_test.rb → unit/error_handling_test.rb} +10 -9
  81. data/test/{geocoder_test.rb → unit/geocoder_test.rb} +26 -7
  82. data/test/{https_test.rb → unit/https_test.rb} +4 -3
  83. data/test/unit/ip_address_test.rb +24 -0
  84. data/test/{lookup_test.rb → unit/lookup_test.rb} +33 -20
  85. data/test/unit/lookups/bing_test.rb +68 -0
  86. data/test/unit/lookups/dstk_test.rb +26 -0
  87. data/test/unit/lookups/esri_test.rb +48 -0
  88. data/test/unit/lookups/freegeoip_test.rb +27 -0
  89. data/test/unit/lookups/geocoder_ca_test.rb +17 -0
  90. data/test/unit/lookups/geocodio_test.rb +55 -0
  91. data/test/unit/lookups/google_premier_test.rb +22 -0
  92. data/test/unit/lookups/google_test.rb +84 -0
  93. data/test/unit/lookups/mapquest_test.rb +60 -0
  94. data/test/unit/lookups/maxmind_local_test.rb +28 -0
  95. data/test/unit/lookups/maxmind_test.rb +63 -0
  96. data/test/unit/lookups/nominatim_test.rb +31 -0
  97. data/test/unit/lookups/smarty_streets_test.rb +71 -0
  98. data/test/unit/lookups/yahoo_test.rb +35 -0
  99. data/test/{method_aliases_test.rb → unit/method_aliases_test.rb} +5 -4
  100. data/test/unit/model_test.rb +38 -0
  101. data/test/{mongoid_test.rb → unit/mongoid_test.rb} +10 -9
  102. data/test/unit/near_test.rb +87 -0
  103. data/test/{oauth_util_test.rb → unit/oauth_util_test.rb} +3 -2
  104. data/test/{proxy_test.rb → unit/proxy_test.rb} +2 -1
  105. data/test/{query_test.rb → unit/query_test.rb} +7 -8
  106. data/test/unit/rake_task_test.rb +21 -0
  107. data/test/{request_test.rb → unit/request_test.rb} +8 -2
  108. data/test/{result_test.rb → unit/result_test.rb} +29 -1
  109. data/test/{test_mode_test.rb → unit/test_mode_test.rb} +12 -1
  110. metadata +80 -27
  111. data/test/custom_block_test.rb +0 -32
  112. data/test/integration/smoke_test.rb +0 -26
  113. data/test/near_test.rb +0 -61
  114. data/test/services_test.rb +0 -393
@@ -0,0 +1,17 @@
1
+ class GeocoderMaxmindGeoliteCountry < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :maxmind_geolite_country, id: false do |t|
4
+ t.column :start_ip, :string
5
+ t.column :end_ip, :string
6
+ t.column :start_ip_num, :bigint, null: false
7
+ t.column :end_ip_num, :bigint, null: false
8
+ t.column :country_code, :string, null: false
9
+ t.column :country, :string, null: false
10
+ end
11
+ add_index :maxmind_geolite_country, :start_ip_num, unique: true
12
+ end
13
+
14
+ def self.down
15
+ drop_table :maxmind_geolite_country
16
+ end
17
+ end
@@ -5,17 +5,17 @@ require "geocoder/exceptions"
5
5
  require "geocoder/cache"
6
6
  require "geocoder/request"
7
7
  require "geocoder/lookup"
8
+ require "geocoder/ip_address"
8
9
  require "geocoder/models/active_record" if defined?(::ActiveRecord)
9
10
  require "geocoder/models/mongoid" if defined?(::Mongoid)
10
11
  require "geocoder/models/mongo_mapper" if defined?(::MongoMapper)
11
12
 
12
13
  module Geocoder
13
- extend self
14
14
 
15
15
  ##
16
16
  # Search for information about an address or a set of coordinates.
17
17
  #
18
- def search(query, options = {})
18
+ def self.search(query, options = {})
19
19
  query = Geocoder::Query.new(query, options) unless query.is_a?(Geocoder::Query)
20
20
  query.blank? ? [] : query.execute
21
21
  end
@@ -23,7 +23,7 @@ module Geocoder
23
23
  ##
24
24
  # Look up the coordinates of the given street or IP address.
25
25
  #
26
- def coordinates(address, options = {})
26
+ def self.coordinates(address, options = {})
27
27
  if (results = search(address, options)).size > 0
28
28
  results.first.coordinates
29
29
  end
@@ -33,19 +33,11 @@ module Geocoder
33
33
  # Look up the address of the given coordinates ([lat,lon])
34
34
  # or IP address (string).
35
35
  #
36
- def address(query, options = {})
36
+ def self.address(query, options = {})
37
37
  if (results = search(query, options)).size > 0
38
38
  results.first.address
39
39
  end
40
40
  end
41
-
42
- ##
43
- # The working Cache object, or +nil+ if none configured.
44
- #
45
- def cache
46
- warn "WARNING: Calling Geocoder.cache is DEPRECATED. The #cache method now belongs to the Geocoder::Lookup object."
47
- Geocoder::Lookup.get(Geocoder.config.lookup).cache
48
- end
49
41
  end
50
42
 
51
43
  # load Railtie if Rails exists
@@ -49,7 +49,8 @@ module Geocoder
49
49
 
50
50
  private # ----------------------------------------------------------------
51
51
 
52
- attr_reader :prefix, :store
52
+ def prefix; @prefix; end
53
+ def store; @store; end
53
54
 
54
55
  ##
55
56
  # Cache key for a given URL.
@@ -63,7 +64,7 @@ module Geocoder
63
64
  # that have non-nil values.
64
65
  #
65
66
  def keys
66
- store.keys.select{ |k| k.match /^#{prefix}/ and interpret(store[k]) }
67
+ store.keys.select{ |k| k.match(/^#{prefix}/) and interpret(store[k]) }
67
68
  end
68
69
 
69
70
  ##
@@ -26,6 +26,11 @@ module Geocoder
26
26
  #
27
27
  KM_IN_NM = 0.539957
28
28
 
29
+ ##
30
+ # Conversion factor: multiply by radians to get degrees.
31
+ #
32
+ DEGREES_PER_RADIAN = 57.2957795
33
+
29
34
  # Not a number constant
30
35
  NAN = defined?(::Float::NAN) ? ::Float::NAN : 0 / 0.0
31
36
 
@@ -254,6 +259,40 @@ module Geocoder
254
259
  [center[0] + delta_lat, center[1] + delta_long]
255
260
  end
256
261
 
262
+ ##
263
+ # Given a start point, distance, and heading (in degrees), provides
264
+ # an endpoint.
265
+ # The starting point is given in the same way that points are given to all
266
+ # Geocoder methods that accept points as arguments. It can be:
267
+ #
268
+ # * an array of coordinates ([lat,lon])
269
+ # * a geocodable address (string)
270
+ # * a geocoded object (one which implements a +to_coordinates+ method
271
+ # which returns a [lat,lon] array
272
+ #
273
+ def endpoint(start, heading, distance, options = {})
274
+ options[:units] ||= Geocoder.config.units
275
+ radius = earth_radius(options[:units])
276
+
277
+ start = extract_coordinates(start)
278
+
279
+ # convert degrees to radians
280
+ start = to_radians(start)
281
+
282
+ lat = start[0]
283
+ lon = start[1]
284
+ heading = to_radians(heading)
285
+ distance = distance.to_f
286
+
287
+ end_lat = Math.asin(Math.sin(lat)*Math.cos(distance/radius) +
288
+ Math.cos(lat)*Math.sin(distance/radius)*Math.cos(heading))
289
+
290
+ end_lon = lon+Math.atan2(Math.sin(heading)*Math.sin(distance/radius)*Math.cos(lat),
291
+ Math.cos(distance/radius)-Math.sin(lat)*Math.sin(end_lat))
292
+
293
+ to_degrees [end_lat, end_lon]
294
+ end
295
+
257
296
  ##
258
297
  # Convert degrees to radians.
259
298
  # If an array (or multiple arguments) is passed,
@@ -14,14 +14,8 @@ module Geocoder
14
14
  # )
15
15
  #
16
16
  def self.configure(options = nil, &block)
17
- if block_given?
18
- warn "WARNING: Passing a block to Geocoder.configure is DEPRECATED. Please pass a hash instead (eg: Geocoder.configure(:units => ..., :api_key => ...))."
19
- block.call(Configuration.instance)
20
- elsif !options.nil?
17
+ if !options.nil?
21
18
  Configuration.instance.configure(options)
22
- else
23
- warn "WARNING: Use of Geocoder.configure to read or write single config options is DEPRECATED. To write to the config please pass a hash (eg: Geocoder.configure(:units => ...)). To read config options please use the Geocoder.config object (eg: Geocoder.config.units)."
24
- Configuration.instance
25
19
  end
26
20
  end
27
21
 
@@ -0,0 +1,12 @@
1
+ module Geocoder
2
+ class IpAddress < String
3
+
4
+ def loopback?
5
+ valid? and (self == "0.0.0.0" or self.match(/\A127\./))
6
+ end
7
+
8
+ def valid?
9
+ !!self.match(/\A(::ffff:)?(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\z/)
10
+ end
11
+ end
12
+ end
@@ -33,7 +33,11 @@ module Geocoder
33
33
  :nominatim,
34
34
  :mapquest,
35
35
  :ovi,
36
+ :here,
36
37
  :baidu,
38
+ :cloudmade,
39
+ :geocodio,
40
+ :smarty_streets,
37
41
  :test
38
42
  ]
39
43
  end
@@ -42,7 +46,12 @@ module Geocoder
42
46
  # All IP address lookup services, default first.
43
47
  #
44
48
  def ip_services
45
- [:freegeoip, :maxmind]
49
+ [
50
+ :freegeoip,
51
+ :maxmind,
52
+ :maxmind_local,
53
+ :baidu_ip
54
+ ]
46
55
  end
47
56
 
48
57
  ##
@@ -20,22 +20,23 @@ module Geocoder::Lookup
20
20
 
21
21
  def results(query, reverse = false)
22
22
  return [] unless doc = fetch_data(query)
23
- case doc['status']; when 0
23
+ case doc['status']
24
+ when 0
24
25
  return [doc['result']] unless doc['result'].blank?
25
26
  when 1, 3, 4
26
- raise_error(Geocoder::Error, messages) ||
27
+ raise_error(Geocoder::Error, "server error.") ||
27
28
  warn("Baidu Geocoding API error: server error.")
28
29
  when 2
29
- raise_error(Geocoder::InvalidRequest, messages) ||
30
+ raise_error(Geocoder::InvalidRequest, "invalid request.") ||
30
31
  warn("Baidu Geocoding API error: invalid request.")
31
32
  when 5
32
- raise_error(Geocoder::InvalidApiKey, messages) ||
33
+ raise_error(Geocoder::InvalidApiKey, "invalid api key") ||
33
34
  warn("Baidu Geocoding API error: invalid api key.")
34
35
  when 101, 102, 200..299
35
- raise_error(Geocoder::RequestDenied) ||
36
+ raise_error(Geocoder::RequestDenied, "request denied") ||
36
37
  warn("Baidu Geocoding API error: request denied.")
37
38
  when 300..399
38
- raise_error(Geocoder::OverQueryLimitError) ||
39
+ raise_error(Geocoder::OverQueryLimitError, "over query limit.") ||
39
40
  warn("Baidu Geocoding API error: over query limit.")
40
41
  end
41
42
  return []
@@ -0,0 +1,54 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/baidu_ip'
3
+
4
+ module Geocoder::Lookup
5
+ class BaiduIp < Base
6
+
7
+ def name
8
+ "Baidu IP"
9
+ end
10
+
11
+ def required_api_key_parts
12
+ ["key"]
13
+ end
14
+
15
+ def query_url(query)
16
+ "http://api.map.baidu.com/location/ip?" + url_query_string(query)
17
+ end
18
+
19
+ private # ---------------------------------------------------------------
20
+
21
+ def results(query, reverse = false)
22
+ return [] unless doc = fetch_data(query)
23
+ case doc['status']
24
+ when 0
25
+ return [doc['content']] unless doc['content'].blank?
26
+ when 1, 3, 4
27
+ raise_error(Geocoder::Error, "server error.") ||
28
+ warn("Baidu IP Geocoding API error: server error.")
29
+ when 2
30
+ raise_error(Geocoder::InvalidRequest, "invalid request.") ||
31
+ warn("Baidu IP Geocoding API error: invalid request.")
32
+ when 5
33
+ raise_error(Geocoder::InvalidApiKey, "invalid api key.") ||
34
+ warn("Baidu IP Geocoding API error: invalid api key.")
35
+ when 101, 102, 200..299
36
+ raise_error(Geocoder::RequestDenied, "request denied.") ||
37
+ warn("Baidu IP Geocoding API error: request denied.")
38
+ when 300..399
39
+ raise_error(Geocoder::OverQueryLimitError, "over query limit") ||
40
+ warn("Baidu IP Geocoding API error: over query limit.")
41
+ end
42
+ return []
43
+ end
44
+
45
+ def query_url_params(query)
46
+ {
47
+ :ip => query.sanitized_text,
48
+ :ak => configuration.api_key,
49
+ :coor => "bd09ll"
50
+ }.merge(super)
51
+ end
52
+
53
+ end
54
+ end
@@ -15,6 +15,9 @@ module Geocoder
15
15
  module Lookup
16
16
 
17
17
  class Base
18
+ def initialize
19
+ @cache = nil
20
+ end
18
21
 
19
22
  ##
20
23
  # Human-readable name of the geocoding API.
@@ -211,7 +214,21 @@ module Geocoder
211
214
  else
212
215
  check_api_key_configuration!(query)
213
216
  response = make_api_request(query)
217
+ check_response_for_errors!(response)
214
218
  body = response.body
219
+
220
+ # apply the charset from the Content-Type header, if possible
221
+ ct = response['content-type']
222
+
223
+ if ct && ct['charset']
224
+ charset = ct.split(';').select do |s|
225
+ s['charset']
226
+ end.first.to_s.split('=')
227
+ if charset.length == 2
228
+ body.force_encoding(charset.last) rescue ArgumentError
229
+ end
230
+ end
231
+
215
232
  if cache and valid_response?(response)
216
233
  cache[key] = body
217
234
  end
@@ -220,6 +237,19 @@ module Geocoder
220
237
  body
221
238
  end
222
239
 
240
+ def check_response_for_errors!(response)
241
+ if response.code.to_i == 400
242
+ raise_error(Geocoder::InvalidRequest) ||
243
+ warn("Geocoding API error: 400 Bad Request")
244
+ elsif response.code.to_i == 401
245
+ raise_error(Geocoder::RequestDenied) ||
246
+ warn("Geocoding API error: 401 Unauthorized")
247
+ elsif response.code.to_i == 402
248
+ raise_error(Geocoder::OverQueryLimitError) ||
249
+ warn("Geocoding API error: 402 Payment Required")
250
+ end
251
+ end
252
+
223
253
  ##
224
254
  # Make an HTTP(S) request to a geocoding API and
225
255
  # return the response object.
@@ -227,15 +257,13 @@ module Geocoder
227
257
  def make_api_request(query)
228
258
  timeout(configuration.timeout) do
229
259
  uri = URI.parse(query_url(query))
230
- # client = http_client.new(uri.host, uri.port)
231
- # client.use_ssl = true if configuration.use_https
232
- # client.get(uri.request_uri, configuration.http_headers)
233
-
234
- http_client.start(uri.host, uri.port) do |client|
235
- client.use_ssl = true if configuration.use_https
236
- req = Net::HTTP::Get.new(uri.request_uri, configuration.http_headers)
237
- req.basic_auth(uri.user, uri.password) if uri.user and uri.password
238
- client.request(req)
260
+ args = [uri.host, uri.port]
261
+ args = args.push(uri.user, uri.password) unless uri.user.nil? or uri.password.nil?
262
+ opts = {}
263
+ opts[:use_ssl] = true if configuration.use_https
264
+
265
+ http_client.start(*args, opts) do |client|
266
+ client.get(uri.request_uri, configuration.http_headers)
239
267
  end
240
268
  end
241
269
  end
@@ -17,13 +17,19 @@ module Geocoder::Lookup
17
17
  end
18
18
 
19
19
  def query_url(query)
20
- "#{protocol}://dev.virtualearth.net/REST/v1/Locations" +
21
- (query.reverse_geocode? ? "/#{query.sanitized_text}?" : "?") +
22
- url_query_string(query)
20
+ base_url(query) + url_query_string(query)
23
21
  end
24
22
 
25
23
  private # ---------------------------------------------------------------
26
24
 
25
+ def base_url(query)
26
+ url = "#{protocol}://dev.virtualearth.net/REST/v1/Locations"
27
+ if !query.reverse_geocode? and r = query.options[:region]
28
+ url << "/#{r}"
29
+ end
30
+ url + "/" + URI.escape(query.sanitized_text.strip) + "?"
31
+ end
32
+
27
33
  def results(query)
28
34
  return [] unless doc = fetch_data(query)
29
35
 
@@ -39,8 +45,7 @@ module Geocoder::Lookup
39
45
 
40
46
  def query_url_params(query)
41
47
  {
42
- :key => configuration.api_key,
43
- :query => query.reverse_geocode? ? nil : query.sanitized_text
48
+ key: configuration.api_key
44
49
  }.merge(super)
45
50
  end
46
51
  end
@@ -0,0 +1,35 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/cloudmade'
3
+
4
+ module Geocoder::Lookup
5
+ class Cloudmade < Base
6
+
7
+ def name
8
+ "Cloudmade"
9
+ end
10
+
11
+ def query_url(query)
12
+ "http://geocoding.cloudmade.com/#{configuration.api_key}/geocoding/v2/find.js?#{url_query_string(query)}"
13
+ end
14
+
15
+ def required_api_key_parts
16
+ ["key"]
17
+ end
18
+
19
+ private
20
+
21
+ def results(query)
22
+ data = fetch_data(query)
23
+ (data && data['features']) || []
24
+ end
25
+
26
+ def query_url_params(query)
27
+ {
28
+ :query => query.sanitized_text,
29
+ :return_location => true,
30
+ :return_geometry => false
31
+ }.merge(super)
32
+ end
33
+
34
+ end
35
+ end
@@ -9,7 +9,7 @@ module Geocoder::Lookup
9
9
  end
10
10
 
11
11
  def query_url(query)
12
- "#{protocol}://freegeoip.net/json/#{query.sanitized_text}"
12
+ "#{protocol}://#{host}/json/#{query.sanitized_text}"
13
13
  end
14
14
 
15
15
  private # ---------------------------------------------------------------
@@ -39,5 +39,9 @@ module Geocoder::Lookup
39
39
  "country_code" => "RD"
40
40
  }
41
41
  end
42
+
43
+ def host
44
+ configuration[:host] || "freegeoip.net"
45
+ end
42
46
  end
43
47
  end
@@ -0,0 +1,42 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/geocodio"
3
+
4
+ module Geocoder::Lookup
5
+ class Geocodio < Base
6
+
7
+ def name
8
+ "Geocodio"
9
+ end
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
+ def results(query)
17
+ return [] unless doc = fetch_data(query)
18
+ return doc["results"] if doc['error'].nil?
19
+
20
+ if doc['error'] == 'Invalid API key'
21
+ raise_error(Geocoder::InvalidApiKey) ||
22
+ warn("Geocodio service error: invalid API key.")
23
+ elsif doc['error'].match(/You have reached your daily maximum/)
24
+ raise_error(Geocoder::OverQueryLimitError, doc['error']) ||
25
+ warn("Geocodio service error: #{doc['error']}.")
26
+ else
27
+ raise_error(Geocoder::InvalidRequest, doc['error']) ||
28
+ warn("Geocodio service error: #{doc['error']}.")
29
+ end
30
+ []
31
+ end
32
+
33
+ private # ---------------------------------------------------------------
34
+
35
+ def query_url_params(query)
36
+ {
37
+ :api_key => configuration.api_key,
38
+ :q => query.sanitized_text
39
+ }.merge(super)
40
+ end
41
+ end
42
+ end