geocoder 1.6.6 → 1.8.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +68 -2
  3. data/README.md +355 -211
  4. data/examples/app_defined_lookup_services.rb +22 -0
  5. data/lib/generators/geocoder/config/templates/initializer.rb +6 -1
  6. data/lib/geocoder/cache.rb +14 -35
  7. data/lib/geocoder/cache_stores/base.rb +40 -0
  8. data/lib/geocoder/cache_stores/generic.rb +35 -0
  9. data/lib/geocoder/cache_stores/redis.rb +34 -0
  10. data/lib/geocoder/configuration.rb +17 -4
  11. data/lib/geocoder/ip_address.rb +9 -0
  12. data/lib/geocoder/lookup.rb +37 -5
  13. data/lib/geocoder/lookups/abstract_api.rb +46 -0
  14. data/lib/geocoder/lookups/amap.rb +2 -2
  15. data/lib/geocoder/lookups/amazon_location_service.rb +58 -0
  16. data/lib/geocoder/lookups/azure.rb +56 -0
  17. data/lib/geocoder/lookups/ban_data_gouv_fr.rb +1 -1
  18. data/lib/geocoder/lookups/base.rb +2 -1
  19. data/lib/geocoder/lookups/bing.rb +2 -2
  20. data/lib/geocoder/lookups/esri.rb +18 -5
  21. data/lib/geocoder/lookups/freegeoip.rb +8 -6
  22. data/lib/geocoder/lookups/geoapify.rb +78 -0
  23. data/lib/geocoder/lookups/geoip2.rb +4 -0
  24. data/lib/geocoder/lookups/geoportail_lu.rb +1 -1
  25. data/lib/geocoder/lookups/google_places_details.rb +20 -0
  26. data/lib/geocoder/lookups/google_places_search.rb +21 -5
  27. data/lib/geocoder/lookups/here.rb +25 -20
  28. data/lib/geocoder/lookups/ip2location.rb +10 -6
  29. data/lib/geocoder/lookups/ip2location_io.rb +62 -0
  30. data/lib/geocoder/lookups/ip2location_lite.rb +40 -0
  31. data/lib/geocoder/lookups/ipbase.rb +49 -0
  32. data/lib/geocoder/lookups/ipdata_co.rb +1 -1
  33. data/lib/geocoder/lookups/ipqualityscore.rb +50 -0
  34. data/lib/geocoder/lookups/location_iq.rb +5 -1
  35. data/lib/geocoder/lookups/mapbox.rb +3 -3
  36. data/lib/geocoder/lookups/melissa_street.rb +41 -0
  37. data/lib/geocoder/lookups/pc_miler.rb +85 -0
  38. data/lib/geocoder/lookups/pdok_nl.rb +43 -0
  39. data/lib/geocoder/lookups/photon.rb +89 -0
  40. data/lib/geocoder/lookups/test.rb +1 -0
  41. data/lib/geocoder/lookups/twogis.rb +58 -0
  42. data/lib/geocoder/lookups/uk_ordnance_survey_names.rb +1 -1
  43. data/lib/geocoder/lookups/yandex.rb +3 -3
  44. data/lib/geocoder/query.rb +1 -1
  45. data/lib/geocoder/results/abstract_api.rb +146 -0
  46. data/lib/geocoder/results/amazon_location_service.rb +62 -0
  47. data/lib/geocoder/results/azure.rb +65 -0
  48. data/lib/geocoder/results/ban_data_gouv_fr.rb +1 -1
  49. data/lib/geocoder/results/esri.rb +5 -2
  50. data/lib/geocoder/results/geoapify.rb +179 -0
  51. data/lib/geocoder/results/here.rb +20 -25
  52. data/lib/geocoder/results/ip2location_io.rb +21 -0
  53. data/lib/geocoder/results/ip2location_lite.rb +47 -0
  54. data/lib/geocoder/results/ipbase.rb +40 -0
  55. data/lib/geocoder/results/ipqualityscore.rb +54 -0
  56. data/lib/geocoder/results/mapbox.rb +34 -10
  57. data/lib/geocoder/results/melissa_street.rb +46 -0
  58. data/lib/geocoder/results/nominatim.rb +24 -16
  59. data/lib/geocoder/results/pc_miler.rb +98 -0
  60. data/lib/geocoder/results/pdok_nl.rb +62 -0
  61. data/lib/geocoder/results/photon.rb +119 -0
  62. data/lib/geocoder/results/twogis.rb +76 -0
  63. data/lib/geocoder/version.rb +1 -1
  64. data/lib/maxmind_database.rb +12 -12
  65. data/lib/tasks/maxmind.rake +1 -1
  66. metadata +65 -11
  67. data/examples/autoexpire_cache_dalli.rb +0 -62
  68. data/examples/autoexpire_cache_redis.rb +0 -30
  69. data/lib/geocoder/lookups/dstk.rb +0 -22
  70. data/lib/geocoder/results/dstk.rb +0 -6
