geocoder 1.6.6 → 1.8.5

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 (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)