geocoder 1.5.2 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +48 -0
  3. data/LICENSE +1 -1
  4. data/README.md +323 -237
  5. data/bin/console +13 -0
  6. data/examples/autoexpire_cache_redis.rb +2 -0
  7. data/lib/easting_northing.rb +171 -0
  8. data/lib/geocoder/cache.rb +9 -1
  9. data/lib/geocoder/configuration.rb +3 -1
  10. data/lib/geocoder/configuration_hash.rb +4 -4
  11. data/lib/geocoder/ip_address.rb +8 -1
  12. data/lib/geocoder/lookup.rb +20 -3
  13. data/lib/geocoder/lookups/abstract_api.rb +46 -0
  14. data/lib/geocoder/lookups/amazon_location_service.rb +53 -0
  15. data/lib/geocoder/lookups/ban_data_gouv_fr.rb +14 -1
  16. data/lib/geocoder/lookups/bing.rb +1 -1
  17. data/lib/geocoder/lookups/esri.rb +6 -0
  18. data/lib/geocoder/lookups/geoapify.rb +72 -0
  19. data/lib/geocoder/lookups/geocodio.rb +1 -1
  20. data/lib/geocoder/lookups/geoip2.rb +4 -0
  21. data/lib/geocoder/lookups/google.rb +7 -2
  22. data/lib/geocoder/lookups/google_places_details.rb +8 -14
  23. data/lib/geocoder/lookups/google_places_search.rb +28 -2
  24. data/lib/geocoder/lookups/google_premier.rb +4 -0
  25. data/lib/geocoder/lookups/here.rb +7 -16
  26. data/lib/geocoder/lookups/ip2location.rb +10 -14
  27. data/lib/geocoder/lookups/ipgeolocation.rb +51 -0
  28. data/lib/geocoder/lookups/ipqualityscore.rb +50 -0
  29. data/lib/geocoder/lookups/latlon.rb +1 -2
  30. data/lib/geocoder/lookups/maxmind_local.rb +7 -1
  31. data/lib/geocoder/lookups/melissa_street.rb +41 -0
  32. data/lib/geocoder/lookups/nationaal_georegister_nl.rb +38 -0
  33. data/lib/geocoder/lookups/osmnames.rb +57 -0
  34. data/lib/geocoder/lookups/photon.rb +89 -0
  35. data/lib/geocoder/lookups/pickpoint.rb +1 -1
  36. data/lib/geocoder/lookups/smarty_streets.rb +6 -1
  37. data/lib/geocoder/lookups/telize.rb +1 -1
  38. data/lib/geocoder/lookups/tencent.rb +9 -9
  39. data/lib/geocoder/lookups/test.rb +4 -0
  40. data/lib/geocoder/lookups/uk_ordnance_survey_names.rb +59 -0
  41. data/lib/geocoder/lookups/yandex.rb +1 -2
  42. data/lib/geocoder/results/abstract_api.rb +146 -0
  43. data/lib/geocoder/results/amazon_location_service.rb +57 -0
  44. data/lib/geocoder/results/baidu.rb +0 -4
  45. data/lib/geocoder/results/ban_data_gouv_fr.rb +27 -2
  46. data/lib/geocoder/results/db_ip_com.rb +1 -1
  47. data/lib/geocoder/results/esri.rb +5 -2
  48. data/lib/geocoder/results/geoapify.rb +179 -0
  49. data/lib/geocoder/results/ipgeolocation.rb +59 -0
  50. data/lib/geocoder/results/ipqualityscore.rb +54 -0
  51. data/lib/geocoder/results/ipregistry.rb +4 -8
  52. data/lib/geocoder/results/mapbox.rb +10 -4
  53. data/lib/geocoder/results/melissa_street.rb +46 -0
  54. data/lib/geocoder/results/nationaal_georegister_nl.rb +62 -0
  55. data/lib/geocoder/results/nominatim.rb +4 -0
  56. data/lib/geocoder/results/osmnames.rb +56 -0
  57. data/lib/geocoder/results/photon.rb +119 -0
  58. data/lib/geocoder/results/uk_ordnance_survey_names.rb +59 -0
  59. data/lib/geocoder/results/yandex.rb +217 -59
  60. data/lib/geocoder/sql.rb +4 -4
  61. data/lib/geocoder/util.rb +29 -0
  62. data/lib/geocoder/version.rb +1 -1
  63. data/lib/maxmind_database.rb +3 -3
  64. metadata +29 -11
  65. data/lib/geocoder/lookups/geocoder_us.rb +0 -51
  66. data/lib/geocoder/results/geocoder_us.rb +0 -39
  67. data/lib/hash_recursive_merge.rb +0 -74
