geocoder 1.1.9 → 1.8.0

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 (238) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +309 -0
  3. data/LICENSE +1 -1
  4. data/README.md +544 -540
  5. data/bin/console +13 -0
  6. data/examples/app_defined_lookup_services.rb +22 -0
  7. data/examples/reverse_geocode_job.rb +40 -0
  8. data/lib/easting_northing.rb +171 -0
  9. data/lib/generators/geocoder/config/templates/initializer.rb +22 -16
  10. data/lib/generators/geocoder/maxmind/geolite_city_generator.rb +30 -0
  11. data/lib/generators/geocoder/maxmind/geolite_country_generator.rb +30 -0
  12. data/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb +30 -0
  13. data/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb +17 -0
  14. data/lib/generators/geocoder/migration_version.rb +15 -0
  15. data/lib/geocoder/cache.rb +20 -32
  16. data/lib/geocoder/cache_stores/base.rb +40 -0
  17. data/lib/geocoder/cache_stores/generic.rb +35 -0
  18. data/lib/geocoder/cache_stores/redis.rb +34 -0
  19. data/lib/geocoder/calculations.rb +67 -36
  20. data/lib/geocoder/cli.rb +2 -2
  21. data/lib/geocoder/configuration.rb +33 -16
  22. data/lib/geocoder/configuration_hash.rb +4 -4
  23. data/lib/geocoder/esri_token.rb +38 -0
  24. data/lib/geocoder/exceptions.rb +19 -0
  25. data/lib/geocoder/ip_address.rb +33 -0
  26. data/lib/geocoder/kernel_logger.rb +25 -0
  27. data/lib/geocoder/logger.rb +47 -0
  28. data/lib/geocoder/lookup.rb +74 -11
  29. data/lib/geocoder/lookups/abstract_api.rb +46 -0
  30. data/lib/geocoder/lookups/amap.rb +63 -0
  31. data/lib/geocoder/lookups/amazon_location_service.rb +54 -0
  32. data/lib/geocoder/lookups/baidu.rb +24 -15
  33. data/lib/geocoder/lookups/baidu_ip.rb +30 -0
  34. data/lib/geocoder/lookups/ban_data_gouv_fr.rb +143 -0
  35. data/lib/geocoder/lookups/base.rb +109 -23
  36. data/lib/geocoder/lookups/bing.rb +45 -10
  37. data/lib/geocoder/lookups/db_ip_com.rb +52 -0
  38. data/lib/geocoder/lookups/dstk.rb +4 -2
  39. data/lib/geocoder/lookups/esri.rb +61 -8
  40. data/lib/geocoder/lookups/freegeoip.rb +25 -6
  41. data/lib/geocoder/lookups/geoapify.rb +72 -0
  42. data/lib/geocoder/lookups/geocoder_ca.rb +5 -6
  43. data/lib/geocoder/lookups/geocodio.rb +42 -0
  44. data/lib/geocoder/lookups/geoip2.rb +49 -0
  45. data/lib/geocoder/lookups/geoportail_lu.rb +65 -0
  46. data/lib/geocoder/lookups/google.rb +45 -12
  47. data/lib/geocoder/lookups/google_places_details.rb +64 -0
  48. data/lib/geocoder/lookups/google_places_search.rb +76 -0
  49. data/lib/geocoder/lookups/google_premier.rb +16 -2
  50. data/lib/geocoder/lookups/here.rb +73 -0
  51. data/lib/geocoder/lookups/ip2location.rb +71 -0
  52. data/lib/geocoder/lookups/ipapi_com.rb +82 -0
  53. data/lib/geocoder/lookups/ipdata_co.rb +62 -0
  54. data/lib/geocoder/lookups/ipgeolocation.rb +51 -0
  55. data/lib/geocoder/lookups/ipinfo_io.rb +44 -0
  56. data/lib/geocoder/lookups/ipqualityscore.rb +50 -0
  57. data/lib/geocoder/lookups/ipregistry.rb +68 -0
  58. data/lib/geocoder/lookups/ipstack.rb +63 -0
  59. data/lib/geocoder/lookups/latlon.rb +58 -0
  60. data/lib/geocoder/lookups/location_iq.rb +54 -0
  61. data/lib/geocoder/lookups/mapbox.rb +59 -0
  62. data/lib/geocoder/lookups/mapquest.rb +9 -10
  63. data/lib/geocoder/lookups/maxmind.rb +10 -8
  64. data/lib/geocoder/lookups/maxmind_geoip2.rb +70 -0
  65. data/lib/geocoder/lookups/maxmind_local.rb +71 -0
  66. data/lib/geocoder/lookups/melissa_street.rb +41 -0
  67. data/lib/geocoder/lookups/nationaal_georegister_nl.rb +38 -0
  68. data/lib/geocoder/lookups/nominatim.rb +26 -6
  69. data/lib/geocoder/lookups/opencagedata.rb +65 -0
  70. data/lib/geocoder/lookups/osmnames.rb +57 -0
  71. data/lib/geocoder/lookups/pelias.rb +63 -0
  72. data/lib/geocoder/lookups/photon.rb +89 -0
  73. data/lib/geocoder/lookups/pickpoint.rb +41 -0
  74. data/lib/geocoder/lookups/pointpin.rb +69 -0
  75. data/lib/geocoder/lookups/postcode_anywhere_uk.rb +50 -0
  76. data/lib/geocoder/lookups/postcodes_io.rb +31 -0
  77. data/lib/geocoder/lookups/smarty_streets.rb +68 -0
  78. data/lib/geocoder/lookups/telize.rb +75 -0
  79. data/lib/geocoder/lookups/tencent.rb +59 -0
  80. data/lib/geocoder/lookups/test.rb +4 -0
  81. data/lib/geocoder/lookups/twogis.rb +58 -0
  82. data/lib/geocoder/lookups/uk_ordnance_survey_names.rb +59 -0
  83. data/lib/geocoder/lookups/yandex.rb +18 -11
  84. data/lib/geocoder/models/active_record.rb +9 -4
  85. data/lib/geocoder/models/base.rb +1 -4
  86. data/lib/geocoder/models/mongo_base.rb +6 -4
  87. data/lib/geocoder/query.rb +23 -5
  88. data/lib/geocoder/railtie.rb +2 -2
  89. data/lib/geocoder/request.rb +102 -11
  90. data/lib/geocoder/results/abstract_api.rb +146 -0
  91. data/lib/geocoder/results/amap.rb +87 -0
  92. data/lib/geocoder/results/amazon_location_service.rb +57 -0
  93. data/lib/geocoder/results/baidu.rb +10 -14
  94. data/lib/geocoder/results/baidu_ip.rb +62 -0
  95. data/lib/geocoder/results/ban_data_gouv_fr.rb +282 -0
  96. data/lib/geocoder/results/base.rb +13 -1
  97. data/lib/geocoder/results/bing.rb +5 -1
  98. data/lib/geocoder/results/db_ip_com.rb +58 -0
  99. data/lib/geocoder/results/esri.rb +35 -8
  100. data/lib/geocoder/results/freegeoip.rb +2 -7
  101. data/lib/geocoder/results/geoapify.rb +179 -0
  102. data/lib/geocoder/results/geocoder_ca.rb +3 -3
  103. data/lib/geocoder/results/geocodio.rb +78 -0
  104. data/lib/geocoder/results/geoip2.rb +76 -0
  105. data/lib/geocoder/results/geoportail_lu.rb +71 -0
  106. data/lib/geocoder/results/google.rb +26 -0
  107. data/lib/geocoder/results/google_places_details.rb +39 -0
  108. data/lib/geocoder/results/google_places_search.rb +52 -0
  109. data/lib/geocoder/results/here.rb +77 -0
  110. data/lib/geocoder/results/ip2location.rb +22 -0
  111. data/lib/geocoder/results/ipapi_com.rb +45 -0
  112. data/lib/geocoder/results/ipdata_co.rb +40 -0
  113. data/lib/geocoder/results/ipgeolocation.rb +59 -0
  114. data/lib/geocoder/results/ipinfo_io.rb +48 -0
  115. data/lib/geocoder/results/ipqualityscore.rb +54 -0
  116. data/lib/geocoder/results/ipregistry.rb +304 -0
  117. data/lib/geocoder/results/ipstack.rb +60 -0
  118. data/lib/geocoder/results/latlon.rb +71 -0
  119. data/lib/geocoder/results/location_iq.rb +6 -0
  120. data/lib/geocoder/results/mapbox.rb +63 -0
  121. data/lib/geocoder/results/mapquest.rb +5 -8
  122. data/lib/geocoder/results/maxmind.rb +0 -5
  123. data/lib/geocoder/results/maxmind_geoip2.rb +9 -0
  124. data/lib/geocoder/results/maxmind_local.rb +44 -0
  125. data/lib/geocoder/results/melissa_street.rb +46 -0
  126. data/lib/geocoder/results/nationaal_georegister_nl.rb +62 -0
  127. data/lib/geocoder/results/nominatim.rb +41 -14
  128. data/lib/geocoder/results/opencagedata.rb +100 -0
  129. data/lib/geocoder/results/osmnames.rb +56 -0
  130. data/lib/geocoder/results/pelias.rb +58 -0
  131. data/lib/geocoder/results/photon.rb +119 -0
  132. data/lib/geocoder/results/pickpoint.rb +6 -0
  133. data/lib/geocoder/results/pointpin.rb +40 -0
  134. data/lib/geocoder/results/postcode_anywhere_uk.rb +42 -0
  135. data/lib/geocoder/results/postcodes_io.rb +40 -0
  136. data/lib/geocoder/results/smarty_streets.rb +142 -0
  137. data/lib/geocoder/results/telize.rb +40 -0
  138. data/lib/geocoder/results/tencent.rb +72 -0
  139. data/lib/geocoder/results/test.rb +20 -3
  140. data/lib/geocoder/results/twogis.rb +76 -0
  141. data/lib/geocoder/results/uk_ordnance_survey_names.rb +59 -0
  142. data/lib/geocoder/results/yandex.rb +244 -32
  143. data/lib/geocoder/sql.rb +25 -21
  144. data/lib/geocoder/stores/active_record.rb +82 -26
  145. data/lib/geocoder/stores/base.rb +9 -14
  146. data/lib/geocoder/stores/mongo_base.rb +0 -31
  147. data/lib/geocoder/util.rb +29 -0
  148. data/lib/geocoder/version.rb +1 -1
  149. data/lib/geocoder.rb +6 -13
  150. data/lib/maxmind_database.rb +109 -0
  151. data/lib/tasks/geocoder.rake +30 -3
  152. data/lib/tasks/maxmind.rake +73 -0
  153. metadata +115 -98
  154. data/.gitignore +0 -5
  155. data/.travis.yml +0 -27
  156. data/Rakefile +0 -25
  157. data/examples/autoexpire_cache_dalli.rb +0 -62
  158. data/examples/autoexpire_cache_redis.rb +0 -28
  159. data/gemfiles/Gemfile.mongoid-2.4.x +0 -15
  160. data/lib/geocoder/lookups/geocoder_us.rb +0 -39
  161. data/lib/geocoder/lookups/ovi.rb +0 -62
  162. data/lib/geocoder/lookups/yahoo.rb +0 -86
  163. data/lib/geocoder/results/geocoder_us.rb +0 -39
  164. data/lib/geocoder/results/ovi.rb +0 -62
  165. data/lib/geocoder/results/yahoo.rb +0 -55
  166. data/lib/hash_recursive_merge.rb +0 -74
  167. data/lib/oauth_util.rb +0 -112
  168. data/test/active_record_test.rb +0 -15
  169. data/test/cache_test.rb +0 -35
  170. data/test/calculations_test.rb +0 -211
  171. data/test/configuration_test.rb +0 -78
  172. data/test/custom_block_test.rb +0 -32
  173. data/test/error_handling_test.rb +0 -43
  174. data/test/fixtures/baidu_invalid_key +0 -1
  175. data/test/fixtures/baidu_no_results +0 -1
  176. data/test/fixtures/baidu_reverse +0 -1
  177. data/test/fixtures/baidu_shanghai_pearl_tower +0 -12
  178. data/test/fixtures/bing_invalid_key +0 -1
  179. data/test/fixtures/bing_madison_square_garden +0 -40
  180. data/test/fixtures/bing_no_results +0 -16
  181. data/test/fixtures/bing_reverse +0 -42
  182. data/test/fixtures/esri_madison_square_garden +0 -59
  183. data/test/fixtures/esri_no_results +0 -8
  184. data/test/fixtures/esri_reverse +0 -21
  185. data/test/fixtures/freegeoip_74_200_247_59 +0 -12
  186. data/test/fixtures/freegeoip_no_results +0 -1
  187. data/test/fixtures/geocoder_ca_madison_square_garden +0 -1
  188. data/test/fixtures/geocoder_ca_no_results +0 -1
  189. data/test/fixtures/geocoder_ca_reverse +0 -34
  190. data/test/fixtures/geocoder_us_madison_square_garden +0 -1
  191. data/test/fixtures/geocoder_us_no_results +0 -1
  192. data/test/fixtures/google_garbage +0 -456
  193. data/test/fixtures/google_madison_square_garden +0 -57
  194. data/test/fixtures/google_no_city_data +0 -44
  195. data/test/fixtures/google_no_locality +0 -51
  196. data/test/fixtures/google_no_results +0 -4
  197. data/test/fixtures/google_over_limit +0 -4
  198. data/test/fixtures/mapquest_error +0 -16
  199. data/test/fixtures/mapquest_invalid_api_key +0 -16
  200. data/test/fixtures/mapquest_invalid_request +0 -16
  201. data/test/fixtures/mapquest_madison_square_garden +0 -52
  202. data/test/fixtures/mapquest_no_results +0 -16
  203. data/test/fixtures/maxmind_24_24_24_21 +0 -1
  204. data/test/fixtures/maxmind_24_24_24_22 +0 -1
  205. data/test/fixtures/maxmind_24_24_24_23 +0 -1
  206. data/test/fixtures/maxmind_24_24_24_24 +0 -1
  207. data/test/fixtures/maxmind_74_200_247_59 +0 -1
  208. data/test/fixtures/maxmind_invalid_key +0 -1
  209. data/test/fixtures/maxmind_no_results +0 -1
  210. data/test/fixtures/nominatim_madison_square_garden +0 -150
  211. data/test/fixtures/nominatim_no_results +0 -1
  212. data/test/fixtures/ovi_madison_square_garden +0 -72
  213. data/test/fixtures/ovi_no_results +0 -8
  214. data/test/fixtures/yahoo_error +0 -1
  215. data/test/fixtures/yahoo_invalid_key +0 -2
  216. data/test/fixtures/yahoo_madison_square_garden +0 -52
  217. data/test/fixtures/yahoo_no_results +0 -10
  218. data/test/fixtures/yahoo_over_limit +0 -2
  219. data/test/fixtures/yandex_invalid_key +0 -1
  220. data/test/fixtures/yandex_kremlin +0 -48
  221. data/test/fixtures/yandex_no_city_and_town +0 -112
  222. data/test/fixtures/yandex_no_results +0 -16
  223. data/test/geocoder_test.rb +0 -59
  224. data/test/https_test.rb +0 -16
  225. data/test/integration/smoke_test.rb +0 -26
  226. data/test/lookup_test.rb +0 -117
  227. data/test/method_aliases_test.rb +0 -25
  228. data/test/mongoid_test.rb +0 -46
  229. data/test/mongoid_test_helper.rb +0 -43
  230. data/test/near_test.rb +0 -61
  231. data/test/oauth_util_test.rb +0 -30
  232. data/test/proxy_test.rb +0 -36
  233. data/test/query_test.rb +0 -52
  234. data/test/request_test.rb +0 -29
  235. data/test/result_test.rb +0 -42
  236. data/test/services_test.rb +0 -393
  237. data/test/test_helper.rb +0 -289
  238. data/test/test_mode_test.rb +0 -59
