geocoder 1.2.6 → 1.8.2

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 (309) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +266 -1
  3. data/LICENSE +1 -1
  4. data/README.md +530 -804
  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 +2 -0
  11. data/lib/generators/geocoder/maxmind/geolite_country_generator.rb +2 -0
  12. data/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb +1 -1
  13. data/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb +1 -1
  14. data/lib/generators/geocoder/migration_version.rb +15 -0
  15. data/lib/geocoder/cache.rb +20 -33
  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 +30 -38
  20. data/lib/geocoder/cli.rb +2 -2
  21. data/lib/geocoder/configuration.rb +36 -9
  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 +26 -11
  26. data/lib/geocoder/kernel_logger.rb +25 -0
  27. data/lib/geocoder/logger.rb +47 -0
  28. data/lib/geocoder/lookup.rb +63 -13
  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 +55 -0
  32. data/lib/geocoder/lookups/baidu.rb +17 -9
  33. data/lib/geocoder/lookups/baidu_ip.rb +7 -31
  34. data/lib/geocoder/lookups/ban_data_gouv_fr.rb +143 -0
  35. data/lib/geocoder/lookups/base.rb +75 -26
  36. data/lib/geocoder/lookups/bing.rb +38 -15
  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 +78 -12
  40. data/lib/geocoder/lookups/freegeoip.rb +22 -7
  41. data/lib/geocoder/lookups/geoapify.rb +78 -0
  42. data/lib/geocoder/lookups/geocoder_ca.rb +5 -6
  43. data/lib/geocoder/lookups/geocodio.rb +8 -8
  44. data/lib/geocoder/lookups/geoip2.rb +13 -4
  45. data/lib/geocoder/lookups/geoportail_lu.rb +65 -0
  46. data/lib/geocoder/lookups/google.rb +44 -11
  47. data/lib/geocoder/lookups/google_places_details.rb +31 -17
  48. data/lib/geocoder/lookups/google_places_search.rb +76 -0
  49. data/lib/geocoder/lookups/google_premier.rb +15 -1
  50. data/lib/geocoder/lookups/here.rb +38 -27
  51. data/lib/geocoder/lookups/ip2location.rb +71 -0
  52. data/lib/geocoder/lookups/ipapi_com.rb +82 -0
  53. data/lib/geocoder/lookups/ipbase.rb +49 -0
  54. data/lib/geocoder/lookups/ipdata_co.rb +62 -0
  55. data/lib/geocoder/lookups/ipgeolocation.rb +51 -0
  56. data/lib/geocoder/lookups/ipinfo_io.rb +44 -0
  57. data/lib/geocoder/lookups/ipqualityscore.rb +50 -0
  58. data/lib/geocoder/lookups/ipregistry.rb +68 -0
  59. data/lib/geocoder/lookups/ipstack.rb +63 -0
  60. data/lib/geocoder/lookups/latlon.rb +58 -0
  61. data/lib/geocoder/lookups/location_iq.rb +54 -0
  62. data/lib/geocoder/lookups/mapbox.rb +59 -0
  63. data/lib/geocoder/lookups/mapquest.rb +7 -9
  64. data/lib/geocoder/lookups/maxmind.rb +7 -7
  65. data/lib/geocoder/lookups/maxmind_geoip2.rb +70 -0
  66. data/lib/geocoder/lookups/maxmind_local.rb +16 -3
  67. data/lib/geocoder/lookups/melissa_street.rb +41 -0
  68. data/lib/geocoder/lookups/nationaal_georegister_nl.rb +38 -0
  69. data/lib/geocoder/lookups/nominatim.rb +18 -6
  70. data/lib/geocoder/lookups/opencagedata.rb +16 -9
  71. data/lib/geocoder/lookups/osmnames.rb +57 -0
  72. data/lib/geocoder/lookups/pc_miler.rb +85 -0
  73. data/lib/geocoder/lookups/pelias.rb +63 -0
  74. data/lib/geocoder/lookups/photon.rb +89 -0
  75. data/lib/geocoder/lookups/pickpoint.rb +41 -0
  76. data/lib/geocoder/lookups/pointpin.rb +14 -13
  77. data/lib/geocoder/lookups/postcode_anywhere_uk.rb +7 -8
  78. data/lib/geocoder/lookups/postcodes_io.rb +31 -0
  79. data/lib/geocoder/lookups/smarty_streets.rb +29 -6
  80. data/lib/geocoder/lookups/telize.rb +42 -7
  81. data/lib/geocoder/lookups/tencent.rb +59 -0
  82. data/lib/geocoder/lookups/test.rb +5 -0
  83. data/lib/geocoder/lookups/twogis.rb +58 -0
  84. data/lib/geocoder/lookups/uk_ordnance_survey_names.rb +59 -0
  85. data/lib/geocoder/lookups/yandex.rb +20 -13
  86. data/lib/geocoder/models/active_record.rb +4 -3
  87. data/lib/geocoder/models/mongo_base.rb +0 -2
  88. data/lib/geocoder/query.rb +15 -1
  89. data/lib/geocoder/railtie.rb +1 -1
  90. data/lib/geocoder/request.rb +103 -14
  91. data/lib/geocoder/results/abstract_api.rb +146 -0
  92. data/lib/geocoder/results/amap.rb +87 -0
  93. data/lib/geocoder/results/amazon_location_service.rb +57 -0
  94. data/lib/geocoder/results/baidu.rb +10 -14
  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 +15 -3
  104. data/lib/geocoder/results/geoip2.rb +37 -25
  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 +4 -0
  108. data/lib/geocoder/results/google_places_search.rb +52 -0
  109. data/lib/geocoder/results/here.rb +30 -15
  110. data/lib/geocoder/results/ip2location.rb +22 -0
  111. data/lib/geocoder/results/ipapi_com.rb +45 -0
  112. data/lib/geocoder/results/ipbase.rb +40 -0
  113. data/lib/geocoder/results/ipdata_co.rb +40 -0
  114. data/lib/geocoder/results/ipgeolocation.rb +59 -0
  115. data/lib/geocoder/results/ipinfo_io.rb +48 -0
  116. data/lib/geocoder/results/ipqualityscore.rb +54 -0
  117. data/lib/geocoder/results/ipregistry.rb +304 -0
  118. data/lib/geocoder/results/ipstack.rb +60 -0
  119. data/lib/geocoder/results/latlon.rb +71 -0
  120. data/lib/geocoder/results/location_iq.rb +6 -0
  121. data/lib/geocoder/results/mapbox.rb +63 -0
  122. data/lib/geocoder/results/mapquest.rb +5 -8
  123. data/lib/geocoder/results/maxmind.rb +0 -5
  124. data/lib/geocoder/results/maxmind_geoip2.rb +9 -0
  125. data/lib/geocoder/results/maxmind_local.rb +0 -5
  126. data/lib/geocoder/results/melissa_street.rb +46 -0
  127. data/lib/geocoder/results/nationaal_georegister_nl.rb +62 -0
  128. data/lib/geocoder/results/nominatim.rb +41 -14
  129. data/lib/geocoder/results/opencagedata.rb +20 -2
  130. data/lib/geocoder/results/osmnames.rb +56 -0
  131. data/lib/geocoder/results/pc_miler.rb +98 -0
  132. data/lib/geocoder/results/pelias.rb +58 -0
  133. data/lib/geocoder/results/photon.rb +119 -0
  134. data/lib/geocoder/results/pickpoint.rb +6 -0
  135. data/lib/geocoder/results/pointpin.rb +0 -4
  136. data/lib/geocoder/results/postcodes_io.rb +40 -0
  137. data/lib/geocoder/results/smarty_streets.rb +55 -19
  138. data/lib/geocoder/results/telize.rb +0 -5
  139. data/lib/geocoder/results/tencent.rb +72 -0
  140. data/lib/geocoder/results/test.rb +1 -1
  141. data/lib/geocoder/results/twogis.rb +76 -0
  142. data/lib/geocoder/results/uk_ordnance_survey_names.rb +59 -0
  143. data/lib/geocoder/results/yandex.rb +240 -32
  144. data/lib/geocoder/sql.rb +9 -6
  145. data/lib/geocoder/stores/active_record.rb +49 -10
  146. data/lib/geocoder/stores/base.rb +2 -14
  147. data/lib/geocoder/stores/mongo_base.rb +0 -31
  148. data/lib/geocoder/util.rb +29 -0
  149. data/lib/geocoder/version.rb +1 -1
  150. data/lib/geocoder.rb +2 -1
  151. data/lib/maxmind_database.rb +9 -9
  152. data/lib/tasks/geocoder.rake +29 -4
  153. data/lib/tasks/maxmind.rake +1 -1
  154. metadata +91 -169
  155. data/.gitignore +0 -6
  156. data/.travis.yml +0 -31
  157. data/Rakefile +0 -25
  158. data/examples/autoexpire_cache_dalli.rb +0 -62
  159. data/examples/autoexpire_cache_redis.rb +0 -28
  160. data/gemfiles/Gemfile.mongoid-2.4.x +0 -16
  161. data/lib/geocoder/lookups/geocoder_us.rb +0 -39
  162. data/lib/geocoder/lookups/okf.rb +0 -43
  163. data/lib/geocoder/lookups/ovi.rb +0 -62
  164. data/lib/geocoder/lookups/yahoo.rb +0 -88
  165. data/lib/geocoder/results/geocoder_us.rb +0 -39
  166. data/lib/geocoder/results/okf.rb +0 -106
  167. data/lib/geocoder/results/ovi.rb +0 -62
  168. data/lib/geocoder/results/yahoo.rb +0 -55
  169. data/lib/hash_recursive_merge.rb +0 -74
  170. data/lib/oauth_util.rb +0 -112
  171. data/test/fixtures/baidu_invalid_key +0 -1
  172. data/test/fixtures/baidu_ip_202_198_16_3 +0 -19
  173. data/test/fixtures/baidu_ip_invalid_key +0 -1
  174. data/test/fixtures/baidu_ip_no_results +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/cloudmade_invalid_key +0 -1
  183. data/test/fixtures/cloudmade_madison_square_garden +0 -1
  184. data/test/fixtures/cloudmade_no_results +0 -1
  185. data/test/fixtures/esri_madison_square_garden +0 -59
  186. data/test/fixtures/esri_no_results +0 -8
  187. data/test/fixtures/esri_reverse +0 -21
  188. data/test/fixtures/freegeoip_74_200_247_59 +0 -12
  189. data/test/fixtures/freegeoip_no_results +0 -1
  190. data/test/fixtures/geocoder_ca_madison_square_garden +0 -1
  191. data/test/fixtures/geocoder_ca_no_results +0 -1
  192. data/test/fixtures/geocoder_ca_reverse +0 -34
  193. data/test/fixtures/geocoder_us_madison_square_garden +0 -1
  194. data/test/fixtures/geocoder_us_no_results +0 -1
  195. data/test/fixtures/geocodio_1101_pennsylvania_ave +0 -1
  196. data/test/fixtures/geocodio_bad_api_key +0 -3
  197. data/test/fixtures/geocodio_invalid +0 -4
  198. data/test/fixtures/geocodio_no_results +0 -1
  199. data/test/fixtures/geocodio_over_query_limit +0 -4
  200. data/test/fixtures/google_garbage +0 -456
  201. data/test/fixtures/google_madison_square_garden +0 -57
  202. data/test/fixtures/google_no_city_data +0 -44
  203. data/test/fixtures/google_no_locality +0 -51
  204. data/test/fixtures/google_no_results +0 -4
  205. data/test/fixtures/google_over_limit +0 -4
  206. data/test/fixtures/google_places_details_invalid_request +0 -4
  207. data/test/fixtures/google_places_details_madison_square_garden +0 -120
  208. data/test/fixtures/google_places_details_no_results +0 -4
  209. data/test/fixtures/google_places_details_no_reviews +0 -60
  210. data/test/fixtures/google_places_details_no_types +0 -66
  211. data/test/fixtures/here_madison_square_garden +0 -72
  212. data/test/fixtures/here_no_results +0 -8
  213. data/test/fixtures/mapquest_error +0 -16
  214. data/test/fixtures/mapquest_invalid_api_key +0 -16
  215. data/test/fixtures/mapquest_invalid_request +0 -16
  216. data/test/fixtures/mapquest_madison_square_garden +0 -52
  217. data/test/fixtures/mapquest_no_results +0 -16
  218. data/test/fixtures/maxmind_24_24_24_21 +0 -1
  219. data/test/fixtures/maxmind_24_24_24_22 +0 -1
  220. data/test/fixtures/maxmind_24_24_24_23 +0 -1
  221. data/test/fixtures/maxmind_24_24_24_24 +0 -1
  222. data/test/fixtures/maxmind_74_200_247_59 +0 -1
  223. data/test/fixtures/maxmind_invalid_key +0 -1
  224. data/test/fixtures/maxmind_no_results +0 -1
  225. data/test/fixtures/nominatim_madison_square_garden +0 -150
  226. data/test/fixtures/nominatim_no_results +0 -1
  227. data/test/fixtures/nominatim_over_limit +0 -1
  228. data/test/fixtures/okf_kirstinmaki +0 -67
  229. data/test/fixtures/okf_no_results +0 -4
  230. data/test/fixtures/opencagedata_invalid_api_key +0 -25
  231. data/test/fixtures/opencagedata_invalid_request +0 -26
  232. data/test/fixtures/opencagedata_madison_square_garden +0 -73
  233. data/test/fixtures/opencagedata_no_results +0 -29
  234. data/test/fixtures/opencagedata_over_limit +0 -31
  235. data/test/fixtures/ovi_madison_square_garden +0 -72
  236. data/test/fixtures/ovi_no_results +0 -8
  237. data/test/fixtures/pointpin_10_10_10_10 +0 -1
  238. data/test/fixtures/pointpin_555_555_555_555 +0 -1
  239. data/test/fixtures/pointpin_80_111_555_555 +0 -1
  240. data/test/fixtures/pointpin_no_results +0 -1
  241. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_WR26NJ +0 -1
  242. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_generic_error +0 -1
  243. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_hampshire +0 -1
  244. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_key_limit_exceeded +0 -1
  245. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_no_results +0 -1
  246. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_romsey +0 -1
  247. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_unknown_key +0 -1
  248. data/test/fixtures/smarty_streets_11211 +0 -1
  249. data/test/fixtures/smarty_streets_madison_square_garden +0 -47
  250. data/test/fixtures/smarty_streets_no_results +0 -1
  251. data/test/fixtures/telize_10_10_10_10 +0 -1
  252. data/test/fixtures/telize_555_555_555_555 +0 -4
  253. data/test/fixtures/telize_74_200_247_59 +0 -1
  254. data/test/fixtures/telize_no_results +0 -1
  255. data/test/fixtures/yahoo_error +0 -1
  256. data/test/fixtures/yahoo_invalid_key +0 -2
  257. data/test/fixtures/yahoo_madison_square_garden +0 -52
  258. data/test/fixtures/yahoo_no_results +0 -10
  259. data/test/fixtures/yahoo_over_limit +0 -2
  260. data/test/fixtures/yandex_canada_rue_dupuis_14 +0 -446
  261. data/test/fixtures/yandex_invalid_key +0 -1
  262. data/test/fixtures/yandex_kremlin +0 -48
  263. data/test/fixtures/yandex_new_york +0 -1
  264. data/test/fixtures/yandex_no_city_and_town +0 -112
  265. data/test/fixtures/yandex_no_results +0 -16
  266. data/test/integration/http_client_test.rb +0 -31
  267. data/test/mongoid_test_helper.rb +0 -43
  268. data/test/test_helper.rb +0 -416
  269. data/test/unit/active_record_test.rb +0 -16
  270. data/test/unit/cache_test.rb +0 -37
  271. data/test/unit/calculations_test.rb +0 -220
  272. data/test/unit/configuration_test.rb +0 -55
  273. data/test/unit/error_handling_test.rb +0 -56
  274. data/test/unit/geocoder_test.rb +0 -78
  275. data/test/unit/https_test.rb +0 -17
  276. data/test/unit/ip_address_test.rb +0 -27
  277. data/test/unit/lookup_test.rb +0 -153
  278. data/test/unit/lookups/bing_test.rb +0 -68
  279. data/test/unit/lookups/dstk_test.rb +0 -26
  280. data/test/unit/lookups/esri_test.rb +0 -48
  281. data/test/unit/lookups/freegeoip_test.rb +0 -27
  282. data/test/unit/lookups/geocoder_ca_test.rb +0 -17
  283. data/test/unit/lookups/geocodio_test.rb +0 -55
  284. data/test/unit/lookups/geoip2_test.rb +0 -27
  285. data/test/unit/lookups/google_places_details_test.rb +0 -122
  286. data/test/unit/lookups/google_premier_test.rb +0 -22
  287. data/test/unit/lookups/google_test.rb +0 -84
  288. data/test/unit/lookups/mapquest_test.rb +0 -60
  289. data/test/unit/lookups/maxmind_local_test.rb +0 -28
  290. data/test/unit/lookups/maxmind_test.rb +0 -63
  291. data/test/unit/lookups/nominatim_test.rb +0 -31
  292. data/test/unit/lookups/okf_test.rb +0 -38
  293. data/test/unit/lookups/opencagedata_test.rb +0 -64
  294. data/test/unit/lookups/pointpin_test.rb +0 -30
  295. data/test/unit/lookups/postcode_anywhere_uk_test.rb +0 -70
  296. data/test/unit/lookups/smarty_streets_test.rb +0 -71
  297. data/test/unit/lookups/telize_test.rb +0 -36
  298. data/test/unit/lookups/yahoo_test.rb +0 -35
  299. data/test/unit/method_aliases_test.rb +0 -26
  300. data/test/unit/model_test.rb +0 -38
  301. data/test/unit/mongoid_test.rb +0 -47
  302. data/test/unit/near_test.rb +0 -87
  303. data/test/unit/oauth_util_test.rb +0 -31
  304. data/test/unit/proxy_test.rb +0 -37
  305. data/test/unit/query_test.rb +0 -52
  306. data/test/unit/rake_task_test.rb +0 -21
  307. data/test/unit/request_test.rb +0 -35
  308. data/test/unit/result_test.rb +0 -72
  309. data/test/unit/test_mode_test.rb +0 -70
