geocoder 1.1.5 → 1.1.6

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 (84) hide show
  1. data/.travis.yml +4 -0
  2. data/{CHANGELOG.rdoc → CHANGELOG.md} +90 -37
  3. data/README.md +96 -45
  4. data/examples/autoexpire_cache.rb +1 -3
  5. data/lib/generators/geocoder/config/templates/initializer.rb +18 -22
  6. data/lib/geocoder.rb +2 -4
  7. data/lib/geocoder/cache.rb +2 -1
  8. data/lib/geocoder/calculations.rb +12 -12
  9. data/lib/geocoder/cli.rb +10 -11
  10. data/lib/geocoder/configuration.rb +67 -43
  11. data/lib/geocoder/configuration_hash.rb +11 -0
  12. data/lib/geocoder/exceptions.rb +3 -0
  13. data/lib/geocoder/lookup.rb +1 -1
  14. data/lib/geocoder/lookups/base.rb +59 -16
  15. data/lib/geocoder/lookups/bing.rb +21 -11
  16. data/lib/geocoder/lookups/freegeoip.rb +8 -4
  17. data/lib/geocoder/lookups/geocoder_ca.rb +11 -7
  18. data/lib/geocoder/lookups/google.rb +18 -9
  19. data/lib/geocoder/lookups/google_premier.rb +16 -8
  20. data/lib/geocoder/lookups/mapquest.rb +12 -5
  21. data/lib/geocoder/lookups/maxmind.rb +72 -0
  22. data/lib/geocoder/lookups/nominatim.rb +13 -8
  23. data/lib/geocoder/lookups/test.rb +4 -0
  24. data/lib/geocoder/lookups/yahoo.rb +38 -11
  25. data/lib/geocoder/lookups/yandex.rb +17 -9
  26. data/lib/geocoder/query.rb +17 -8
  27. data/lib/geocoder/request.rb +7 -1
  28. data/lib/geocoder/results/google.rb +6 -0
  29. data/lib/geocoder/results/maxmind.rb +136 -0
  30. data/lib/geocoder/results/nominatim.rb +0 -10
  31. data/lib/geocoder/sql.rb +6 -4
  32. data/lib/geocoder/stores/active_record.rb +5 -5
  33. data/lib/geocoder/stores/base.rb +3 -2
  34. data/lib/geocoder/version.rb +1 -1
  35. data/lib/hash_recursive_merge.rb +74 -0
  36. data/lib/oauth_util.rb +8 -2
  37. data/test/cache_test.rb +2 -2
  38. data/test/calculations_test.rb +4 -4
  39. data/test/configuration_test.rb +26 -51
  40. data/test/error_handling_test.rb +4 -4
  41. data/test/fixtures/bing_invalid_key +1 -0
  42. data/test/fixtures/{bing_madison_square_garden.json → bing_madison_square_garden} +0 -0
  43. data/test/fixtures/{bing_no_results.json → bing_no_results} +0 -0
  44. data/test/fixtures/{bing_reverse.json → bing_reverse} +0 -0
  45. data/test/fixtures/{freegeoip_74_200_247_59.json → freegeoip_74_200_247_59} +0 -0
  46. data/test/fixtures/{freegeoip_no_results.json → freegeoip_no_results} +0 -0
  47. data/test/fixtures/{geocoder_ca_madison_square_garden.json → geocoder_ca_madison_square_garden} +0 -0
  48. data/test/fixtures/{geocoder_ca_no_results.json → geocoder_ca_no_results} +0 -0
  49. data/test/fixtures/{geocoder_ca_reverse.json → geocoder_ca_reverse} +0 -0
  50. data/test/fixtures/{google_garbage.json → google_garbage} +0 -0
  51. data/test/fixtures/{google_madison_square_garden.json → google_madison_square_garden} +0 -0
  52. data/test/fixtures/{google_no_city_data.json → google_no_city_data} +0 -0
  53. data/test/fixtures/{google_no_locality.json → google_no_locality} +0 -0
  54. data/test/fixtures/{google_no_results.json → google_no_results} +0 -0
  55. data/test/fixtures/{mapquest_madison_square_garden.json → mapquest_madison_square_garden} +0 -0
  56. data/test/fixtures/{mapquest_no_results.json → mapquest_no_results} +0 -0
  57. data/test/fixtures/maxmind_24_24_24_21 +1 -0
  58. data/test/fixtures/maxmind_24_24_24_22 +1 -0
  59. data/test/fixtures/maxmind_24_24_24_23 +1 -0
  60. data/test/fixtures/maxmind_24_24_24_24 +1 -0
  61. data/test/fixtures/maxmind_74_200_247_59 +1 -0
  62. data/test/fixtures/maxmind_invalid_key +1 -0
  63. data/test/fixtures/maxmind_no_results +1 -0
  64. data/test/fixtures/{nominatim_madison_square_garden.json → nominatim_madison_square_garden} +0 -0
  65. data/test/fixtures/{nominatim_no_results.json → nominatim_no_results} +0 -0
  66. data/test/fixtures/{yahoo_error.json → yahoo_error} +0 -0
  67. data/test/fixtures/yahoo_invalid_key +2 -0
  68. data/test/fixtures/{yahoo_madison_square_garden.json → yahoo_madison_square_garden} +0 -0
  69. data/test/fixtures/{yahoo_no_results.json → yahoo_no_results} +0 -0
  70. data/test/fixtures/yahoo_over_limit +2 -0
  71. data/test/fixtures/{yandex_invalid_key.json → yandex_invalid_key} +0 -0
  72. data/test/fixtures/{yandex_kremlin.json → yandex_kremlin} +0 -0
  73. data/test/fixtures/{yandex_no_results.json → yandex_no_results} +0 -0
  74. data/test/https_test.rb +3 -3
  75. data/test/integration/smoke_test.rb +2 -2
  76. data/test/lookup_test.rb +82 -5
  77. data/test/oauth_util_test.rb +30 -0
  78. data/test/proxy_test.rb +2 -2
  79. data/test/query_test.rb +3 -0
  80. data/test/result_test.rb +2 -2
  81. data/test/services_test.rb +121 -44
  82. data/test/test_helper.rb +44 -109
  83. data/test/test_mode_test.rb +3 -3
  84. metadata +42 -33