data/bin/console ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'geocoder'
5
+
6
+ if File.exist?("api_keys.yml")
7
+ require 'yaml'
8
+ @api_keys = YAML.load(File.read("api_keys.yml"), symbolize_names: true)
9
+ Geocoder.configure(@api_keys)
10
+ end
11
+
12
+ require 'irb'
13
+ IRB.start
@@ -1,6 +1,8 @@
1
1
  # This class implements a cache with simple delegation to the Redis store, but
2
2
  # when it creates a key/value pair, it also sends an EXPIRE command with a TTL.
3
3
  # It should be fairly simple to do the same thing with Memcached.
4
+ # Alternatively, this class could inherit from Redis, which would make most
5
+ # of the below methods unnecessary.
4
6
  class AutoexpireCacheRedis
5
7
  def initialize(store, ttl = 86400)
6
8
  @store = store
@@ -0,0 +1,171 @@
1
+ module Geocoder
2
+ class EastingNorthing
3
+ attr_reader :easting, :northing, :lat_lng
4
+
5
+ def initialize(opts)
6
+ @easting = opts[:easting]
7
+ @northing = opts[:northing]
8
+
9
+ @lat_lng = to_WGS84(to_osgb_36)
10
+ end
11
+
12
+ private
13
+
14
+ def to_osgb_36
15
+ osgb_fo = 0.9996012717
16
+ northing0 = -100_000.0
17
+ easting0 = 400_000.0
18
+ phi0 = deg_to_rad(49.0)
19
+ lambda0 = deg_to_rad(-2.0)
20
+ a = 6_377_563.396
21
+ b = 6_356_256.909
22
+ eSquared = ((a * a) - (b * b)) / (a * a)
23
+ phi = 0.0
24
+ lambda = 0.0
25
+ n = (a - b) / (a + b)
26
+ m = 0.0
27
+ phiPrime = ((northing - northing0) / (a * osgb_fo)) + phi0
28
+
29
+ while (northing - northing0 - m) >= 0.001
30
+ m =
31
+ (b * osgb_fo)\
32
+ * (((1 + n + ((5.0 / 4.0) * n * n) + ((5.0 / 4.0) * n * n * n))\
33
+ * (phiPrime - phi0))\
34
+ - (((3 * n) + (3 * n * n) + ((21.0 / 8.0) * n * n * n))\
35
+ * Math.sin(phiPrime - phi0)\
36
+ * Math.cos(phiPrime + phi0))\
37
+ + ((((15.0 / 8.0) * n * n) + ((15.0 / 8.0) * n * n * n))\
38
+ * Math.sin(2.0 * (phiPrime - phi0))\
39
+ * Math.cos(2.0 * (phiPrime + phi0)))\
40
+ - (((35.0 / 24.0) * n * n * n)\
41
+ * Math.sin(3.0 * (phiPrime - phi0))\
42
+ * Math.cos(3.0 * (phiPrime + phi0))))
43
+
44
+ phiPrime += (northing - northing0 - m) / (a * osgb_fo)
45
+ end
46
+
47
+ v = a * osgb_fo * ((1.0 - eSquared * sin_pow_2(phiPrime))**-0.5)
48
+ rho =
49
+ a\
50
+ * osgb_fo\
51
+ * (1.0 - eSquared)\
52
+ * ((1.0 - eSquared * sin_pow_2(phiPrime))**-1.5)
53
+ etaSquared = (v / rho) - 1.0
54
+ vii = Math.tan(phiPrime) / (2 * rho * v)
55
+ viii =
56
+ (Math.tan(phiPrime) / (24.0 * rho * (v**3.0)))\
57
+ * (5.0\
58
+ + (3.0 * tan_pow_2(phiPrime))\
59
+ + etaSquared\
60
+ - (9.0 * tan_pow_2(phiPrime) * etaSquared))
61
+ ix =
62
+ (Math.tan(phiPrime) / (720.0 * rho * (v**5.0)))\
63
+ * (61.0\
64
+ + (90.0 * tan_pow_2(phiPrime))\
65
+ + (45.0 * tan_pow_2(phiPrime) * tan_pow_2(phiPrime)))
66
+ x = sec(phiPrime) / v
67
+ xi =
68
+ (sec(phiPrime) / (6.0 * v * v * v))\
69
+ * ((v / rho) + (2 * tan_pow_2(phiPrime)))
70
+ xiii =
71
+ (sec(phiPrime) / (120.0 * (v**5.0)))\
72
+ * (5.0\
73
+ + (28.0 * tan_pow_2(phiPrime))\
74
+ + (24.0 * tan_pow_2(phiPrime) * tan_pow_2(phiPrime)))
75
+ xiia =
76
+ (sec(phiPrime) / (5040.0 * (v**7.0)))\
77
+ * (61.0\
78
+ + (662.0 * tan_pow_2(phiPrime))\
79
+ + (1320.0 * tan_pow_2(phiPrime) * tan_pow_2(phiPrime))\
80
+ + (720.0\
81
+ * tan_pow_2(phiPrime)\
82
+ * tan_pow_2(phiPrime)\
83
+ * tan_pow_2(phiPrime)))
84
+ phi =
85
+ phiPrime\
86
+ - (vii * ((easting - easting0)**2.0))\
87
+ + (viii * ((easting - easting0)**4.0))\
88
+ - (ix * ((easting - easting0)**6.0))
89
+ lambda =
90
+ lambda0\
91
+ + (x * (easting - easting0))\
92
+ - (xi * ((easting - easting0)**3.0))\
93
+ + (xiii * ((easting - easting0)**5.0))\
94
+ - (xiia * ((easting - easting0)**7.0))
95
+
96
+ [rad_to_deg(phi), rad_to_deg(lambda)]
97
+ end
98
+
99
+ def to_WGS84(latlng)
100
+ latitude = latlng[0]
101
+ longitude = latlng[1]
102
+
103
+ a = 6_377_563.396
104
+ b = 6_356_256.909
105
+ eSquared = ((a * a) - (b * b)) / (a * a)
106
+
107
+ phi = deg_to_rad(latitude)
108
+ lambda = deg_to_rad(longitude)
109
+ v = a / Math.sqrt(1 - eSquared * sin_pow_2(phi))
110
+ h = 0
111
+ x = (v + h) * Math.cos(phi) * Math.cos(lambda)
112
+ y = (v + h) * Math.cos(phi) * Math.sin(lambda)
113
+ z = ((1 - eSquared) * v + h) * Math.sin(phi)
114
+
115
+ tx = 446.448
116
+ ty = -124.157
117
+ tz = 542.060
118
+
119
+ s = -0.0000204894
120
+ rx = deg_to_rad(0.00004172222)
121
+ ry = deg_to_rad(0.00006861111)
122
+ rz = deg_to_rad(0.00023391666)
123
+
124
+ xB = tx + (x * (1 + s)) + (-rx * y) + (ry * z)
125
+ yB = ty + (rz * x) + (y * (1 + s)) + (-rx * z)
126
+ zB = tz + (-ry * x) + (rx * y) + (z * (1 + s))
127
+
128
+ a = 6_378_137.000
129
+ b = 6_356_752.3141
130
+ eSquared = ((a * a) - (b * b)) / (a * a)
131
+
132
+ lambdaB = rad_to_deg(Math.atan(yB / xB))
133
+ p = Math.sqrt((xB * xB) + (yB * yB))
134
+ phiN = Math.atan(zB / (p * (1 - eSquared)))
135
+
136
+ (1..10).each do |_i|
137
+ v = a / Math.sqrt(1 - eSquared * sin_pow_2(phiN))
138
+ phiN1 = Math.atan((zB + (eSquared * v * Math.sin(phiN))) / p)
139
+ phiN = phiN1
140
+ end
141
+
142
+ phiB = rad_to_deg(phiN)
143
+
144
+ [phiB, lambdaB]
145
+ end
146
+
147
+ def deg_to_rad(degrees)
148
+ degrees / 180.0 * Math::PI
149
+ end
150
+
151
+ def rad_to_deg(r)
152
+ (r / Math::PI) * 180
153
+ end
154
+
155
+ def sin_pow_2(x)
156
+ Math.sin(x) * Math.sin(x)
157
+ end
158
+
159
+ def cos_pow_2(x)
160
+ Math.cos(x) * Math.cos(x)
161
+ end
162
+
163
+ def tan_pow_2(x)
164
+ Math.tan(x) * Math.tan(x)
165
+ end
166
+
167
+ def sec(x)
168
+ 1.0 / Math.cos(x)
169
+ end
170
+ end
171
+ end
@@ -18,6 +18,8 @@ module Geocoder
18
18
  when store.respond_to?(:read)