@@ -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,63 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/amap"
3
+
4
+ module Geocoder::Lookup
5
+ class Amap < Base
6
+
7
+ def name
8
+ "AMap"
9
+ end
10
+
11
+ def required_api_key_parts
12
+ ["key"]
13
+ end
14
+
15
+ def supported_protocols
16
+ [:http]
17
+ end
18
+
19
+ private # ---------------------------------------------------------------
20
+
21
+ def base_query_url(query)
22
+ path = query.reverse_geocode? ? 'regeo' : 'geo'
23
+ "http://restapi.amap.com/v3/geocode/#{path}?"
24
+ end
25
+
26
+ def results(query, reverse = false)
27
+ return [] unless doc = fetch_data(query)
28
+ case [doc['status'], doc['info']]
29
+ when ['1', 'OK']
30
+ return doc['regeocodes'] unless doc['regeocodes'].blank?
31
+ return [doc['regeocode']] unless doc['regeocode'].blank?
32
+ return doc['geocodes'] unless doc['geocodes'].blank?
33
+ when ['0', 'INVALID_USER_KEY']
34
+ raise_error(Geocoder::InvalidApiKey, "invalid api key") ||
35
+ Geocoder.log(:warn, "#{self.name} Geocoding API error: invalid api key.")
36
+ else
37
+ raise_error(Geocoder::Error, "server error.") ||
38
+ Geocoder.log(:warn, "#{self.name} Geocoding API error: server error - [#{doc['info']}]")
39
+ end
40
+ return []
41
+ end
42
+
43
+ def query_url_params(query)
44
+ params = {
45
+ :key => configuration.api_key,
46
+ :output => "json"
47
+ }
48
+ if query.reverse_geocode?
49
+ params[:location] = revert_coordinates(query.text)
50
+ params[:extensions] = "all"
51
+ params[:coordsys] = "gps"
52
+ else
53
+ params[:address] = query.sanitized_text
54
+ end
55
+ params.merge(super)
56
+ end
57
+
58
+ def revert_coordinates(text)
59
+ [text[1],text[0]].join(",")
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,55 @@
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
+ resp = if query.reverse_geocode?
17
+ client.search_place_index_for_position(params.merge(position: query.coordinates.reverse))
18
+ else
19
+ client.search_place_index_for_text(params.merge(text: query.text))
20
+ end
21
+
22
+ resp.results.map(&:place)
23
+ end
24
+
25
+ private
26
+
27
+ def client
28
+ return @client if @client
29
+ require_sdk
30
+ keys = configuration.api_key
31
+ if keys
32
+ @client = Aws::LocationService::Client.new(**{
33
+ region: keys[:region],
34
+ access_key_id: keys[:access_key_id],
35
+ secret_access_key: keys[:secret_access_key]
36
+ }.compact)
37
+ else
38
+ @client = Aws::LocationService::Client.new
39
+ end
40
+ end
41
+
42
+ def require_sdk
43
+ begin
44
+ require 'aws-sdk-locationservice'
45
+ rescue LoadError
46
+ raise_error(Geocoder::ConfigurationError) ||
47
+ Geocoder.log(
48
+ :error,
49
+ "Couldn't load the Amazon Location Service SDK. " +
50
+ "Install it with: gem install aws-sdk-locationservice -v '~> 1.4'"
51
+ )
52
+ end
53
+ end
54
+ end
55
+ end
@@ -12,32 +12,41 @@ module Geocoder::Lookup
12
12
  ["key"]