@@ -25,6 +25,4 @@ class AutoexpireCache
25
25
  end
26
26
  end
27
27
 
28
- Geocoder.configure do |config|
29
- config.cache = AutoexpireCache.new(Redis.new)
30
- end
28
+ Geocoder.configure(:cache => AutoexpireCache.new(Redis.new))
@@ -1,25 +1,21 @@
1
- Geocoder.configure do |config|
2
- ## Configurable parameters: if you wish to change some configurable
3
- ## behaviour in Geocoder, feel free to uncomment the following lines
4
- ## and provide custom parameters.
1
+ Geocoder.configure(
2
+ # geocoding options
3
+ # :timeout => 3, # geocoding service timeout (secs)
4
+ # :lookup => :google, # name of geocoding service (symbol)
5
+ # :language => :en, # ISO-639 language code
6
+ # :use_https => false, # use HTTPS for lookup requests? (if supported)
7
+ # :http_proxy => nil, # HTTP proxy server (user:pass@host:port)
8
+ # :https_proxy => nil, # HTTPS proxy server (user:pass@host:port)
9
+ # :api_key => nil, # API key for geocoding service
10
+ # :cache => nil, # cache object (must respond to #[], #[]=, and #keys)
11
+ # :cache_prefix => "geocoder:", # prefix (string) to use for all cache keys
5
12
 
6
- # config.timeout = 3 # geocoding service timeout (secs)
7
- # config.lookup = :google # name of geocoding service (symbol)
8
- # config.language = :en # ISO-639 language code
9
- # config.use_https = false # use HTTPS for lookup requests? (if supported)
10
- # config.http_proxy = nil # HTTP proxy server (user:pass@host:port)
11
- # config.https_proxy = nil # HTTPS proxy server (user:pass@host:port)
12
- # config.api_key = nil # API key for geocoding service
13
- # config.cache = nil # cache object (must respond to #[], #[]=, and #keys)
14
- # config.cache_prefix = "geocoder:" # prefix (string) to use for all cache keys
13
+ # exceptions that should not be rescued by default
14
+ # (if you want to implement custom error handling);
15
+ # supports SocketError and TimeoutError
16
+ # :always_raise => [],
15
17
 
16
- ## exceptions that should not be rescued by default
17
- ## (if you want to implement custom error handling);
18
- ## supports SocketError and TimeoutError
19
- # config.always_raise = []
20
-
21
- ## Calculation options
22
- # config.units = :mi # :km for kilometers or :mi for miles
23
- # config.distances = :linear # :spherical or :linear
18
+ # calculation options
19
+ # :units => :mi, # :km for kilometers or :mi for miles
20
+ # :distances => :linear # :spherical or :linear
24
21
  end
25
-
@@ -43,10 +43,8 @@ module Geocoder
43
43
  # The working Cache object, or +nil+ if none configured.
44
44
  #
45
45
  def cache
46
- if @cache.nil? and store = Configuration.cache
47
- @cache = Cache.new(store, Configuration.cache_prefix)
48
- end
49
- @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).send(:configuration).cache
50
48
  end