@@ -10,12 +10,6 @@ module Geocoder
10
10
  #
11
11
  COMPASS_POINTS = %w[N NE E SE S SW W NW]
12
12
 
13
- ##
14
- # Radius of the Earth, in kilometers.
15
- # Value taken from: http://en.wikipedia.org/wiki/Earth_radius
16
- #
17
- EARTH_RADIUS = 6371.0
18
-
19
13
  ##
20
14
  # Conversion factor: multiply by kilometers to get miles.
21
15
  #
@@ -26,6 +20,21 @@ module Geocoder
26
20
  #
27
21
  KM_IN_NM = 0.539957
28
22
 
23
+ ##
24
+ # Conversion factor: multiply by radians to get degrees.
25
+ #
26
+ DEGREES_PER_RADIAN = 57.2957795
27
+
28
+ ##
29
+ # Radius of the Earth, in kilometers.
30
+ # Value taken from: http://en.wikipedia.org/wiki/Earth_radius
31
+ #
32
+ EARTH_RADII = {km: 6371.0}
33
+ EARTH_RADII[:mi] = EARTH_RADII[:km] * KM_IN_MI
34
+ EARTH_RADII[:nm] = EARTH_RADII[:km] * KM_IN_NM
35
+
36
+ EARTH_RADIUS = EARTH_RADII[:km] # TODO: deprecate this constant (use `EARTH_RADII[:km]`)
37
+
29
38
  # Not a number constant