19
19
  store.read key_for(url)
20
20
  end
21
+ rescue => e
22
+ warn "Geocoder cache read error: #{e}"
21
23
  end
22
24
 
23
25
  ##
@@ -32,6 +34,8 @@ module Geocoder
32
34
  when store.respond_to?(:write)
33
35
  store.write key_for(url), value
34
36
  end
37
+ rescue => e
38
+ warn "Geocoder cache write error: #{e}"
35
39
  end
36
40
 
37
41
  ##
@@ -60,7 +64,11 @@ module Geocoder
60
64
  # Cache key for a given URL.
61
65
  #
62
66
  def key_for(url)
63
- [prefix, url].join
67
+ if url.match(/^#{prefix}/)
68
+ url
69
+ else
70
+ [prefix, url].join
71
+ end
64
72
  end
65
73
 
66
74
  ##
@@ -1,5 +1,6 @@
1
1
  require 'singleton'
2
2
  require 'geocoder/configuration_hash'
3
+ require 'geocoder/util'
3
4
 
4
5
  module Geocoder
5
6
 
@@ -54,6 +55,7 @@ module Geocoder
54
55
  :lookup,
55
56
  :ip_lookup,
56
57
  :language,
58
+ :host,
57
59
  :http_headers,
58
60
  :use_https,
59
61
  :http_proxy,
@@ -85,7 +87,7 @@ module Geocoder
85
87
  end
86
88
 
87
89
  def configure(options)
88
- @data.rmerge!(options)
90
+ Util.recursive_hash_merge(@data, options)
89
91
  end
90
92
 
91
93
  def initialize # :nodoc
@@ -1,11 +1,11 @@
1
- require 'hash_recursive_merge'
2
-
3
1
  module Geocoder
4
2
  class ConfigurationHash < Hash
5
- include HashRecursiveMerge
6
-
7
3
  def method_missing(meth, *args, &block)
8
4
  has_key?(meth) ? self[meth] : super
9
5
  end
6
+
7
+ def respond_to_missing?(meth, include_private = false)
8
+ has_key?(meth) || super
9
+ end
10
10
  end
11
11
  end
@@ -7,6 +7,12 @@ 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
+
13
+ super(ip)
14
+ end
15
+
10
16
  def internal?
11
17
  loopback? || private?
12
18
  end
@@ -20,7 +26,8 @@ module Geocoder
20
26
  end
21
27
 
22
28
  def valid?
23
- !!((self =~ Resolv::IPv4::Regex) || (self =~ Resolv::IPv6::Regex))
29
+ ip = self[/(?<=\[)(.*?)(?=\])/] || self
30
+ !!((ip =~ Resolv::IPv4::Regex) || (ip =~ Resolv::IPv6::Regex))
24
31
  end
25
32
  end
26
33
  end
@@ -18,6 +18,14 @@ 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]
27
+ end
28
+
21
29
  ##