51
49
  end
52
50
 
@@ -78,7 +78,8 @@ module Geocoder
78
78
  end
79
79
 
80
80
  def expire_single_url(url)
81
- store.del(key_for(url))
81
+ key = key_for(url)
82
+ store.respond_to?(:del) ? store.del(key) : store.delete(key)
82
83
  end
83
84
  end
84
85
  end
@@ -40,7 +40,7 @@ module Geocoder
40
40
  # Distance spanned by one degree of latitude in the given units.
41
41
  #
42
42
  def latitude_degree_distance(units = nil)
43
- units ||= Geocoder::Configuration.units
43
+ units ||= Geocoder.config.units
44
44
  2 * Math::PI * earth_radius(units) / 360
45
45
  end
46
46
 
@@ -49,7 +49,7 @@ module Geocoder
49
49
  # This ranges from around 69 miles at the equator to zero at the poles.
50
50
  #
51
51
  def longitude_degree_distance(latitude, units = nil)
52
- units ||= Geocoder::Configuration.units
52
+ units ||= Geocoder.config.units
53
53
  latitude_degree_distance(units) * Math.cos(to_radians(latitude))
54
54
  end
55
55
 
@@ -67,12 +67,12 @@ module Geocoder
67
67
  # The options hash supports:
68
68
  #
69
69
  # * <tt>:units</tt> - <tt>:mi</tt> or <tt>:km</tt>
70
- # See Geocoder::Configuration to know how configure default units.
70
+ # Use Geocoder.configure(:units => ...) to configure default units.
71
71
  #
72
72
  def distance_between(point1, point2, options = {})
73
73
 
74
74
  # set default options
75
- options[:units] ||= Geocoder::Configuration.units
75
+ options[:units] ||= Geocoder.config.units
76
76
 
77
77
  # convert to coordinate arrays
78
78
  point1 = extract_coordinates(point1)
@@ -103,14 +103,14 @@ module Geocoder
103
103
  # the spherical method is "correct" in that it returns the shortest path
104
104
  # (one along a great circle) but the linear method is less confusing
105
105
  # (returns due east or west when given two points with the same latitude).
106
- # See Geocoder::Configuration to know how configure default method.
106
+ # Use Geocoder.configure(:distances => ...) to configure calculation method.
107
107
  #
108
108
  # Based on: http://www.movable-type.co.uk/scripts/latlong.html
109
109
  #
110
110
  def bearing_between(point1, point2, options = {})
111
111
 
112
112
  # set default options
113
- options[:method] ||= Geocoder::Configuration.distances
113
+ options[:method] ||= Geocoder.config.distances
114
114
  options[:method] = :linear unless options[:method] == :spherical
115
115
 
116
116
  # convert to coordinate arrays
@@ -197,12 +197,12 @@ module Geocoder
197
197
  # ways of specifying the point. Also accepts an options hash:
198
198
  #
199
199
  # * <tt>:units</tt> - <tt>:mi</tt> or <tt>:km</tt>.
200
- # See Geocoder::Configuration to know how configure default units.
200
+ # Use Geocoder.configure(:units => ...) to configure default units.
201
201
  #