13
13
  end
14
14
 
15
- def query_url(query)
16
- "http://api.map.baidu.com/geocoder/v2/?" + url_query_string(query)
15
+ # HTTP only
16
+ def supported_protocols
17
+ [:http]
17
18
  end
18
19
 
19
20
  private # ---------------------------------------------------------------
20
21
 
22
+ def base_query_url(query)
23
+ "#{protocol}://api.map.baidu.com/geocoder/v2/?"
24
+ end
25
+
26
+ def content_key
27
+ 'result'
28
+ end
29
+
21
30
  def results(query, reverse = false)
22
31
  return [] unless doc = fetch_data(query)
23
32
  case doc['status']
24
33
  when 0
25
- return [doc['result']] unless doc['result'].blank?
34
+ return [doc[content_key]] unless doc[content_key].blank?
26
35
  when 1, 3, 4
27
36
  raise_error(Geocoder::Error, "server error.") ||
28
- warn("Baidu Geocoding API error: server error.")
37
+ Geocoder.log(:warn, "#{name} Geocoding API error: server error.")
29
38
  when 2
30
39
  raise_error(Geocoder::InvalidRequest, "invalid request.") ||
31
- warn("Baidu Geocoding API error: invalid request.")
40
+ Geocoder.log(:warn, "#{name} Geocoding API error: invalid request.")
32
41
  when 5