30
39
  NAN = defined?(::Float::NAN) ? ::Float::NAN : 0 / 0.0
31
40
 
@@ -45,7 +54,6 @@ module Geocoder
45
54
  # Distance spanned by one degree of latitude in the given units.
46
55
  #
47
56
  def latitude_degree_distance(units = nil)
48
- units ||= Geocoder.config.units
49
57
  2 * Math::PI * earth_radius(units) / 360
50
58
  end
51
59
 
@@ -54,7 +62,6 @@ module Geocoder
54
62
  # This ranges from around 69 miles at the equator to zero at the poles.
55
63
  #
56
64
  def longitude_degree_distance(latitude, units = nil)
57
- units ||= Geocoder.config.units
58
65
  latitude_degree_distance(units) * Math.cos(to_radians(latitude))
59
66
  end
60
67
 
@@ -75,10 +82,6 @@ module Geocoder
75
82
  # Use Geocoder.configure(:units => ...) to configure default units.
76
83
  #
77
84
  def distance_between(point1, point2, options = {})
78
-
79
- # set default options
80
- options[:units] ||= Geocoder.config.units
81
-
82
85
  # convert to coordinate arrays
83
86
  point1 = extract_coordinates(point1)
84
87
  point2 = extract_coordinates(point2)
@@ -151,7 +154,7 @@ module Geocoder
151
154
  # Translate a bearing (float) into a compass direction (string, eg "North").