22
30
  # All street address lookup services, default first.
23
31
  #
@@ -32,11 +40,12 @@ module Geocoder
32
40
  :google_places_search,
33
41
  :bing,
34
42
  :geocoder_ca,
35
- :geocoder_us,
36
43
  :yandex,
44
+ :nationaal_georegister_nl,
37
45
  :nominatim,
38
46
  :mapbox,
39
47
  :mapquest,
48
+ :uk_ordnance_survey_names,
40
49
  :opencagedata,
41
50
  :pelias,
42
51
  :pickpoint,
@@ -51,7 +60,12 @@ module Geocoder
51
60
  :ban_data_gouv_fr,
52
61
  :test,
53
62
  :latlon,
54
- :amap
63
+ :amap,
64
+ :osmnames,
65
+ :melissa_street,
66
+ :amazon_location_service,
67
+ :geoapify,
68
+ :photon
55
69
  ]
56
70
  end
57
71
 
@@ -61,6 +75,7 @@ module Geocoder
61
75
  def ip_services
62
76
  @ip_services ||= [
63
77
  :baidu_ip,
78
+ :abstract_api,
64
79
  :freegeoip,
65
80
  :geoip2,
66
81
  :maxmind,
@@ -74,7 +89,9 @@ module Geocoder
74
89
  :ipdata_co,
75
90
  :db_ip_com,
76
91
  :ipstack,
77
- :ip2location
92
+ :ip2location,
93
+ :ipgeolocation,
94
+ :ipqualityscore
78
95
  ]