33
42
  raise_error(Geocoder::InvalidApiKey, "invalid api key") ||
34
- warn("Baidu Geocoding API error: invalid api key.")
43
+ Geocoder.log(:warn, "#{name} Geocoding API error: invalid api key.")
35
44
  when 101, 102, 200..299
36
45
  raise_error(Geocoder::RequestDenied, "request denied") ||
37
- warn("Baidu Geocoding API error: request denied.")
46
+ Geocoder.log(:warn, "#{name} Geocoding API error: request denied.")
38
47
  when 300..399
39
48
  raise_error(Geocoder::OverQueryLimitError, "over query limit.") ||
40
- warn("Baidu Geocoding API error: over query limit.")
49
+ Geocoder.log(:warn, "#{name} Geocoding API error: over query limit.")
41
50
  end
42
51
  return []
43
52
  end
@@ -52,4 +61,3 @@ module Geocoder::Lookup
52
61
 
53
62
  end
54
63
  end
55
-
@@ -1,45 +1,21 @@
1
- require 'geocoder/lookups/base'
1
+ require 'geocoder/lookups/baidu'
2
2
  require 'geocoder/results/baidu_ip'
3
3
 
4
4
  module Geocoder::Lookup
5
- class BaiduIp < Base
5
+ class BaiduIp < Baidu
6
6
 