152
155
  #
153
156
  def compass_point(bearing, points = COMPASS_POINTS)
154
- seg_size = 360 / points.size
157
+ seg_size = 360.0 / points.size
155
158
  points[((bearing + (seg_size / 2)) % 360) / seg_size]
156
159
  end
157
160
 
@@ -207,12 +210,11 @@ module Geocoder
207
210
  def bounding_box(point, radius, options = {})
208
211
  lat,lon = extract_coordinates(point)
209
212
  radius = radius.to_f
210
- units = options[:units] || Geocoder.config.units
211
213
  [
212
- lat - (radius / latitude_degree_distance(units)),
213
- lon - (radius / longitude_degree_distance(lat, units)),
214
- lat + (radius / latitude_degree_distance(units)),
215
- lon + (radius / longitude_degree_distance(lat, units))
214
+ lat - (radius / latitude_degree_distance(options[:units])),
215
+ lon - (radius / longitude_degree_distance(lat, options[:units])),
216
+ lat + (radius / latitude_degree_distance(options[:units])),
217
+ lon + (radius / longitude_degree_distance(lat, options[:units]))
216
218
  ]
217
219
  end
218
220
 
@@ -232,10 +234,9 @@ module Geocoder
232
234
  #
233
235
  # * <tt>:units</tt> - <tt>:mi</tt> or <tt>:km</tt>
234
236
  # Use Geocoder.configure(:units => ...) to configure default units.
237
+ # * <tt>:seed</tt> - The seed for the random number generator
235
238
  def random_point_near(center, radius, options = {})
236
-
237
- # set default options
238
- options[:units] ||= Geocoder.config.units
239
+ random = Random.new(options[:seed] || Random.new_seed)
239
240
 
240
241
  # convert to coordinate arrays
241
242
  center = extract_coordinates(center)