202
202
  def bounding_box(point, radius, options = {})
203
203
  lat,lon = extract_coordinates(point)
204
204
  radius = radius.to_f
205
- units = options[:units] || Geocoder::Configuration.units
205
+ units = options[:units] || Geocoder.config.units
206
206
  [
207
207
  lat - (radius / latitude_degree_distance(units)),
208
208
  lon - (radius / longitude_degree_distance(lat, units)),
@@ -240,12 +240,12 @@ module Geocoder
240
240
  end
241
241
 
242
242
  def distance_to_radians(distance, units = nil)
243
- units ||= Geocoder::Configuration.units
243
+ units ||= Geocoder.config.units
244
244
  distance.to_f / earth_radius(units)
245
245
  end
246
246
 
247
247
  def radians_to_distance(radians, units = nil)
248
- units ||= Geocoder::Configuration.units
248
+ units ||= Geocoder.config.units
249
249
  radians * earth_radius(units)
250
250
  end
251
251
 
@@ -265,10 +265,10 @@ module Geocoder
265
265
 
266
266
  ##
267
267
  # Radius of the Earth in the given units (:mi or :km).
268
- # See Geocoder::Configuration to know how configure default units.
268
+ # Use Geocoder.configure(:units => ...) to configure default units.
269
269
  #
270
270
  def earth_radius(units = nil)
271
- units ||= Geocoder::Configuration.units
271
+ units ||= Geocoder.config.units
272
272
  units == :km ? EARTH_RADIUS : to_miles(EARTH_RADIUS)
273
273
  end
274
274
 
@@ -13,34 +13,33 @@ module Geocoder
13
13
  opts.separator "\nOptions: "
14
14
 
15
15
  opts.on("-k <key>", "--key <key>",
16
- "Key for geocoding API (optional for most). For Google Premier use 'key client channel' separated by spaces") do |key|
17
- premier_key = key.split(' ')
18
- if premier_key.length == 3
19
- Geocoder::Configuration.api_key = premier_key
16
+ "Key for geocoding API (usually optional). Enclose multi-part keys in quotes and separate parts by spaces") do |key|
17
+ if (key_parts = key.split(/\s+/)).size > 1
18
+ Geocoder.configure(:api_key => key_parts)
20
19
  else
21
- Geocoder::Configuration.api_key = key
20
+ Geocoder.configure(:api_key => key)
22
21
  end
23
22
  end
24
23
 
25
24
  opts.on("-l <language>", "--language <language>",
26
25
  "Language of output (see API docs for valid choices)") do |language|
27
- Geocoder::Configuration.language = language
26
+ Geocoder.configure(:language => language)
28
27
  end
29
28
 
30
29
  opts.on("-p <proxy>", "--proxy <proxy>",
31
30
  "HTTP proxy server to use (user:pass@host:port)") do |proxy|
32
- Geocoder::Configuration.http_proxy = proxy
31
+ Geocoder.configure(:http_proxy => proxy)
33
32
  end
34
33
 
35
34
  opts.on("-s <service>", Geocoder::Lookup.all_services_except_test, "--service <service>",
36
35
  "Geocoding service: #{Geocoder::Lookup.all_services_except_test * ', '}") do |service|
37
- Geocoder::Configuration.lookup = service.to_sym
38
- Geocoder::Configuration.ip_lookup = service.to_sym
36
+ Geocoder.configure(:lookup => service.to_sym)
37
+ Geocoder.configure(:ip_lookup => service.to_sym)
39
38
  end
40
39
 
41
40
  opts.on("-t <seconds>", "--timeout <seconds>",
42
41
  "Maximum number of seconds to wait for API response") do |timeout|
43
- Geocoder::Configuration.timeout = timeout.to_i
42
+ Geocoder.configure(:timeout => timeout.to_i)
44
43
  end
45
44
 
46
45
  opts.on("-j", "--json", "Print API's raw JSON response") do
@@ -80,7 +79,7 @@ module Geocoder
80
79
 
81
80
  if show_url
82
81
  q = Geocoder::Query.new(query)