7
7
  def name
8
8
  "Baidu IP"
9
9
  end
10
10
 
11
- def required_api_key_parts
12
- ["key"]
13
- end
11
+ private # ---------------------------------------------------------------
14
12
 
15
- def query_url(query)
16
- "http://api.map.baidu.com/location/ip?" + url_query_string(query)
13
+ def base_query_url(query)
14
+ "#{protocol}://api.map.baidu.com/location/ip?"
17
15
  end
18
16
 
19
- private # ---------------------------------------------------------------
20
-
21
- def results(query, reverse = false)
22
- return [] unless doc = fetch_data(query)
23
- case doc['status']
24
- when 0
25
- return [doc['content']] unless doc['content'].blank?
26
- when 1, 3, 4
27
- raise_error(Geocoder::Error, "server error.") ||
28
- warn("Baidu IP Geocoding API error: server error.")
29
- when 2
30
- raise_error(Geocoder::InvalidRequest, "invalid request.") ||
31
- warn("Baidu IP Geocoding API error: invalid request.")
32
- when 5
33
- raise_error(Geocoder::InvalidApiKey, "invalid api key.") ||
34
- warn("Baidu IP Geocoding API error: invalid api key.")
35
- when 101, 102, 200..299
36
- raise_error(Geocoder::RequestDenied, "request denied.") ||
37
- warn("Baidu IP Geocoding API error: request denied.")
38
- when 300..399
39
- raise_error(Geocoder::OverQueryLimitError, "over query limit") ||
40
- warn("Baidu IP Geocoding API error: over query limit.")
41
- end
42
- return []
17
+ def content_key
18
+ 'content'
43
19
  end
44
20
 
45
21
  def query_url_params(query)