@@ -244,16 +245,49 @@ module Geocoder
244
245
  max_degree_delta = 360.0 * (radius / earth_circumference)
245
246
 
246
247
  # random bearing in radians
247
- theta = 2 * Math::PI * rand
248
+ theta = 2 * Math::PI * random.rand
248
249
 
249
250
  # random radius, use the square root to ensure a uniform
250
251
  # distribution of points over the circle
251
- r = Math.sqrt(rand) * max_degree_delta
252
+ r = Math.sqrt(random.rand) * max_degree_delta
252
253
 
253
254
  delta_lat, delta_long = [r * Math.cos(theta), r * Math.sin(theta)]
254
255
  [center[0] + delta_lat, center[1] + delta_long]
255
256
  end
256
257
 
258
+ ##
259
+ # Given a start point, heading (in degrees), and distance, provides
260
+ # an endpoint.
261
+ # The starting point is given in the same way that points are given to all
262
+ # Geocoder methods that accept points as arguments. It can be:
263
+ #
264
+ # * an array of coordinates ([lat,lon])
265
+ # * a geocodable address (string)
266
+ # * a geocoded object (one which implements a +to_coordinates+ method
267
+ # which returns a [lat,lon] array
268
+ #
269
+ def endpoint(start, heading, distance, options = {})
270
+ radius = earth_radius(options[:units])
271
+
272
+ start = extract_coordinates(start)
273
+
274
+ # convert degrees to radians
275
+ start = to_radians(start)
276
+
277
+ lat = start[0]
278
+ lon = start[1]
279
+ heading = to_radians(heading)
280
+ distance = distance.to_f
281
+
282
+ end_lat = Math.asin(Math.sin(lat)*Math.cos(distance/radius) +
283
+ Math.cos(lat)*Math.sin(distance/radius)*Math.cos(heading))
284
+
285
+ end_lon = lon+Math.atan2(Math.sin(heading)*Math.sin(distance/radius)*Math.cos(lat),
286
+ Math.cos(distance/radius)-Math.sin(lat)*Math.sin(end_lat))
287
+
288
+ to_degrees [end_lat, end_lon]
289
+ end
290
+
257
291
  ##
258
292
  # Convert degrees to radians.
259
293
  # If an array (or multiple arguments) is passed,
@@ -283,12 +317,10 @@ module Geocoder
283
317
  end
284
318
 
285
319
  def distance_to_radians(distance, units = nil)
286
- units ||= Geocoder.config.units
287
320
  distance.to_f / earth_radius(units)
288
321
  end
289
322
 
290
323
  def radians_to_distance(radians, units = nil)
291
- units ||= Geocoder.config.units
292
324
  radians * earth_radius(units)
293
325
  end
294
326
 
@@ -296,6 +328,7 @@ module Geocoder
296
328
  # Convert miles to kilometers.
297
329
  #
298
330
  def to_kilometers(mi)
331
+ Geocoder.log(:warn, "DEPRECATION WARNING: Geocoder::Calculations.to_kilometers is deprecated and will be removed in Geocoder 1.5.0. Please multiply by MI_IN_KM instead.")
299
332
  mi * mi_in_km
300
333
  end
301
334
 
@@ -303,14 +336,16 @@ module Geocoder
303
336
  # Convert kilometers to miles.
304
337
  #
305
338
  def to_miles(km)
306
- km * km_in_mi
339
+ Geocoder.log(:warn, "DEPRECATION WARNING: Geocoder::Calculations.to_miles is deprecated and will be removed in Geocoder 1.5.0. Please multiply by KM_IN_MI instead.")
340
+ km * KM_IN_MI
307
341
  end
308
342
 
309
343
  ##
310
344
  # Convert kilometers to nautical miles.
311
345
  #
312
346
  def to_nautical_miles(km)
313
- km * km_in_nm
347
+ Geocoder.log(:warn, "DEPRECATION WARNING: Geocoder::Calculations.to_nautical_miles is deprecated and will be removed in Geocoder 1.5.0. Please multiply by KM_IN_NM instead.")
348
+ km * KM_IN_NM
314
349
  end
315
350
 
316
351
  ##
@@ -318,18 +353,14 @@ module Geocoder
318
353
  # Use Geocoder.configure(:units => ...) to configure default units.
319
354
  #
320
355
  def earth_radius(units = nil)
321
- units ||= Geocoder.config.units
322
- case units
323
- when :km; EARTH_RADIUS
324
- when :mi; to_miles(EARTH_RADIUS)
325
- when :nm; to_nautical_miles(EARTH_RADIUS)
326
- end
356
+ EARTH_RADII[units || Geocoder.config.units]
327
357
  end
328
358
 
329
359
  ##
330
360
  # Conversion factor: km to mi.
331
361
  #
332
362
  def km_in_mi
363
+ Geocoder.log(:warn, "DEPRECATION WARNING: Geocoder::Calculations.km_in_mi is deprecated and will be removed in Geocoder 1.5.0. Please use the constant KM_IN_MI instead.")
333
364
  KM_IN_MI
334
365
  end
335
366
 
@@ -337,15 +368,15 @@ module Geocoder
337
368
  # Conversion factor: km to nm.
338
369
  #
339
370
  def km_in_nm