79
96
  end
80
97
 
@@ -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
@@ -0,0 +1,53 @@
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 = { **global_index_name, **query.options }
8
+ if query.reverse_geocode?
9
+ resp = client.search_place_index_for_position(**{ **params, position: query.coordinates.reverse })
10
+ else
11
+ resp = client.search_place_index_for_text(**{ **params, text: query.text })
12
+ end
13
+ resp.results.map(&:place)
14
+ end
15
+
16
+ private
17
+
18
+ def client
19
+ return @client if @client
20
+ require_sdk
21
+ keys = configuration.api_key
22
+ if keys
23
+ @client = Aws::LocationService::Client.new(
24
+ access_key_id: keys[:access_key_id],
25
+ secret_access_key: keys[:secret_access_key],
26
+ )
27
+ else
28
+ @client = Aws::LocationService::Client.new
29
+ end
30
+ end
31
+
32
+ def require_sdk
33
+ begin
34
+ require 'aws-sdk-locationservice'
35
+ rescue LoadError
36
+ raise_error(Geocoder::ConfigurationError) ||
37
+ Geocoder.log(
38
+ :error,
39
+ "Couldn't load the Amazon Location Service SDK. " +
40
+ "Install it with: gem install aws-sdk-locationservice -v '~> 1.4'"
41
+ )
42
+ end
43
+ end
44
+
45
+ def global_index_name
46
+ if configuration[:index_name]
47
+ { index_name: configuration[:index_name] }
48
+ else
49
+ {}
50
+ end
51
+ end
52
+ end
53
+ end
@@ -22,7 +22,7 @@ module Geocoder::Lookup
22
22
  end
23
23
 
24
24
  def any_result?(doc)
25
- doc['features'].any?
25
+ doc['features'] and doc['features'].any?
26
26
  end
27
27
 
28
28
  def results(query)
@@ -86,6 +86,12 @@ module Geocoder::Lookup
86
86
  unless (citycode = query.options[:citycode]).nil? || !code_param_is_valid?(citycode)
87
87
  params[:citycode] = citycode.to_s
88
88
  end
89
+ unless (lat = query.options[:lat]).nil? || !latitude_is_valid?(lat)
90
+ params[:lat] = lat
91
+ end
92
+ unless (lon = query.options[:lon]).nil? || !longitude_is_valid?(lon)
93
+ params[:lon] = lon
94
+ end
89
95
  params
90
96
  end
91
97
 
@@ -126,5 +132,12 @@ module Geocoder::Lookup
126
132
  (1..99999).include?(param.to_i)
127
133
  end
128
134
 
135
+ def latitude_is_valid?(param)
136
+ param.to_f <= 90 && param.to_f >= -90
137
+ end
138
+
139
+ def longitude_is_valid?(param)
140
+ param.to_f <= 180 && param.to_f >= -180
141
+ end
129
142
  end
130
143
  end
@@ -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
 
@@ -9,6 +9,10 @@ module Geocoder::Lookup
9
9
  "Esri"
10
10
  end
11
11
 
12
+ def supported_protocols
13
+ [:https]
14
+ end
15
+
12
16
  private # ---------------------------------------------------------------
13
17
 
14
18
  def base_query_url(query)
@@ -47,6 +51,8 @@ module Geocoder::Lookup
47
51
  params[:forStorage] = for_storage_value
48
52
  end
49
53
  params[:sourceCountry] = configuration[:source_country] if configuration[:source_country]
54
+ params[:preferredLabelValues] = configuration[:preferred_label_values] if configuration[:preferred_label_values]
55
+
50
56
  params.merge(super)
51
57
  end