@@ -0,0 +1,143 @@
1
+ # encoding: utf-8
2
+
3
+ require 'geocoder/lookups/base'
4
+ require 'geocoder/results/ban_data_gouv_fr'
5
+
6
+ module Geocoder::Lookup
7
+ class BanDataGouvFr < Base
8
+
9
+ def name
10
+ "Base Adresse Nationale Française"
11
+ end
12
+
13
+ def map_link_url(coordinates)
14
+ "https://www.openstreetmap.org/#map=19/#{coordinates.join('/')}"
15
+ end
16
+
17
+ private # ---------------------------------------------------------------
18
+
19
+ def base_query_url(query)
20
+ method = query.reverse_geocode? ? "reverse" : "search"
21
+ "#{protocol}://api-adresse.data.gouv.fr/#{method}/?"
22
+ end
23
+
24
+ def any_result?(doc)
25
+ doc['features'] and doc['features'].any?
26
+ end
27
+
28
+ def results(query)
29
+ if doc = fetch_data(query) and any_result?(doc)
30
+ [doc]
31
+ else
32
+ []
33
+ end
34
+ end
35
+
36
+ #### PARAMS ####
37
+
38
+ def query_url_params(query)
39
+ query_ban_datagouv_fr_params(query).merge(super)
40
+ end
41
+
42
+ def query_ban_datagouv_fr_params(query)
43
+ query.reverse_geocode? ? reverse_geocode_ban_fr_params(query) : search_geocode_ban_fr_params(query)
44
+ end
45
+
46
+ #### SEARCH GEOCODING PARAMS ####
47
+ #
48
+ # :q => required, full text search param)
49
+
50
+ # :limit => force limit number of results returned by raw API
51
+ # (default = 5) note : only first result is taken
52
+ # in account in geocoder
53
+ #
54
+ # :autocomplete => pass 0 to disable autocomplete treatment of :q
55
+ # (default = 1)
56
+ #
57
+ # :lat => force filter results around specific lat/lon
58
+ #
59
+ # :lon => force filter results around specific lat/lon
60
+ #
61
+ # :type => force filter the returned result type
62
+ # (check results for a list of accepted types)
63
+ #
64
+ # :postcode => force filter results on a specific city post code
65
+ #
66
+ # :citycode => force filter results on a specific city UUID INSEE code
67
+ #
68
+ # For up to date doc (in french only) : https://adresse.data.gouv.fr/api/
69
+ #
70
+ def search_geocode_ban_fr_params(query)
71
+ params = {
72
+ q: query.sanitized_text
73
+ }
74
+ unless (limit = query.options[:limit]).nil? || !limit_param_is_valid?(limit)
75
+ params[:limit] = limit.to_i
76
+ end
77
+ unless (autocomplete = query.options[:autocomplete]).nil? || !autocomplete_param_is_valid?(autocomplete)
78
+ params[:autocomplete] = autocomplete.to_s
79
+ end
80
+ unless (type = query.options[:type]).nil? || !type_param_is_valid?(type)
81
+ params[:type] = type.downcase
82
+ end
83
+ unless (postcode = query.options[:postcode]).nil? || !code_param_is_valid?(postcode)
84
+ params[:postcode] = postcode.to_s
85
+ end
86
+ unless (citycode = query.options[:citycode]).nil? || !code_param_is_valid?(citycode)
87
+ params[:citycode] = citycode.to_s
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
95
+ params
96
+ end
97
+
98
+ #### REVERSE GEOCODING PARAMS ####
99
+ #
100
+ # :lat => required
101
+ #
102
+ # :lon => required
103
+ #
104
+ # :type => force returned results type
105
+ # (check results for a list of accepted types)
106
+ #
107
+ def reverse_geocode_ban_fr_params(query)
108
+ lat_lon = query.coordinates
109
+ params = {
110
+ lat: lat_lon.first,
111
+ lon: lat_lon.last
112
+ }
113
+ unless (type = query.options[:type]).nil? || !type_param_is_valid?(type)
114
+ params[:type] = type.downcase
115
+ end
116
+ params
117
+ end
118
+
119
+ def limit_param_is_valid?(param)
120
+ param.to_i.positive?
121
+ end
122
+
123
+ def autocomplete_param_is_valid?(param)
124
+ [0,1].include?(param.to_i)
125
+ end
126
+
127
+ def type_param_is_valid?(param)
128
+ %w(housenumber street locality municipality).include?(param.downcase)
129
+ end
130
+
131
+ def code_param_is_valid?(param)
132
+ (1..99999).include?(param.to_i)
133
+ end
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
142
+ end
143
+ end
@@ -4,7 +4,6 @@ require 'uri'
4
4
 
5
5
  unless defined?(ActiveSupport::JSON)
6
6
  begin
7
- require 'rubygems' # for Ruby 1.8
8
7
  require 'json'
9
8
  rescue LoadError
10
9
  raise LoadError, "Please install the 'json' or 'json_pure' gem to parse geocoder results."
@@ -72,8 +71,12 @@ module Geocoder
72
71
  ##
73
72
  # URL to use for querying the geocoding engine.
74
73
  #
74
+ # Subclasses should not modify this method. Instead they should define
75
+ # base_query_url and url_query_string. If absolutely necessary to
76
+ # subclss this method, they must also subclass #cache_key.
77
+ #
75
78
  def query_url(query)
76
- fail
79
+ base_query_url(query) + url_query_string(query)
77
80
  end
78
81
 
79
82
  ##
@@ -81,13 +84,31 @@ module Geocoder
81
84
  #
82
85
  def cache
83
86
  if @cache.nil? and store = configuration.cache
84
- @cache = Cache.new(store, configuration.cache_prefix)
87
+ cache_options = configuration.cache_options
88
+ @cache = Cache.new(store, cache_options)
85
89
  end
86
90
  @cache
87
91
  end
88
92
 