371
+ Geocoder.log(:warn, "DEPRECATION WARNING: Geocoder::Calculations.km_in_nm is deprecated and will be removed in Geocoder 1.5.0. Please use the constant KM_IN_NM instead.")
340
372
  KM_IN_NM
341
373
  end
342
374
 
343
-
344
-
345
375
  ##
346
376
  # Conversion factor: mi to km.
347
377
  #
348
378
  def mi_in_km
379
+ Geocoder.log(:warn, "DEPRECATION WARNING: Geocoder::Calculations.mi_in_km is deprecated and will be removed in Geocoder 1.5.0. Please use 1.0 / KM_IN_MI instead.")
349
380
  1.0 / KM_IN_MI
350
381
  end
351
382
 
@@ -353,6 +384,7 @@ module Geocoder
353
384
  # Conversion factor: nm to km.
354
385
  #
355
386
  def nm_in_km
387
+ Geocoder.log(:warn, "DEPRECATION WARNING: Geocoder::Calculations.nm_in_km is deprecated and will be removed in Geocoder 1.5.0. Please use 1.0 / KM_IN_NM instead.")
356
388
  1.0 / KM_IN_NM
357
389
  end
358
390
 
@@ -386,4 +418,3 @@ module Geocoder
386
418
  end
387
419
  end
388
420
  end
389
-
data/lib/geocoder/cli.rb CHANGED
@@ -97,7 +97,7 @@ module Geocoder
97
97
  end
98
98
 
99
99
  if (result = Geocoder.search(query).first)
100
- google = Geocoder::Lookup.get(:google)
100
+ nominatim = Geocoder::Lookup.get(:nominatim)
101
101
  lines = [
102
102
  ["Latitude", result.latitude],
103
103
  ["Longitude", result.longitude],
@@ -106,7 +106,7 @@ module Geocoder
106
106
  ["State/province", result.state],
107
107
  ["Postal code", result.postal_code],
108
108
  ["Country", result.country],
109
- ["Google map", google.map_link_url(result.coordinates)],
109
+ ["Map", nominatim.map_link_url(result.coordinates)],
110
110
  ]
111
111
  lines.each do |line|
112
112
  out << (line[0] + ": ").ljust(18) + line[1].to_s + "\n"
@@ -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
 
@@ -14,14 +15,8 @@ module Geocoder
14
15
  # )
15
16
  #
16
17
  def self.configure(options = nil, &block)
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 => ...))."
19
- block.call(Configuration.instance)
20
- elsif !options.nil?
18
+ if !options.nil?
21
19
  Configuration.instance.configure(options)
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)."
24
- Configuration.instance
25
20
  end
26
21
  end
27
22
 
@@ -44,6 +39,14 @@ module Geocoder
44
39
  data
45
40
  end
46
41
 
42
+ ##
43
+ # Merge the given hash into a lookup's existing configuration.
44
+ #
45
+ def self.merge_into_lookup_config(lookup_name, options)
46
+ base = Geocoder.config[lookup_name]
47
+ Geocoder.configure(lookup_name => base.merge(options))
48
+ end
49
+
47
50
  class Configuration
48
51
  include Singleton
49
52
 
@@ -52,16 +55,20 @@ module Geocoder
52
55
  :lookup,
53
56
  :ip_lookup,
54
57
  :language,
58
+ :host,
55
59
  :http_headers,
56
60
  :use_https,
57
61
  :http_proxy,
58
62
  :https_proxy,
59
63
  :api_key,
60
64
  :cache,
61
- :cache_prefix,
62
65
  :always_raise,
63
66
  :units,
64
- :distances
67
+ :distances,
68
+ :basic_auth,
69
+ :logger,
70
+ :kernel_logger_level,
71
+ :cache_options
65
72
  ]
66
73
 
67
74
  attr_accessor :data
@@ -80,7 +87,7 @@ module Geocoder
80
87
  end
81
88
 
82
89
  def configure(options)
83
- @data.rmerge!(options)
90
+ Util.recursive_hash_merge(@data, options)
84
91
  end
85
92
 
86
93
  def initialize # :nodoc
@@ -92,25 +99,36 @@ module Geocoder
92
99
 
93
100
  # geocoding options
94
101
  @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)
102
+ @data[:lookup] = :nominatim # name of street address geocoding service (symbol)
103
+ @data[:ip_lookup] = :ipinfo_io # name of IP address geocoding service (symbol)
97
104
  @data[:language] = :en # ISO-639 language code
98
105
  @data[:http_headers] = {} # HTTP headers for lookup
99
106
  @data[:use_https] = false # use HTTPS for lookup requests? (if supported)
100
107
  @data[:http_proxy] = nil # HTTP proxy server (user:pass@host:port)
101
108
  @data[:https_proxy] = nil # HTTPS proxy server (user:pass@host:port)
102
109
  @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
110
+ @data[:basic_auth] = {} # user and password for basic auth ({:user => "user", :password => "password"})
111
+ @data[:logger] = :kernel # :kernel or Logger instance
112
+ @data[:kernel_logger_level] = ::Logger::WARN # log level, if kernel logger is used
105
113
 
106
114
  # exceptions that should not be rescued by default
107
115
  # (if you want to implement custom error handling);