83
- out << q.lookup.send(:query_url, q) + "\n"
82
+ out << q.url + "\n"
84
83
  exit 0
85
84
  end
86
85
 
@@ -1,39 +1,49 @@
1
1
  require 'singleton'
2
+ require 'geocoder/configuration_hash'
2
3
 
3
4
  module Geocoder
4
5
 
5
6
  ##
6
- # Provides convenient access to the Configuration singleton.
7
+ # Configuration options should be set by passing a hash:
7
8
  #
8
- def self.configure(&block)
9
+ # Geocoder.configure(
10
+ # :timeout => 5,
11
+ # :lookup => :yandex,
12
+ # :api_key => "2a9fsa983jaslfj982fjasd",
13
+ # :units => :km
14
+ # )
15
+ #
16
+ def self.configure(options = nil, &block)
9
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 => ...))."
10
19
  block.call(Configuration.instance)
20
+ elsif !options.nil?
21
+ Configuration.instance.configure(options)
11
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)."
12
24
  Configuration.instance
13
25
  end
14
26
  end
15
27
 
16
28
  ##
17
- # This class handles geocoder Geocoder configuration
18
- # (geocoding service provider, caching, units of measurement, etc).
19
- # Configuration can be done in two ways:
20
- #
21
- # 1) Using Geocoder.configure and passing a block
22
- # (useful for configuring multiple things at once):
23
- #
24
- # Geocoder.configure do |config|
25
- # config.timeout = 5
26
- # config.lookup = :yandex
27
- # config.api_key = "2a9fsa983jaslfj982fjasd"
28
- # config.units = :km
29
- # end
29
+ # Read-only access to the singleton's config data.
30
30
  #
31
- # 2) Using the Geocoder::Configuration singleton directly:
32
- #
33
- # Geocoder::Configuration.language = 'pt-BR'
34
- #
35
- # Default values are defined in Configuration#set_defaults.
31
+ def self.config
32
+ Configuration.instance.data
33
+ end
34
+
35
+ ##
36
+ # Read-only access to lookup-specific config data.
36
37
  #
38
+ def self.config_for_lookup(lookup_name)
39
+ data = config.clone
40
+ data.reject!{ |key,value| !Configuration::OPTIONS.include?(key) }
41
+ if config.has_key?(lookup_name)
42
+ data.merge!(config[lookup_name])
43
+ end
44
+ data
45
+ end
46
+
37
47
  class Configuration
38
48
  include Singleton
39
49
 
@@ -54,53 +64,67 @@ module Geocoder
54
64
  :distances
55
65
  ]
56
66
 
57
- attr_accessor *OPTIONS
67
+ attr_accessor :data
68
+
69
+ def self.set_defaults
70
+ instance.set_defaults
71
+ end
72
+
73
+ OPTIONS.each do |o|
74
+ define_method o do
75
+ @data[o]
76
+ end
77
+ define_method "#{o}=" do |value|
78
+ @data[o] = value
79
+ end
80
+ end
81
+
82
+ def configure(options)
83
+ @data.rmerge!(options)
84
+ end
58
85
 
59
86
  def initialize # :nodoc
87
+ @data = Geocoder::ConfigurationHash.new
60
88
  set_defaults
61
89
  end
62
90
 
63
91
  def set_defaults
64
- @timeout = 3 # geocoding service timeout (secs)
65
- @lookup = :google # name of street address geocoding service (symbol)
66
- @ip_lookup = :freegeoip # name of IP address geocoding service (symbol)
67
- @language = :en # ISO-639 language code
68
- @http_headers = {} # HTTP headers for lookup
69
- @use_https = false # use HTTPS for lookup requests? (if supported)
70
- @http_proxy = nil # HTTP proxy server (user:pass@host:port)
71
- @https_proxy = nil # HTTPS proxy server (user:pass@host:port)
72
- @api_key = nil # API key for geocoding service
73
- @cache = nil # cache object (must respond to #[], #[]=, and #keys)
74
- @cache_prefix = "geocoder:" # prefix (string) to use for all cache keys
92
+
93
+ # geocoding options
94
+ @data[:timeout] = 3 # geocoding service timeout (secs)
95
+ @data[:lookup] = :google # name of street address geocoding service (symbol)
96
+ @data[:ip_lookup] = :freegeoip # name of IP address geocoding service (symbol)
97
+ @data[:language] = :en # ISO-639 language code
98
+ @data[:http_headers] = {} # HTTP headers for lookup
99
+ @data[:use_https] = false # use HTTPS for lookup requests? (if supported)
100
+ @data[:http_proxy] = nil # HTTP proxy server (user:pass@host:port)
101
+ @data[:https_proxy] = nil # HTTPS proxy server (user:pass@host:port)
102
+ @data[:api_key] = nil # API key for geocoding service
103
+ @data[:cache] = nil # cache object (must respond to #[], #[]=, and #keys)
104
+ @data[:cache_prefix] = "geocoder:" # prefix (string) to use for all cache keys
75
105
 