93
+ ##
94
+ # Array containing the protocols supported by the api.
95
+ # Should be set to [:http] if only HTTP is supported
96
+ # or [:https] if only HTTPS is supported.
97
+ #
98
+ def supported_protocols
99
+ [:http, :https]
100
+ end
101
+
89
102
  private # -------------------------------------------------------------
90
103
 
104
+ ##
105
+ # String which, when concatenated with url_query_string(query)
106
+ # produces the full query URL. Should include the "?" a the end.
107
+ #
108
+ def base_query_url(query)
109
+ fail
110
+ end
111
+
91
112
  ##
92
113
  # An object with configuration data for this particular lookup.
93
114
  #
@@ -99,7 +120,6 @@ module Geocoder
99
120
  # Object used to make HTTP requests.
100
121
  #
101
122
  def http_client
102
- protocol = "http#{'s' if use_ssl?}"
103
123
  proxy_name = "#{protocol}_proxy"
104
124
  if proxy = configuration.send(proxy_name)
105
125
  proxy_url = !!(proxy =~ /^#{protocol}/) ? proxy : protocol + '://' + proxy
@@ -139,7 +159,14 @@ module Geocoder
139
159
  # something else (like the URL before OAuth encoding).
140
160
  #
141
161
  def cache_key(query)
142
- query_url(query)
162
+ base_query_url(query) + hash_to_query(cache_key_params(query))
163
+ end
164
+
165
+ def cache_key_params(query)
166
+ # omit api_key and token because they may vary among requests
167
+ query_url_params(query).reject do |key,value|
168
+ key.to_s.match(/(key|token)/)
169
+ end
143
170
  end
144
171
 
145
172
  ##
@@ -168,12 +195,14 @@ module Geocoder
168
195
  def fetch_data(query)
169
196
  parse_raw_data fetch_raw_data(query)
170
197
  rescue SocketError => err
171
- raise_error(err) or warn "Geocoding API connection cannot be established."
198
+ raise_error(err) or Geocoder.log(:warn, "Geocoding API connection cannot be established.")
172
199
  rescue Errno::ECONNREFUSED => err
173
- raise_error(err) or warn "Geocoding API connection refused."
174
- rescue TimeoutError => err
175
- raise_error(err) or warn "Geocoding API not responding fast enough " +
176
- "(use Geocoder.configure(:timeout => ...) to set limit)."
200
+ raise_error(err) or Geocoder.log(:warn, "Geocoding API connection refused.")
201
+ rescue Geocoder::NetworkError => err
202
+ raise_error(err) or Geocoder.log(:warn, "Geocoding API connection is either unreacheable or reset by the peer")
203
+ rescue Timeout::Error => err
204
+ raise_error(err) or Geocoder.log(:warn, "Geocoding API not responding fast enough " +
205
+ "(use Geocoder.configure(:timeout => ...) to set limit).")
177
206
  end
178
207
 
179
208
  def parse_json(data)
@@ -182,6 +211,11 @@ module Geocoder
182
211
  else
183
212
  JSON.parse(data)
184
213
  end
214
+ rescue
215
+ unless raise_error(ResponseParseError.new(data))
216
+ Geocoder.log(:warn, "Geocoding API's response was not valid JSON")
217
+ Geocoder.log(:debug, "Raw response: #{data}")
218
+ end
185
219
  end
186
220
 
187
221
  ##
@@ -189,8 +223,6 @@ module Geocoder
189
223
  #
190
224
  def parse_raw_data(raw_data)
191
225
  parse_json(raw_data)
192
- rescue
193
- warn "Geocoding API's response was not valid JSON."
194
226
  end
195
227
 
196
228
  ##
@@ -242,16 +274,19 @@ module Geocoder
242
274
  def check_response_for_errors!(response)
243
275
  if response.code.to_i == 400
244
276
  raise_error(Geocoder::InvalidRequest) ||
245
- warn("Geocoding API error: 400 Bad Request")
277
+ Geocoder.log(:warn, "Geocoding API error: 400 Bad Request")
246
278
  elsif response.code.to_i == 401
247
279
  raise_error(Geocoder::RequestDenied) ||
248
- warn("Geocoding API error: 401 Unauthorized")
280
+ Geocoder.log(:warn, "Geocoding API error: 401 Unauthorized")
249
281
  elsif response.code.to_i == 402
250
282
  raise_error(Geocoder::OverQueryLimitError) ||
251
- warn("Geocoding API error: 402 Payment Required")
283
+ Geocoder.log(:warn, "Geocoding API error: 402 Payment Required")
252
284
  elsif response.code.to_i == 429
253
285
  raise_error(Geocoder::OverQueryLimitError) ||
254
- warn("Geocoding API error: 429 Too Many Requests")
286
+ Geocoder.log(:warn, "Geocoding API error: 429 Too Many Requests")
287
+ elsif response.code.to_i == 503
288
+ raise_error(Geocoder::ServiceUnavailable) ||
289
+ Geocoder.log(:warn, "Geocoding API error: 503 Service Unavailable")
255
290
  end
256
291
  end
257
292
 
@@ -260,23 +295,37 @@ module Geocoder
260
295
  # return the response object.
261
296
  #
262
297
  def make_api_request(query)
263
- timeout(configuration.timeout) do
264
- uri = URI.parse(query_url(query))
265
- args = [uri.host, uri.port]
266
- args = args.push(uri.user, uri.password) unless uri.user.nil? or uri.password.nil?
267
- opts = {}
268
- opts[:use_ssl] = use_ssl?
269
-
270
- http_client.start(*args, opts) do |client|
271
- client.get(uri.request_uri, configuration.http_headers)
298
+ uri = URI.parse(query_url(query))
299
+ Geocoder.log(:debug, "Geocoder: HTTP request being made for #{uri.to_s}")
300
+ http_client.start(uri.host, uri.port, use_ssl: use_ssl?, open_timeout: configuration.timeout, read_timeout: configuration.timeout) do |client|
301
+ configure_ssl!(client) if use_ssl?
302
+ req = Net::HTTP::Get.new(uri.request_uri, configuration.http_headers)
303
+ if configuration.basic_auth[:user] and configuration.basic_auth[:password]
304
+ req.basic_auth(
305
+ configuration.basic_auth[:user],
306
+ configuration.basic_auth[:password]
307
+ )
272
308
  end
309
+ client.request(req)
273
310
  end
311
+ rescue Timeout::Error
312
+ raise Geocoder::LookupTimeout
313
+ rescue Errno::EHOSTUNREACH, Errno::ETIMEDOUT, Errno::ENETUNREACH, Errno::ECONNRESET
314
+ raise Geocoder::NetworkError
274
315
  end
275
316
 
276
317
  def use_ssl?
277
- configuration.use_https
318
+ if supported_protocols == [:https]
319
+ true
320
+ elsif supported_protocols == [:http]
321
+ false
322
+ else
323
+ configuration.use_https
324
+ end
278
325
  end
279
326
 
327
+ def configure_ssl!(client); end
328
+
280
329
  def check_api_key_configuration!(query)
281
330
  key_parts = query.lookup.required_api_key_parts
282
331
  if key_parts.size > Array(configuration.api_key).size
@@ -16,24 +16,20 @@ module Geocoder::Lookup
16
16
  ["key"]
17
17
  end
18
18
 
19
- def query_url(query)
20
- base_url(query) + url_query_string(query)
21
- end
22
-
23
19
  private # ---------------------------------------------------------------
24
20
 
25
- def base_url(query)
26
- url = "#{protocol}://dev.virtualearth.net/REST/v1/Locations"
27
-
28
- if !query.reverse_geocode?
21
+ def base_query_url(query)
22
+ text = CGI.escape(query.sanitized_text.strip)
23
+ url = "#{protocol}://dev.virtualearth.net/REST/v1/Locations/"
24
+ if query.reverse_geocode?
25
+ url + "#{text}?"
26
+ else
29
27
  if r = query.options[:region]
30
- url << "/#{r}"
28
+ url << "#{r}/"
31
29
  end
32
30
  # use the more forgiving 'unstructured' query format to allow special
33
31
  # chars, newlines, brackets, typos.
34
- url + "?q=" + URI.escape(query.sanitized_text.strip) + "&"
35
- else
36
- url + "/#{URI.escape(query.sanitized_text.strip)}?"
32
+ url + "?q=#{text}&"
37
33
  end
38
34
  end
39
35
 
@@ -43,17 +39,44 @@ module Geocoder::Lookup
43
39
  if doc['statusCode'] == 200
44
40
  return doc['resourceSets'].first['estimatedTotal'] > 0 ? doc['resourceSets'].first['resources'] : []
45
41
  elsif doc['statusCode'] == 401 and doc["authenticationResultCode"] == "InvalidCredentials"
46
- raise_error(Geocoder::InvalidApiKey) || warn("Invalid Bing API key.")
42
+ raise_error(Geocoder::InvalidApiKey) || Geocoder.log(:warn, "Invalid Bing API key.")
43
+ elsif doc['statusCode'] == 403
44
+ raise_error(Geocoder::RequestDenied) || Geocoder.log(:warn, "Bing Geocoding API error: Forbidden Request")
45
+ elsif [500, 503].include?(doc['statusCode'])
46
+ raise_error(Geocoder::ServiceUnavailable) ||
47
+ Geocoder.log(:warn, "Bing Geocoding API error: Service Unavailable")
47
48
  else
48
- warn "Bing Geocoding API error: #{doc['statusCode']} (#{doc['statusDescription']})."
49
+ Geocoder.log(:warn, "Bing Geocoding API error: #{doc['statusCode']} (#{doc['statusDescription']}).")
49
50
  end
50
51
  return []
51
52
  end
52
53
 
53
54
  def query_url_params(query)
54
55
  {
55
- key: configuration.api_key
56
+ key: configuration.api_key,
57
+ culture: (query.language || configuration.language)
56
58
  }.merge(super)
57
59
  end
60
+
61
+ def check_response_for_errors!(response)
62
+ super
63
+ if server_overloaded?(response)
64
+ raise_error(Geocoder::ServiceUnavailable) ||
65
+ Geocoder.log(:warn, "Bing Geocoding API error: Service Unavailable")
66
+ end
67
+ end
68
+
69
+ def valid_response?(response)
70
+ super(response) and not server_overloaded?(response)
71
+ end
72
+
73
+ def server_overloaded?(response)
74
+ # Occasionally, the servers processing service requests can be overloaded,
75
+ # and you may receive some responses that contain no results for queries that
76
+ # you would normally receive a result. To identify this situation,
77
+ # check the HTTP headers of the response. If the HTTP header X-MS-BM-WS-INFO is set to 1,
78
+ # it is best to wait a few seconds and try again.
79
+ response['x-ms-bm-ws-info'].to_i == 1
80
+ end
58
81
  end
59
82
  end