geocoder 1.1.3 → 1.1.6

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 (98) hide show
  1. data/.travis.yml +4 -0
  2. data/{CHANGELOG.rdoc → CHANGELOG.md} +109 -35
  3. data/README.md +645 -0
  4. data/examples/autoexpire_cache.rb +28 -0
  5. data/lib/generators/geocoder/config/templates/initializer.rb +18 -22
  6. data/lib/geocoder/cache.rb +2 -1
  7. data/lib/geocoder/calculations.rb +13 -13
  8. data/lib/geocoder/cli.rb +17 -19
  9. data/lib/geocoder/configuration.rb +68 -42
  10. data/lib/geocoder/configuration_hash.rb +11 -0
  11. data/lib/geocoder/exceptions.rb +3 -0
  12. data/lib/geocoder/lookup.rb +81 -0
  13. data/lib/geocoder/lookups/base.rb +106 -56
  14. data/lib/geocoder/lookups/bing.rb +25 -11
  15. data/lib/geocoder/lookups/freegeoip.rb +11 -7
  16. data/lib/geocoder/lookups/geocoder_ca.rb +17 -9
  17. data/lib/geocoder/lookups/google.rb +29 -8
  18. data/lib/geocoder/lookups/google_premier.rb +20 -11
  19. data/lib/geocoder/lookups/mapquest.rb +29 -19
  20. data/lib/geocoder/lookups/maxmind.rb +72 -0
  21. data/lib/geocoder/lookups/nominatim.rb +21 -13
  22. data/lib/geocoder/lookups/test.rb +12 -6
  23. data/lib/geocoder/lookups/yahoo.rb +63 -13
  24. data/lib/geocoder/lookups/yandex.rb +26 -11
  25. data/lib/geocoder/models/mongoid.rb +1 -2
  26. data/lib/geocoder/query.rb +103 -0
  27. data/lib/geocoder/request.rb +7 -1
  28. data/lib/geocoder/results/base.rb +8 -2
  29. data/lib/geocoder/results/google.rb +6 -0
  30. data/lib/geocoder/results/mapquest.rb +19 -34
  31. data/lib/geocoder/results/maxmind.rb +136 -0
  32. data/lib/geocoder/results/nominatim.rb +14 -3
  33. data/lib/geocoder/results/yahoo.rb +9 -2
  34. data/lib/geocoder/sql.rb +106 -0
  35. data/lib/geocoder/stores/active_record.rb +75 -142
  36. data/lib/geocoder/stores/base.rb +3 -2
  37. data/lib/geocoder/stores/mongo_base.rb +2 -2
  38. data/lib/geocoder/version.rb +1 -1
  39. data/lib/geocoder.rb +11 -89
  40. data/lib/hash_recursive_merge.rb +74 -0
  41. data/lib/oauth_util.rb +112 -0
  42. data/test/active_record_test.rb +15 -0
  43. data/test/cache_test.rb +19 -0
  44. data/test/calculations_test.rb +11 -4
  45. data/test/configuration_test.rb +26 -51
  46. data/test/error_handling_test.rb +15 -11
  47. data/test/fixtures/bing_invalid_key +1 -0
  48. data/test/fixtures/mapquest_madison_square_garden +52 -0
  49. data/test/fixtures/mapquest_no_results +7 -0
  50. data/test/fixtures/maxmind_24_24_24_21 +1 -0
  51. data/test/fixtures/maxmind_24_24_24_22 +1 -0
  52. data/test/fixtures/maxmind_24_24_24_23 +1 -0
  53. data/test/fixtures/maxmind_24_24_24_24 +1 -0
  54. data/test/fixtures/maxmind_74_200_247_59 +1 -0
  55. data/test/fixtures/maxmind_invalid_key +1 -0
  56. data/test/fixtures/maxmind_no_results +1 -0
  57. data/test/fixtures/yahoo_error +1 -0
  58. data/test/fixtures/yahoo_invalid_key +2 -0
  59. data/test/fixtures/yahoo_madison_square_garden +52 -0
  60. data/test/fixtures/yahoo_no_results +10 -0
  61. data/test/fixtures/yahoo_over_limit +2 -0
  62. data/test/https_test.rb +3 -3
  63. data/test/integration/smoke_test.rb +8 -6
  64. data/test/lookup_test.rb +92 -13
  65. data/test/near_test.rb +11 -0
  66. data/test/oauth_util_test.rb +30 -0
  67. data/test/proxy_test.rb +2 -2
  68. data/test/query_test.rb +42 -0
  69. data/test/result_test.rb +4 -3
  70. data/test/services_test.rb +164 -26
  71. data/test/test_helper.rb +93 -112
  72. data/test/test_mode_test.rb +3 -4
  73. metadata +52 -35
  74. data/README.rdoc +0 -552
  75. data/test/fixtures/mapquest_madison_square_garden.json +0 -27
  76. data/test/fixtures/mapquest_no_results.json +0 -1
  77. data/test/fixtures/yahoo_garbage.json +0 -50
  78. data/test/fixtures/yahoo_madison_square_garden.json +0 -46
  79. data/test/fixtures/yahoo_no_results.json +0 -10
  80. data/test/input_handling_test.rb +0 -43
  81. /data/test/fixtures/{bing_madison_square_garden.json → bing_madison_square_garden} +0 -0
  82. /data/test/fixtures/{bing_no_results.json → bing_no_results} +0 -0
  83. /data/test/fixtures/{bing_reverse.json → bing_reverse} +0 -0
  84. /data/test/fixtures/{freegeoip_74_200_247_59.json → freegeoip_74_200_247_59} +0 -0
  85. /data/test/fixtures/{freegeoip_no_results.json → freegeoip_no_results} +0 -0
  86. /data/test/fixtures/{geocoder_ca_madison_square_garden.json → geocoder_ca_madison_square_garden} +0 -0
  87. /data/test/fixtures/{geocoder_ca_no_results.json → geocoder_ca_no_results} +0 -0
  88. /data/test/fixtures/{geocoder_ca_reverse.json → geocoder_ca_reverse} +0 -0
  89. /data/test/fixtures/{google_garbage.json → google_garbage} +0 -0
  90. /data/test/fixtures/{google_madison_square_garden.json → google_madison_square_garden} +0 -0
  91. /data/test/fixtures/{google_no_city_data.json → google_no_city_data} +0 -0
  92. /data/test/fixtures/{google_no_locality.json → google_no_locality} +0 -0
  93. /data/test/fixtures/{google_no_results.json → google_no_results} +0 -0
  94. /data/test/fixtures/{nominatim_madison_square_garden.json → nominatim_madison_square_garden} +0 -0
  95. /data/test/fixtures/{nominatim_no_results.json → nominatim_no_results} +0 -0
  96. /data/test/fixtures/{yandex_invalid_key.json → yandex_invalid_key} +0 -0
  97. /data/test/fixtures/{yandex_kremlin.json → yandex_kremlin} +0 -0
  98. /data/test/fixtures/{yandex_no_results.json → yandex_no_results} +0 -0