108
- # supports SocketError and TimeoutError
116
+ # supports SocketError and Timeout::Error
109
117
  @data[:always_raise] = []
110
118
 
111
119
  # calculation options
112
120
  @data[:units] = :mi # :mi or :km
113
121
  @data[:distances] = :linear # :linear or :spherical
122
+
123
+ # Set the default values for the caching mechanism
124
+ # By default, the cache keys will not expire as IP addresses and phyiscal
125
+ # addresses will rarely change.
126
+ @data[:cache] = nil # cache object (must respond to #[], #[]=, and optionally #keys)
127
+ @data[:cache_prefix] = nil # - DEPRECATED - prefix (string) to use for all cache keys
128
+ @data[:cache_options] = {
129
+ prefix: 'geocoder:',
130
+ expiration: nil
131
+ }
114
132
  end
115
133
 
116
134
  instance_eval(OPTIONS.map do |option|
@@ -125,6 +143,5 @@ module Geocoder
125
143
  end
126
144
  EOS
127
145
  end.join("\n\n"))
128
-
129
146
  end
130
147
  end
@@ -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
@@ -0,0 +1,38 @@
1
+ module Geocoder
2
+ class EsriToken
3
+ attr_accessor :value, :expires_at
4
+
5
+ def initialize(value, expires_at)
6
+ @value = value
7
+ @expires_at = expires_at
8
+ end
9
+
10
+ def to_s
11
+ @value
12
+ end
13
+
14
+ def active?
15
+ @expires_at > Time.now
16
+ end
17
+
18
+ def self.generate_token(client_id, client_secret, expires=1440)
19
+ # creates a new token that will expire in 1 day by default
20
+ getToken = Net::HTTP.post_form URI('https://www.arcgis.com/sharing/rest/oauth2/token'),
21
+ f: 'json',
22
+ client_id: client_id,
23
+ client_secret: client_secret,
24
+ grant_type: 'client_credentials',
25
+ expiration: expires # (minutes) max: 20160, default: 1 day
26
+
27
+ response = JSON.parse(getToken.body)
28
+
29
+ if response['error']
30
+ Geocoder.log(:warn, response['error'])
31
+ else
32
+ token_value = response['access_token']
33
+ expires_at = Time.now + (expires * 60)
34
+ new(token_value, expires_at)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,3 +1,5 @@
1
+ require 'timeout'
2
+
1
3
  module Geocoder
2
4
 
3
5
  class Error < StandardError
@@ -9,6 +11,14 @@ module Geocoder
9
11
  class OverQueryLimitError < Error
10
12
  end
11
13
 
14
+ class ResponseParseError < Error
15
+ attr_reader :response
16
+
17
+ def initialize(response)
18
+ @response = response
19
+ end
20
+ end
21
+
12
22
  class RequestDenied < Error
13
23
  end
14
24
 
@@ -18,4 +28,13 @@ module Geocoder
18
28
  class InvalidApiKey < Error
19
29
  end
20
30
 
31
+ class ServiceUnavailable < Error
32
+ end
33
+
34
+ class LookupTimeout < ::Timeout::Error
35
+ end
36
+
37
+ class NetworkError < Error
38
+ end
39
+
21
40
  end
@@ -0,0 +1,33 @@
1
+ require 'resolv'
2
+ module Geocoder
3
+ class IpAddress < String
4
+ PRIVATE_IPS = [
5
+ '10.0.0.0/8',
6
+ '172.16.0.0/12',
7
+ '192.168.0.0/16',
8
+ ].map { |ip| IPAddr.new(ip) }.freeze
9
+
10
+ def initialize(ip)
11
+ ip = ip.to_string if ip.is_a?(IPAddr)
12
+
13
+ super(ip)
14
+ end
15
+
16
+ def internal?
17
+ loopback? || private?
18
+ end
19
+
20
+ def loopback?
21
+ valid? and !!(self == "0.0.0.0" or self.match(/\A127\./) or self == "::1")
22
+ end
23
+
24
+ def private?
25
+ valid? && PRIVATE_IPS.any? { |ip| ip.include?(self) }
26
+ end
27
+
28
+ def valid?
29
+ ip = self[/(?<=\[)(.*?)(?=\])/] || self
30
+ !!((ip =~ Resolv::IPv4::Regex) || (ip =~ Resolv::IPv6::Regex))
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,25 @@
1
+ module Geocoder
2
+ class KernelLogger
3
+ include Singleton
4
+
5
+ def add(level, message)
6
+ return unless log_message_at_level?(level)
7
+ case level
8
+ when ::Logger::DEBUG, ::Logger::INFO
9
+ puts message
10
+ when ::Logger::WARN
11
+ warn message
12
+ when ::Logger::ERROR
13
+ raise message
14
+ when ::Logger::FATAL
15
+ fail message
16
+ end
17
+ end
18
+
19
+ private # ----------------------------------------------------------------
20
+
21
+ def log_message_at_level?(level)
22
+ level >= Geocoder.config.kernel_logger_level
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,47 @@
1
+ require 'logger'
2
+
3
+ module Geocoder
4
+
5
+ def self.log(level, message)
6
+ Logger.instance.log(level, message)
7
+ end
8
+
9
+ class Logger
10
+ include Singleton
11
+
12
+ SEVERITY = {
13
+ debug: ::Logger::DEBUG,
14
+ info: ::Logger::INFO,
15
+ warn: ::Logger::WARN,
16
+ error: ::Logger::ERROR,
17
+ fatal: ::Logger::FATAL
18
+ }
19
+
20
+ def log(level, message)
21
+ unless valid_level?(level)
22
+ raise StandardError, "Geocoder tried to log a message with an invalid log level."
23
+ end
24
+ if current_logger.respond_to? :add
25
+ current_logger.add(SEVERITY[level], message)
26
+ else
27
+ raise Geocoder::ConfigurationError, "Please specify valid logger for Geocoder. " +
28
+ "Logger specified must be :kernel or must respond to `add(level, message)`."
29
+ end
30
+ nil
31
+ end
32
+
33
+ private # ----------------------------------------------------------------
34
+
35
+ def current_logger
36
+ logger = Geocoder.config[:logger]
37
+ if logger == :kernel
38
+ logger = Geocoder::KernelLogger.instance
39
+ end
40
+ logger
41
+ end
42
+
43
+ def valid_level?(level)
44
+ SEVERITY.keys.include?(level)
45
+ end
46
+ end
47
+ end
@@ -1,3 +1,5 @@
1
+ require "geocoder/lookups/test"
2
+
1
3
  module Geocoder