@@ -0,0 +1,22 @@
1
+ # To extend the Geocoder with additional lookups that come from the application,
2
+ # not shipped with the gem, define a "child" lookup in your application, based on existing one.
3
+ # This is required because the Geocoder::Configuration is a Singleton and stores one api key per lookup.
4
+
5
+ # in app/libs/geocoder/lookup/my_preciousss.rb
6
+ module Geocoder::Lookup
7
+ class MyPreciousss < Google
8
+ end
9
+ end
10
+
11
+ # Update Geocoder's street_services on initialize:
12
+ # config/initializers/geocoder.rb
13
+ Geocoder::Lookup.street_services << :my_preciousss
14
+
15
+ # Override the configuration when necessary (e.g. provide separate Google API key for the account):
16
+ Geocoder.configure(my_preciousss: { api_key: 'abcdef' })
17
+
18
+ # Lastly, search using your custom lookup service/api keys
19
+ Geocoder.search("Paris", lookup: :my_preciousss)
20
+
21
+ # This is useful when we have groups of users in the application who use Google paid services
22
+ # and we want to properly separate them and allow using individual API KEYS or timeouts.
@@ -9,7 +9,6 @@ Geocoder.configure(
9
9
  # https_proxy: nil, # HTTPS proxy server (user:pass@host:port)
10
10
  # api_key: nil, # API key for geocoding service
11
11
  # cache: nil, # cache object (must respond to #[], #[]=, and #del)
12
- # cache_prefix: 'geocoder:', # prefix (string) to use for all cache keys
13
12
 
14
13
  # Exceptions that should not be rescued by default
15
14
  # (if you want to implement custom error handling);
@@ -19,4 +18,10 @@ Geocoder.configure(
19
18
  # Calculation options
20
19
  # units: :mi, # :km for kilometers or :mi for miles
21
20
  # distances: :linear # :spherical or :linear
21
+
22
+ # Cache configuration
23
+ # cache_options: {
24
+ # expiration: 2.days,
25
+ # prefix: 'geocoder:'
26
+ # }
22
27
  )
@@ -1,41 +1,29 @@
1
+ Dir["#{__dir__}/cache_stores/*.rb"].each {|file| require file }
2
+
1
3
  module Geocoder
2
4
  class Cache
3
5
 
4
- def initialize(store, prefix)
5
- @store = store
6
- @prefix = prefix
6
+ def initialize(store, config)
7
+ @class = (Geocoder::CacheStore.const_get("#{store.class}", false) rescue Geocoder::CacheStore::Generic)
8
+ @store_service = @class.new(store, config)
7
9
  end
8
10
 
9
11
  ##
10
12
  # Read from the Cache.
11
13
  #
12
14
  def [](url)
13
- interpret case
14
- when store.respond_to?(:[])
15
- store[key_for(url)]
16
- when store.respond_to?(:get)
17
- store.get key_for(url)
18
- when store.respond_to?(:read)
19
- store.read key_for(url)
20
- end
15
+ interpret store_service.read(url)
21
16
  rescue => e
22
- warn "Geocoder cache read error: #{e}"
17
+ Geocoder.log(:warn, "Geocoder cache read error: #{e}")
23
18
  end
24
19
 
25
20
  ##
26
21
  # Write to the Cache.
27
22
  #
28
23
  def []=(url, value)
29
- case
30
- when store.respond_to?(:[]=)
31
- store[key_for(url)] = value
32
- when store.respond_to?(:set)
33
- store.set key_for(url), value
34
- when store.respond_to?(:write)
35
- store.write key_for(url), value
36
- end
24
+ store_service.write(url, value)
37
25
  rescue => e
38
- warn "Geocoder cache write error: #{e}"
26
+ Geocoder.log(:warn, "Geocoder cache write error: #{e}")
39
27
  end
40
28
 
41
29
  ##
@@ -44,7 +32,7 @@ module Geocoder
44
32
  #
45
33
  def expire(url)
46
34
  if url == :all
47
- if store.respond_to?(:keys)
35
+ if store_service.respond_to?(:keys)
48
36
  urls.each{ |u| expire(u) }
49
37
  else
50
38
  raise(NoMethodError, "The Geocoder cache store must implement `#keys` for `expire(:all)` to work")
@@ -57,29 +45,21 @@ module Geocoder
57
45
 
58
46
  private # ----------------------------------------------------------------
59
47
 
60
- def prefix; @prefix; end
61
- def store; @store; end
62
-
63
- ##
64
- # Cache key for a given URL.
65
- #
66
- def key_for(url)
67
- [prefix, url].join
68
- end
48
+ def store_service; @store_service; end
69
49
 
70
50
  ##
71
51
  # Array of keys with the currently configured prefix
72
52
  # that have non-nil values.
73
53
  #
74
54
  def keys
75
- store.keys.select{ |k| k.match(/^#{prefix}/) and self[k] }
55
+ store_service.keys
76
56
  end
77
57
 
78
58
  ##
79
59
  # Array of cached URLs.
80
60
  #
81
61
  def urls
82
- keys.map{ |k| k[/^#{prefix}(.*)/, 1] }
62
+ store_service.urls
83
63
  end
84
64
 
85
65
  ##
@@ -91,8 +71,7 @@ module Geocoder
91
71
  end
92
72
 
93
73
  def expire_single_url(url)
94
- key = key_for(url)
95
- store.respond_to?(:del) ? store.del(key) : store.delete(key)
74
+ store_service.remove(url)
96
75
  end
97
76
  end
98
77
  end
@@ -0,0 +1,40 @@
1
+ module Geocoder::CacheStore
2
+ class Base
3
+ def initialize(store, options)
4
+ @store = store
5
+ @config = options
6
+ @prefix = config[:prefix]
7
+ end
8
+
9
+ ##
10
+ # Array of keys with the currently configured prefix
11
+ # that have non-nil values.
12
+ def keys
13
+ store.keys.select { |k| k.match(/^#{prefix}/) and self[k] }
14
+ end
15
+
16
+ ##
17
+ # Array of cached URLs.
18
+ #
19
+ def urls
20
+ keys
21
+ end
22
+
23
+ protected # ----------------------------------------------------------------
24
+
25
+ def prefix; @prefix; end
26
+ def store; @store; end
27
+ def config; @config; end
28
+
29
+ ##
30
+ # Cache key for a given URL.
31
+ #
32
+ def key_for(url)
33
+ if url.match(/^#{prefix}/)
34
+ url
35
+ else
36
+ [prefix, url].join
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,35 @@
1
+ require 'geocoder/cache_stores/base'
2
+
3
+ module Geocoder::CacheStore
4
+ class Generic < Base
5
+ def write(url, value)
6
+ case
7
+ when store.respond_to?(:[]=)
8
+ store[key_for(url)] = value
9
+ when store.respond_to?(:set)
10
+ store.set key_for(url), value
11
+ when store.respond_to?(:write)
12
+ store.write key_for(url), value
13
+ end
14
+ end
15
+
16
+ def read(url)
17
+ case
18
+ when store.respond_to?(:[])
19
+ store[key_for(url)]
20
+ when store.respond_to?(:get)
21
+ store.get key_for(url)
22
+ when store.respond_to?(:read)
23
+ store.read key_for(url)
24
+ end
25
+ end
26
+
27
+ def keys
28
+ store.keys
29
+ end
30
+
31
+ def remove(key)
32
+ store.delete(key)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,34 @@
1
+ require 'geocoder/cache_stores/base'
2
+
3
+ module Geocoder::CacheStore
4
+ class Redis < Base
5
+ def initialize(store, options)
6
+ super
7
+ @expiration = options[:expiration]
8
+ end
9
+
10
+ def write(url, value, expire = @expiration)
11
+ if expire.present?
12
+ store.set key_for(url), value, ex: expire
13
+ else
14
+ store.set key_for(url), value
15
+ end
16
+ end
17
+
18
+ def read(url)
19
+ store.get key_for(url)
20
+ end
21
+
22
+ def keys
23
+ store.keys("#{prefix}*")
24
+ end
25
+
26
+ def remove(key)
27
+ store.del(key)
28
+ end
29
+
30
+ private # ----------------------------------------------------------------
31
+
32
+ def expire; @expiration; end
33
+ end
34
+ end
@@ -55,19 +55,20 @@ module Geocoder
55
55
  :lookup,
56
56
  :ip_lookup,
57
57
  :language,
58
+ :host,
58
59
  :http_headers,
59
60
  :use_https,
60
61
  :http_proxy,
61
62
  :https_proxy,
62
63
  :api_key,
63
64
  :cache,
64
- :cache_prefix,
65
65
  :always_raise,
66
66
  :units,
67
67
  :distances,
68
68
  :basic_auth,
69
69
  :logger,
70
- :kernel_logger_level
70
+ :kernel_logger_level,
71
+ :cache_options
71
72
  ]
72
73
 
73
74
  attr_accessor :data
@@ -76,6 +77,10 @@ module Geocoder
76
77
  instance.set_defaults
77
78
  end
78
79
 
80
+ def self.initialize
81
+ instance.send(:initialize)
82
+ end
83
+
79
84
  OPTIONS.each do |o|
80
85
  define_method o do
81
86
  @data[o]
@@ -106,8 +111,6 @@ module Geocoder
106
111
  @data[:http_proxy] = nil # HTTP proxy server (user:pass@host:port)
107
112
  @data[:https_proxy] = nil # HTTPS proxy server (user:pass@host:port)
108
113
  @data[:api_key] = nil # API key for geocoding service
109
- @data[:cache] = nil # cache object (must respond to #[], #[]=, and #keys)
110
- @data[:cache_prefix] = "geocoder:" # prefix (string) to use for all cache keys
111
114
  @data[:basic_auth] = {} # user and password for basic auth ({:user => "user", :password => "password"})
112
115
  @data[:logger] = :kernel # :kernel or Logger instance
113
116
  @data[:kernel_logger_level] = ::Logger::WARN # log level, if kernel logger is used
@@ -120,6 +123,16 @@ module Geocoder
120
123
  # calculation options
121
124
  @data[:units] = :mi # :mi or :km
122
125
  @data[:distances] = :linear # :linear or :spherical
126
+
127
+ # Set the default values for the caching mechanism
128
+ # By default, the cache keys will not expire as IP addresses and phyiscal
129
+ # addresses will rarely change.
130
+ @data[:cache] = nil # cache object (must respond to #[], #[]=, and optionally #keys)
131
+ @data[:cache_prefix] = nil # - DEPRECATED - prefix (string) to use for all cache keys
132
+ @data[:cache_options] = {
133
+ prefix: 'geocoder:',
134
+ expiration: nil
135
+ }
123
136
  end
124
137
 
125
138
  instance_eval(OPTIONS.map do |option|
@@ -7,6 +7,15 @@ module Geocoder
7
7
  '192.168.0.0/16',
8
8
  ].map { |ip| IPAddr.new(ip) }.freeze
9
9
 
10
+ def initialize(ip)
11
+ ip = ip.to_string if ip.is_a?(IPAddr)
12
+ if ip.is_a?(Hash)
13
+ super(**ip)
14
+ else
15
+ super(ip)
16
+ end
17
+ end
18
+
10
19
  def internal?
11
20
  loopback? || private?
12
21
  end
@@ -18,13 +18,21 @@ module Geocoder
18
18
  all_services - [:test]
19
19
  end
20
20
 
21
+ ##
22
+ # Array of valid Lookup service names, excluding any that do not build their own HTTP requests.
23
+ # For example, Amazon Location Service uses the AWS gem, not HTTP REST requests, to fetch data.
24
+ #
25
+ def all_services_with_http_requests
26
+ all_services_except_test - [:amazon_location_service, :maxmind_local, :geoip2, :ip2location_lite]
27
+ end
28
+
21
29
  ##
22
30
  # All street address lookup services, default first.
23
31
  #
24
32
  def street_services
25
33
  @street_services ||= [
26
34
  :location_iq,
27
- :dstk,
35
+ :azure,
28
36
  :esri,
29
37
  :google,
30
38
  :google_premier,
@@ -40,6 +48,7 @@ module Geocoder
40
48
  :uk_ordnance_survey_names,
41
49
  :opencagedata,
42
50
  :pelias,
51
+ :pdok_nl,
43
52
  :pickpoint,
44
53
  :here,
45
54
  :baidu,
@@ -53,7 +62,13 @@ module Geocoder
53
62
  :test,
54
63
  :latlon,
55
64
  :amap,
56
- :osmnames
65
+ :osmnames,
66
+ :melissa_street,
67
+ :amazon_location_service,
68
+ :geoapify,
69
+ :photon,
70
+ :twogis,
71
+ :pc_miler
57
72
  ]
58
73
  end
59
74
 
@@ -63,6 +78,7 @@ module Geocoder
63
78
  def ip_services
64
79
  @ip_services ||= [
65
80
  :baidu_ip,
81
+ :abstract_api,
66
82
  :freegeoip,
67
83
  :geoip2,
68
84
  :maxmind,
@@ -77,7 +93,11 @@ module Geocoder
77
93
  :db_ip_com,
78
94
  :ipstack,
79
95
  :ip2location,
80
- :ipgeolocation
96
+ :ipgeolocation,
97
+ :ipqualityscore,
98
+ :ipbase,
99
+ :ip2location_io,
100
+ :ip2location_lite
81
101
  ]
82
102
  end
83
103
 
@@ -103,8 +123,7 @@ module Geocoder
103
123
  def spawn(name)
104
124
  if all_services.include?(name)
105
125
  name = name.to_s
106
- require "geocoder/lookups/#{name}"
107
- Geocoder::Lookup.const_get(classify_name(name)).new
126
+ instantiate_lookup(name)
108
127
  else
109
128
  valids = all_services.map(&:inspect).join(", ")
110
129
  raise ConfigurationError, "Please specify a valid lookup for Geocoder " +
@@ -118,5 +137,18 @@ module Geocoder
118
137
  def classify_name(filename)
119
138
  filename.to_s.split("_").map{ |i| i[0...1].upcase + i[1..-1] }.join
120
139
  end
140
+
141
+ ##
142
+ # Safely instantiate Lookup
143
+ #
144
+ def instantiate_lookup(name)
145
+ class_name = classify_name(name)
146
+ begin
147
+ Geocoder::Lookup.const_get(class_name, inherit=false)
148
+ rescue NameError
149
+ require "geocoder/lookups/#{name}"
150
+ end
151
+ Geocoder::Lookup.const_get(class_name).new
152
+ end
121
153
  end
122
154
  end
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+
3
+ require 'geocoder/lookups/base'
4
+ require 'geocoder/results/abstract_api'
5
+
6
+ module Geocoder::Lookup
7
+ class AbstractApi < Base
8
+
9
+ def name
10
+ "Abstract API"
11
+ end
12
+
13
+ def required_api_key_parts
14
+ ['api_key']
15
+ end
16
+
17
+ def supported_protocols
18
+ [:https]
19
+ end
20
+
21
+ private # ---------------------------------------------------------------
22
+
23
+ def base_query_url(query)
24
+ "#{protocol}://ipgeolocation.abstractapi.com/v1/?"
25
+ end
26
+
27
+ def query_url_params(query)
28
+ params = {api_key: configuration.api_key}
29
+
30
+ ip_address = query.sanitized_text
31
+ if ip_address.is_a?(String) && ip_address.length > 0
32
+ params[:ip_address] = ip_address
33
+ end
34
+
35
+ params.merge(super)
36
+ end
37
+
38
+ def results(query, reverse = false)
39
+ if doc = fetch_data(query)
40
+ [doc]
41
+ else
42
+ []
43
+ end
44
+ end
45
+ end
46
+ end
@@ -32,10 +32,10 @@ module Geocoder::Lookup
32
32
  return doc['geocodes'] unless doc['geocodes'].blank?
33
33
  when ['0', 'INVALID_USER_KEY']
34
34
  raise_error(Geocoder::InvalidApiKey, "invalid api key") ||
35
- warn("#{self.name} Geocoding API error: invalid api key.")
35
+ Geocoder.log(:warn, "#{self.name} Geocoding API error: invalid api key.")
36
36
  else
37
37
  raise_error(Geocoder::Error, "server error.") ||
38
- warn("#{self.name} Geocoding API error: server error - [#{doc['info']}]")
38
+ Geocoder.log(:warn, "#{self.name} Geocoding API error: server error - [#{doc['info']}]")
39
39
  end
40
40
  return []
41
41
  end
@@ -0,0 +1,58 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/amazon_location_service'
3
+
4
+ module Geocoder::Lookup
5
+ class AmazonLocationService < Base
6
+ def results(query)
7
+ params = query.options.dup
8
+
9
+ # index_name is required
10
+ # Aws::ParamValidator raises ArgumentError on missing required keys
11
+ params.merge!(index_name: configuration[:index_name])
12
+
13
+ # Aws::ParamValidator raises ArgumentError on unexpected keys
14
+ params.delete(:lookup)
15
+
16
+ # Inherit language from configuration
17
+ params.merge!(language: configuration[:language])
18
+
19
+ resp = if query.reverse_geocode?
20
+ client.search_place_index_for_position(params.merge(position: query.coordinates.reverse))
21
+ else
22
+ client.search_place_index_for_text(params.merge(text: query.text))
23
+ end
24
+
25
+ resp.results
26
+ end
27
+
28
+ private
29
+
30
+ def client
31
+ return @client if @client
32
+ require_sdk
33
+ keys = configuration.api_key
34
+ if keys
35
+ @client = Aws::LocationService::Client.new(**{
36
+ region: keys[:region],
37
+ access_key_id: keys[:access_key_id],
38
+ secret_access_key: keys[:secret_access_key]
39
+ }.compact)
40
+ else
41
+ @client = Aws::LocationService::Client.new
42
+ end
43
+ end
44
+
45
+ def require_sdk
46
+ begin
47
+ require 'aws-sdk-locationservice'
48
+ rescue LoadError
49
+ raise_error(Geocoder::ConfigurationError) ||
50
+ Geocoder.log(
51
+ :error,
52
+ "Couldn't load the Amazon Location Service SDK. " +
53
+ "Install it with: gem install aws-sdk-locationservice -v '~> 1.4'"
54
+ )
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,56 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/azure'
3
+
4
+ module Geocoder::Lookup
5
+ class Azure < Base
6
+ def name
7
+ 'Azure'
8
+ end
9
+
10
+ def required_api_key_parts
11
+ ['api_key']
12
+ end
13
+
14
+ def supported_protocols
15
+ [:https]
16
+ end
17
+
18
+ private
19
+
20
+ def base_query_url(query)
21
+ host = 'atlas.microsoft.com/search/address'
22
+
23
+ if query.reverse_geocode?
24
+ "#{protocol}://#{host}/reverse/json?"
25
+ else
26
+ "#{protocol}://#{host}/json?"
27
+ end
28
+ end
29
+
30
+ def query_url_params(query)
31
+ params = {
32
+ 'api-version' => 1.0,
33
+ 'language' => query.options[:language] || 'en',
34
+ 'limit' => configuration[:limit] || 10,
35
+ 'query' => query.sanitized_text,
36
+ 'subscription-key' => configuration.api_key
37
+ }
38
+
39
+ params.merge(super)
40
+ end
41
+
42
+ def results(query)
43
+ return [] unless (doc = fetch_data(query))
44
+
45
+ return doc if doc['error']
46
+
47
+ if doc['results']&.any?
48
+ doc['results']
49
+ elsif doc['addresses']&.any?
50
+ doc['addresses']
51
+ else
52
+ []
53
+ end
54
+ end
55
+ end
56
+ end
@@ -125,7 +125,7 @@ module Geocoder::Lookup
125
125
  end
126
126
 
127
127
  def type_param_is_valid?(param)
128
- %w(housenumber street locality village town city).include?(param.downcase)
128
+ %w(housenumber street locality municipality).include?(param.downcase)
129
129
  end
130
130
 
131
131
  def code_param_is_valid?(param)
@@ -84,7 +84,8 @@ module Geocoder
84
84
  #
85
85
  def cache
86
86
  if @cache.nil? and store = configuration.cache
87
- @cache = Cache.new(store, configuration.cache_prefix)
87
+ cache_options = configuration.cache_options
88
+ @cache = Cache.new(store, cache_options)
88
89
  end
89
90
  @cache
90
91
  end
@@ -19,7 +19,7 @@ module Geocoder::Lookup
19
19
  private # ---------------------------------------------------------------
20
20
 
21
21
  def base_query_url(query)
22
- text = CGI.escape(query.sanitized_text.strip)
22
+ text = ERB::Util.url_encode(query.sanitized_text.strip)
23
23
  url = "#{protocol}://dev.virtualearth.net/REST/v1/Locations/"
24
24
  if query.reverse_geocode?
25
25
  url + "#{text}?"
@@ -54,7 +54,7 @@ module Geocoder::Lookup
54
54
  def query_url_params(query)
55
55
  {
56
56
  key: configuration.api_key,
57
- language: (query.language || configuration.language)
57
+ culture: (query.language || configuration.language)
58
58
  }.merge(super)
59
59
  end
60
60
 
@@ -23,15 +23,28 @@ module Geocoder::Lookup
23
23
  def results(query)
24
24
  return [] unless doc = fetch_data(query)
25
25
 
26
- if (!query.reverse_geocode?)
27
- return [] if !doc['locations'] || doc['locations'].empty?
28
- end
29
-
30
26
  if (doc['error'].nil?)
27
+ if (!query.reverse_geocode?)
28
+ return [] if !doc['locations'] || doc['locations'].empty?
29
+ end
31
30
  return [ doc ]
32
31
  else
33
- return []
32
+ case [ doc['error']['code'] ]
33
+ when [498]
34
+ raise_error(Geocoder::InvalidApiKey, doc['error']['message']) ||
35
+ Geocoder.log(:warn, "#{self.name} Geocoding API error: #{doc['error']['message']}")
36
+ when [ 403 ]
37
+ raise_error(Geocoder::RequestDenied, 'ESRI request denied') ||
38
+ Geocoder.log(:warn, "#{self.name} ESRI request denied: #{doc['error']['message']}")
39
+ when [ 500 ], [501]
40
+ raise_error(Geocoder::ServiceUnavailable, 'ESRI service unavailable') ||
41
+ Geocoder.log(:warn, "#{self.name} ESRI service error: #{doc['error']['message']}")
42
+ else
43
+ raise_error(Geocoder::Error, doc['error']['message']) ||
44
+ Geocoder.log(:warn, "#{self.name} Geocoding error: #{doc['error']['message']}")
45
+ end
34
46
  end
47
+ return []
35
48
  end
36
49
 
37
50
  def query_url_params(query)