@@ -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
-
@@ -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
@@ -184,7 +184,7 @@ module Geocoder
184
184
  end
185
185
 
186
186
  ##
187
- # Returns coordinates of the lower-left and upper-right corners of a box
187
+ # Returns coordinates of the southwest and northeast corners of a box
188
188
  # with the given point at its center. The radius is the shortest distance
189
189
  # from the center point to any side of the box (the length of each side
190
190
  # is twice the radius).
@@ -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
 
data/lib/geocoder/cli.rb CHANGED
@@ -13,33 +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
- opts.on("-s <service>", Geocoder.street_lookups, "--service <service>",
36
- "Geocoding service: #{Geocoder.street_lookups * ', '}") do |service|
37
- Geocoder::Configuration.lookup = service.to_sym
34
+ opts.on("-s <service>", Geocoder::Lookup.all_services_except_test, "--service <service>",
35
+ "Geocoding service: #{Geocoder::Lookup.all_services_except_test * ', '}") do |service|
36
+ Geocoder.configure(:lookup => service.to_sym)
37
+ Geocoder.configure(:ip_lookup => service.to_sym)
38
38
  end
39
39
 
40
40
  opts.on("-t <seconds>", "--timeout <seconds>",
41
41
  "Maximum number of seconds to wait for API response") do |timeout|
42
- Geocoder::Configuration.timeout = timeout.to_i
42
+ Geocoder.configure(:timeout => timeout.to_i)
43
43
  end
44
44
 
45
45
  opts.on("-j", "--json", "Print API's raw JSON response") do
@@ -78,21 +78,19 @@ module Geocoder
78
78
  end
79
79
 
80
80
  if show_url
81
- lookup = Geocoder.send(:lookup, query)
82
- reverse = lookup.send(:coordinates?, query)
83
- out << lookup.send(:query_url, query, reverse) + "\n"
81
+ q = Geocoder::Query.new(query)
82
+ out << q.url + "\n"
84
83
  exit 0
85
84
  end
86
85
 
87
86
  if show_json
88
- lookup = Geocoder.send(:lookup, query)
89
- reverse = lookup.send(:coordinates?, query)
90
- out << lookup.send(:fetch_raw_data, query, reverse) + "\n"
87
+ q = Geocoder::Query.new(query)
88
+ out << q.lookup.send(:fetch_raw_data, q) + "\n"
91
89
  exit 0
92
90
  end
93
91
 
94
92
  if (result = Geocoder.search(query).first)
95
- lookup = Geocoder.send(:get_lookup, :google)
93
+ google = Geocoder::Lookup.get(:google)
96
94
  lines = [
97
95
  ["Latitude", result.latitude],
98
96
  ["Longitude", result.longitude],
@@ -101,7 +99,7 @@ module Geocoder
101
99
  ["State/province", result.state],
102
100
  ["Postal code", result.postal_code],
103
101
  ["Country", result.country],
104
- ["Google map", lookup.map_link_url(result.coordinates)],
102
+ ["Google map", google.map_link_url(result.coordinates)],
105
103
  ]