76
106
  # exceptions that should not be rescued by default
77
107
  # (if you want to implement custom error handling);
78
108
  # supports SocketError and TimeoutError
79
- @always_raise = []
109
+ @data[:always_raise] = []
80
110
 
81
111
  # calculation options
82
- @units = :mi # :mi or :km
83
- @distances = :linear # :linear or :spherical
112
+ @data[:units] = :mi # :mi or :km
113
+ @data[:distances] = :linear # :linear or :spherical
84
114
  end
85
115
 
86
116
  instance_eval(OPTIONS.map do |option|
87
117
  o = option.to_s
88
118
  <<-EOS
89
119
  def #{o}
90
- instance.#{o}
120
+ instance.data[:#{o}]
91
121
  end
92
122
 
93
123
  def #{o}=(value)
94
- instance.#{o} = value
124
+ instance.data[:#{o}] = value
95
125
  end
96
126
  EOS
97
127
  end.join("\n\n"))
98
128
 
99
- class << self
100
- def set_defaults
101
- instance.set_defaults
102
- end
103
- end
104
-
105
129
  end
106
130
  end
@@ -0,0 +1,11 @@
1
+ require 'hash_recursive_merge'
2
+
3
+ module Geocoder
4
+ class ConfigurationHash < Hash
5
+ include HashRecursiveMerge
6
+
7
+ def method_missing(meth, *args, &block)
8
+ has_key?(meth) ? self[meth] : super
9
+ end
10
+ end
11
+ end
@@ -15,4 +15,7 @@ module Geocoder
15
15
  class InvalidRequest < Error
16
16
  end
17
17
 
18
+ class InvalidApiKey < Error
19
+ end
20
+
18
21
  end
@@ -37,7 +37,7 @@ module Geocoder
37
37
  # All IP address lookup services, default first.
38
38
  #
39
39
  def ip_services
40
- [:freegeoip]
40
+ [:freegeoip, :maxmind]
41
41
  end
42
42
 
43
43
  ##
@@ -16,6 +16,21 @@ module Geocoder
16
16
 
17
17
  class Base
18
18
 
19
+ ##
20
+ # Human-readable name of the geocoding API.
21
+ #
22
+ def name
23
+ fail
24
+ end
25
+
26
+ ##
27
+ # Symbol which is used in configuration to refer to this Lookup.
28
+ #
29
+ def handle
30
+ str = self.class.to_s
31
+ str[str.rindex(':')+1..-1].gsub(/([a-z\d]+)([A-Z])/,'\1_\2').downcase.to_sym
32
+ end
33
+
19
34
  ##
20
35
  # Query the geocoding API and return a Geocoder::Result object.
21
36
  # Returns +nil+ on timeout or error.
@@ -43,16 +58,37 @@ module Geocoder
43
58
  nil
44
59
  end
45
60
 
61
+ ##
62
+ # Array containing string descriptions of keys required by the API.
63
+ # Empty array if keys are optional or not required.
64
+ #
65
+ def required_api_key_parts
66
+ []
67
+ end
68
+
69
+ ##
70
+ # URL to use for querying the geocoding engine.
71
+ #
72
+ def query_url(query)
73
+ fail
74
+ end
46
75
 
47
76
  private # -------------------------------------------------------------
48
77
 
78
+ ##
79
+ # An object with configuration data for this particular lookup.
80
+ #
81
+ def configuration
82
+ Geocoder.config_for_lookup(handle)
83
+ end
84
+
49
85
  ##
50
86
  # Object used to make HTTP requests.
51
87
  #
52
88
  def http_client
53
- protocol = "http#{'s' if Geocoder::Configuration.use_https}"
89
+ protocol = "http#{'s' if configuration.use_https}"
54
90
  proxy_name = "#{protocol}_proxy"
55
- if proxy = Geocoder::Configuration.send(proxy_name)
91
+ if proxy = configuration.send(proxy_name)
56
92
  proxy_url = protocol + '://' + proxy
57
93
  begin
58
94
  uri = URI.parse(proxy_url)
@@ -83,13 +119,6 @@ module Geocoder
83
119
  )
84
120
  end
85
121
 
86
- ##
87
- # URL to use for querying the geocoding engine.
88
- #
89
- def query_url(query)
90
- fail
91
- end
92
-
93
122
  ##
94
123
  # Key to use for caching a geocoding result. Usually this will be the
95
124
  # request URL, but in cases where OAuth is used and the nonce,
@@ -112,7 +141,7 @@ module Geocoder
112
141
  # Return false if exception not raised.
113
142
  #
114
143
  def raise_error(error, message = nil)
115
- exceptions = Geocoder::Configuration.always_raise
144
+ exceptions = configuration.always_raise
116
145
  if exceptions == :all or exceptions.include?( error.is_a?(Class) ? error : error.class )
117
146
  raise error, message
118
147
  else
@@ -129,7 +158,7 @@ module Geocoder
129
158
  raise_error(err) or warn "Geocoding API connection cannot be established."
130
159
  rescue TimeoutError => err
131
160
  raise_error(err) or warn "Geocoding API not responding fast enough " +
132
- "(see Geocoder::Configuration.timeout to set limit)."
161
+ "(use Geocoder.configure(:timeout => ...) to set limit)."
133
162
  end
134
163
 
135
164
  ##
@@ -150,7 +179,7 @@ module Geocoder
150
179
  # Set in configuration but not available for every service.
151
180
  #
152
181
  def protocol
153
- "http" + (Geocoder::Configuration.use_https ? "s" : "")
182
+ "http" + (configuration.use_https ? "s" : "")
154
183
  end
155
184
 
156
185
  ##
@@ -162,6 +191,7 @@ module Geocoder
162
191
  if cache and body = cache[key]
163
192
  @cache_hit = true
164
193
  else
194
+ check_api_key_configuration!(query)
165
195
  response = make_api_request(query)
166
196
  body = response.body
167
197
  if cache and (200..399).include?(response.code.to_i)
@@ -177,11 +207,21 @@ module Geocoder
177
207
  # return the response object.
178
208
  #
179
209
  def make_api_request(query)
180
- timeout(Geocoder::Configuration.timeout) do
210
+ timeout(configuration.timeout) do
181
211
  uri = URI.parse(query_url(query))
182
212
  client = http_client.new(uri.host, uri.port)
183
- client.use_ssl = true if Geocoder::Configuration.use_https
184
- client.get(uri.request_uri, Geocoder::Configuration.http_headers)
213
+ client.use_ssl = true if configuration.use_https
214
+ client.get(uri.request_uri, configuration.http_headers)
215
+ end
216
+ end
217
+
218
+ def check_api_key_configuration!(query)
219
+ key_parts = query.lookup.required_api_key_parts
220
+ if key_parts.size > Array(configuration.api_key).size
221
+ parts_string = key_parts.size == 1 ? key_parts.first : key_parts
222
+ raise Geocoder::ConfigurationError,
223
+ "The #{query.lookup.name} API requires a key to be configured: " +
224
+ parts_string.inspect
185
225
  end
186
226
  end
187
227
 
@@ -189,7 +229,10 @@ module Geocoder
189
229
  # The working Cache object.
190
230
  #
191
231
  def cache
192
- Geocoder.cache
232
+ if @cache.nil? and store = configuration.cache
233
+ @cache = Cache.new(store, configuration.cache_prefix)
234
+ end
235
+ @cache
193
236
  end
194
237
 
195
238
  ##