2
4
  module Lookup
3
5
  extend self
@@ -16,25 +18,55 @@ module Geocoder
16
18
  all_services - [:test]
17
19
  end
18
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
+
19
29
  ##
20
30
  # All street address lookup services, default first.
21
31
  #
22
32
  def street_services
23
- [
33
+ @street_services ||= [
34
+ :location_iq,
24
35
  :dstk,
25
36
  :esri,
26
37
  :google,
27
38
  :google_premier,
28
- :yahoo,
39
+ :google_places_details,
40
+ :google_places_search,
29
41
  :bing,
30
42
  :geocoder_ca,
31
- :geocoder_us,
32
43
  :yandex,
44
+ :nationaal_georegister_nl,
33
45
  :nominatim,
46
+ :mapbox,
34
47
  :mapquest,
35
- :ovi,
48
+ :uk_ordnance_survey_names,
49
+ :opencagedata,
50
+ :pelias,
51
+ :pickpoint,
52
+ :here,
36
53
  :baidu,
37
- :test
54
+ :tencent,
55
+ :geocodio,
56
+ :smarty_streets,
57
+ :postcode_anywhere_uk,
58
+ :postcodes_io,
59
+ :geoportail_lu,
60
+ :ban_data_gouv_fr,
61
+ :test,
62
+ :latlon,
63
+ :amap,
64
+ :osmnames,
65
+ :melissa_street,
66
+ :amazon_location_service,
67
+ :geoapify,
68
+ :photon,
69
+ :twogis
38
70
  ]
39
71
  end
40
72
 
@@ -42,9 +74,30 @@ module Geocoder
42
74
  # All IP address lookup services, default first.
43
75
  #
44
76
  def ip_services
45
- [:freegeoip, :maxmind]
77
+ @ip_services ||= [
78
+ :baidu_ip,
79
+ :abstract_api,
80
+ :freegeoip,
81
+ :geoip2,
82
+ :maxmind,
83
+ :maxmind_local,
84
+ :telize,
85
+ :pointpin,
86
+ :maxmind_geoip2,
87
+ :ipinfo_io,
88
+ :ipregistry,
89
+ :ipapi_com,
90
+ :ipdata_co,
91
+ :db_ip_com,
92
+ :ipstack,
93
+ :ip2location,
94
+ :ipgeolocation,
95
+ :ipqualityscore
96
+ ]
46
97
  end
47
98
 
99
+ attr_writer :street_services, :ip_services
100
+
48
101
  ##
49
102
  # Retrieve a Lookup object from the store.
50
103
  # Use this instead of Geocoder::Lookup::X.new to get an
@@ -64,7 +117,8 @@ module Geocoder
64
117
  #
65
118
  def spawn(name)
66
119
  if all_services.include?(name)
67
- Geocoder::Lookup.const_get(classify_name(name)).new
120
+ name = name.to_s
121
+ instantiate_lookup(name)
68
122
  else
69
123
  valids = all_services.map(&:inspect).join(", ")
70
124
  raise ConfigurationError, "Please specify a valid lookup for Geocoder " +
@@ -78,9 +132,18 @@ module Geocoder
78
132
  def classify_name(filename)
79
133
  filename.to_s.split("_").map{ |i| i[0...1].upcase + i[1..-1] }.join
80
134
  end
81
- end
82
- end
83
135
 
84
- Geocoder::Lookup.all_services.each do |name|
85
- require "geocoder/lookups/#{name}"
136
+ ##
137
+ # Safely instantiate Lookup
138
+ #
139
+ def instantiate_lookup(name)
140
+ class_name = "Geocoder::Lookup::#{classify_name(name)}"
141
+ begin
142
+ Geocoder::Lookup.const_get(class_name)
143
+ rescue NameError
144
+ require "geocoder/lookups/#{name}"
145
+ end
146
+ Geocoder::Lookup.const_get(class_name).new
147
+ end
148
+ end
86
149
  end