106
104
  lines.each do |line|
107
105
  out << (line[0] + ": ").ljust(18) + line[1].to_s + "\n"
@@ -1,45 +1,56 @@
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 = :yahoo
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
 
40
50
  OPTIONS = [
41
51
  :timeout,
42
52
  :lookup,
53
+ :ip_lookup,
43
54
  :language,
44
55
  :http_headers,
45
56
  :use_https,
@@ -53,52 +64,67 @@ module Geocoder
53
64
  :distances
54
65
  ]
55
66
 
56
- 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
57
85
 
58
86
  def initialize # :nodoc
87
+ @data = Geocoder::ConfigurationHash.new
59
88
  set_defaults
60
89
  end
61
90
 
62
91
  def set_defaults
63
- @timeout = 3 # geocoding service timeout (secs)
64
- @lookup = :google # name of geocoding service (symbol)
65
- @language = :en # ISO-639 language code
66
- @http_headers = {} # HTTP headers for lookup
67
- @use_https = false # use HTTPS for lookup requests? (if supported)
68
- @http_proxy = nil # HTTP proxy server (user:pass@host:port)
69
- @https_proxy = nil # HTTPS proxy server (user:pass@host:port)
70
- @api_key = nil # API key for geocoding service
71
- @cache = nil # cache object (must respond to #[], #[]=, and #keys)
72
- @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
73
105
 
74
106
  # exceptions that should not be rescued by default
75
107
  # (if you want to implement custom error handling);
76
108
  # supports SocketError and TimeoutError
77
- @always_raise = []
109
+ @data[:always_raise] = []
78
110
 
79
111
  # calculation options
80
- @units = :mi # :mi or :km
81
- @distances = :linear # :linear or :spherical
112
+ @data[:units] = :mi # :mi or :km
113
+ @data[:distances] = :linear # :linear or :spherical
82
114
  end
83
115
 
84
116
  instance_eval(OPTIONS.map do |option|
85
117
  o = option.to_s
86
118
  <<-EOS
87
119
  def #{o}
88
- instance.#{o}
120
+ instance.data[:#{o}]
89
121
  end
90
122
 
91
123
  def #{o}=(value)
92
- instance.#{o} = value
124
+ instance.data[:#{o}] = value
93
125
  end
94
126
  EOS
95
127
  end.join("\n\n"))
96
128
 
97
- class << self
98
- def set_defaults
99
- instance.set_defaults
100
- end
101
- end
102
-
103
129
  end
104
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
@@ -0,0 +1,81 @@
1
+ module Geocoder
2
+ module Lookup
3
+ extend self
4
+
5
+ ##
6
+ # Array of valid Lookup service names.
7
+ #
8
+ def all_services
9
+ street_services + ip_services
10
+ end
11
+
12
+ ##
13
+ # Array of valid Lookup service names, excluding :test.
14
+ #
15
+ def all_services_except_test
16
+ all_services - [:test]
17
+ end
18
+
19
+ ##
20
+ # All street address lookup services, default first.
21
+ #
22
+ def street_services
23
+ [
24
+ :google,
25
+ :google_premier,
26
+ :yahoo,
27
+ :bing,
28
+ :geocoder_ca,
29
+ :yandex,
30
+ :nominatim,
31
+ :mapquest,
32
+ :test
33
+ ]
34
+ end
35
+
36
+ ##
37
+ # All IP address lookup services, default first.
38
+ #
39
+ def ip_services
40
+ [:freegeoip, :maxmind]
41
+ end
42
+
43
+ ##
44
+ # Retrieve a Lookup object from the store.
45
+ # Use this instead of Geocoder::Lookup::X.new to get an
46
+ # already-configured Lookup object.
47
+ #
48
+ def get(name)
49
+ @services = {} unless defined?(@services)
50
+ @services[name] = spawn(name) unless @services.include?(name)
51
+ @services[name]
52
+ end
53
+
54
+
55
+ private # -----------------------------------------------------------------
56
+
57
+ ##
58
+ # Spawn a Lookup of the given name.
59
+ #
60
+ def spawn(name)
61
+ if all_services.include?(name)
62
+ Geocoder::Lookup.const_get(classify_name(name)).new
63
+ else
64
+ valids = all_services.map(&:inspect).join(", ")
65
+ raise ConfigurationError, "Please specify a valid lookup for Geocoder " +
66
+ "(#{name.inspect} is not one of: #{valids})."
67
+ end
68
+ end
69
+
70
+ ##
71
+ # Convert an "underscore" version of a name into a "class" version.
72
+ #
73
+ def classify_name(filename)
74
+ filename.to_s.split("_").map{ |i| i[0...1].upcase + i[1..-1] }.join
75
+ end
76
+ end
77
+ end
78
+
79
+ Geocoder::Lookup.all_services.each do |name|
80
+ require "geocoder/lookups/#{name}"
81
+ end