52
58
 
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'geocoder/lookups/base'
4
+ require 'geocoder/results/geoapify'
5
+
6
+ module Geocoder
7
+ module Lookup
8
+ # https://apidocs.geoapify.com/docs/geocoding/api
9
+ class Geoapify < Base
10
+ def name
11
+ 'Geoapify'
12
+ end
13
+
14
+ def required_api_key_parts
15
+ ['api_key']
16
+ end
17
+
18
+ def supported_protocols
19
+ [:https]
20
+ end
21
+
22
+ private
23
+
24
+ def base_query_url(query)
25
+ method = query.reverse_geocode? ? 'reverse' : 'search'
26
+ "https://api.geoapify.com/v1/geocode/#{method}?"
27
+ end
28
+
29
+ def results(query)
30
+ return [] unless (doc = fetch_data(query))
31
+
32
+ # The rest of the status codes should be already handled by the default
33
+ # functionality as the API returns correct HTTP response codes in most
34
+ # cases. There may be some unhandled cases still (such as over query
35
+ # limit reached) but there is not enough documentation to cover them.
36
+ case doc['statusCode']
37
+ when 500
38
+ raise_error(Geocoder::InvalidRequest) || Geocoder.log(:warn, doc['message'])
39
+ end
40
+
41
+ return [] unless doc['type'] == 'FeatureCollection'
42
+ return [] unless doc['features'] || doc['features'].present?
43
+
44
+ doc['features']
45
+ end
46
+
47
+ def query_url_params(query)
48
+ lang = query.language || configuration.language
49
+ params = { apiKey: configuration.api_key, lang: lang, limit: query.options[:limit] }
50
+
51
+ if query.reverse_geocode?
52
+ params.merge!(query_url_params_reverse(query))
53
+ else
54
+ params.merge!(query_url_params_coordinates(query))
55
+ end
56
+
57
+ params.merge!(super)
58
+ end
59
+
60
+ def query_url_params_coordinates(query)
61
+ { text: query.sanitized_text }
62
+ end
63
+
64
+ def query_url_params_reverse(query)
65
+ {
66
+ lat: query.coordinates[0],
67
+ lon: query.coordinates[1]
68
+ }
69
+ end
70
+ end
71
+ end
72
+ end
@@ -29,7 +29,7 @@ module Geocoder::Lookup
29
29
 
30
30
  def base_query_url(query)
31
31
  path = query.reverse_geocode? ? "reverse" : "geocode"
32
- "#{protocol}://api.geocod.io/v1.3/#{path}?"
32
+ "#{protocol}://api.geocod.io/v1.6/#{path}?"
33
33
  end
34
34
 
35
35
  def query_url_params(query)
@@ -37,6 +37,10 @@ module Geocoder
37
37
  def results(query)
38
38
  return [] unless configuration[:file]
39
39
 
40
+ if @mmdb.respond_to?(:local_ip_alias) && !configuration[:local_ip_alias].nil?
41
+ @mmdb.local_ip_alias = configuration[:local_ip_alias]
42
+ end
43
+
40
44
  result = @mmdb.lookup(query.to_s)
41
45
  result.nil? ? [] : [result]
42
46
  end
@@ -44,10 +44,15 @@ module Geocoder::Lookup
44
44
  super(response) and ['OK', 'ZERO_RESULTS'].include?(status)
45
45
  end
46
46
 
47
+ def result_root_attr
48
+ 'results'
49
+ end
50
+
47
51
  def results(query)
48
52
  return [] unless doc = fetch_data(query)
49
- case doc['status']; when "OK" # OK status implies >0 results
50
- return doc['results']
53
+ case doc['status']
54
+ when "OK" # OK status implies >0 results
55
+ return doc[result_root_attr]
51
56
  when "OVER_QUERY_LIMIT"
52
57
  raise_error(Geocoder::OverQueryLimitError) ||
53
58
  Geocoder.log(:warn, "#{name} API error: over query limit.")
@@ -22,21 +22,15 @@ module Geocoder
22
22
  "#{protocol}://maps.googleapis.com/maps/api/place/details/json?"
23
23
  end
24
24
 
25
+ def result_root_attr
26
+ 'result'
27
+ end
28
+
25
29
  def results(query)
26
- return [] unless doc = fetch_data(query)
27
-
28
- case doc["status"]
29
- when "OK"
30
- return [doc["result"]]
31
- when "OVER_QUERY_LIMIT"
32
- raise_error(Geocoder::OverQueryLimitError) || Geocoder.log(:warn, "Google Places Details API error: over query limit.")
33
- when "REQUEST_DENIED"
34
- raise_error(Geocoder::RequestDenied) || Geocoder.log(:warn, "Google Places Details API error: request denied.")
35
- when "INVALID_REQUEST"
36
- raise_error(Geocoder::InvalidRequest) || Geocoder.log(:warn, "Google Places Details API error: invalid request.")
37
- end
38
-
39
- []
30
+ result = super(query)
31
+ return [result] unless result.is_a? Array
32
+
33
+ result
40
34
  end
41
35
 
42
36
  def query_url_google_params(query)