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,52 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/db_ip_com'
3
+
4
+ module Geocoder::Lookup
5
+ class DbIpCom < Base
6
+
7
+ def name
8
+ 'DB-IP.com'
9
+ end
10
+
11
+ def supported_protocols
12
+ [:https, :http]
13
+ end
14
+
15
+ def required_api_key_parts
16
+ ['api_key']
17
+ end
18
+
19
+ private # ----------------------------------------------------------------
20
+
21
+ def base_query_url(query)
22
+ "#{protocol}://api.db-ip.com/v2/#{configuration.api_key}/#{query.sanitized_text}?"
23
+ end
24
+
25
+ ##
26
+ # Same as query_url but without the api key.
27
+ #
28
+ def cache_key(query)
29
+ "#{protocol}://api.db-ip.com/v2/#{query.sanitized_text}?" + hash_to_query(cache_key_params(query))
30
+ end
31
+
32
+ def results(query)
33
+ return [] unless (doc = fetch_data(query))
34
+
35
+ case doc['error']
36
+ when 'maximum number of queries per day exceeded'
37
+ raise_error Geocoder::OverQueryLimitError ||
38
+ Geocoder.log(:warn, 'DB-API query limit exceeded.')
39
+
40
+ when 'invalid API key'
41
+ raise_error Geocoder::InvalidApiKey ||
42
+ Geocoder.log(:warn, 'Invalid DB-IP API key.')
43
+ when nil
44
+ [doc]
45
+
46
+ else
47
+ raise_error Geocoder::Error ||
48
+ Geocoder.log(:warn, "Request failed: #{doc['error']}")
49
+ end
50
+ end
51
+ end
52
+ end
@@ -12,9 +12,11 @@ module Geocoder::Lookup
12
12
  "Data Science Toolkit"
13
13
  end
14
14
 
15
- def query_url(query)
15
+ private # ----------------------------------------------------------------
16
+
17
+ def base_query_url(query)
16
18
  host = configuration[:host] || "www.datasciencetoolkit.org"
17
- "#{protocol}://#{host}/maps/api/geocode/json?" + url_query_string(query)
19
+ "#{protocol}://#{host}/maps/api/geocode/json?"
18
20
  end
19
21
  end
20
22
  end
@@ -1,34 +1,50 @@
1
1
  require 'geocoder/lookups/base'
2
2
  require "geocoder/results/esri"
3
+ require 'geocoder/esri_token'
3
4
 
4
5
  module Geocoder::Lookup
5
6
  class Esri < Base
6
-
7
+
7
8
  def name
8
9
  "Esri"
9
10
  end
10
11
 
11
- def query_url(query)
12
- search_keyword = query.reverse_geocode? ? "reverseGeocode" : "find"
13
-
14
- "#{protocol}://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/#{search_keyword}?" +
15
- url_query_string(query)
16
- end
12
+ def supported_protocols
13
+ [:https]
14
+ end
17
15
 
18
16
  private # ---------------------------------------------------------------
19
17
 
18
+ def base_query_url(query)
19
+ action = query.reverse_geocode? ? "reverseGeocode" : "find"
20
+ "#{protocol}://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/#{action}?"
21
+ end
22
+
20
23
  def results(query)
21
24
  return [] unless doc = fetch_data(query)
22
25
 
23
- if (!query.reverse_geocode?)
24
- return [] if doc['locations'].empty?
25
- end
26
-
27
26
  if (doc['error'].nil?)
27
+ if (!query.reverse_geocode?)
28
+ return [] if !doc['locations'] || doc['locations'].empty?
29
+ end
28
30
  return [ doc ]
29
31
  else
30
- return []
32
+ case [ doc['error']['code'] ]
33
+ when [498]
34
+ raise_error(Geocoder::InvalidApiKey, doc['error']['message']) ||
35
+ Geocoder.log(:warn, "#{self.name} Geocoding API error: #{doc['error']['message']}")
36
+ when [ 403 ]
37
+ raise_error(Geocoder::RequestDenied, 'ESRI request denied') ||
38
+ Geocoder.log(:warn, "#{self.name} ESRI request denied: #{doc['error']['message']}")
39
+ when [ 500 ], [501]
40
+ raise_error(Geocoder::ServiceUnavailable, 'ESRI service unavailable') ||
41
+ Geocoder.log(:warn, "#{self.name} ESRI service error: #{doc['error']['message']}")
42
+ else
43
+ raise_error(Geocoder::Error, doc['error']['message']) ||
44
+ Geocoder.log(:warn, "#{self.name} Geocoding error: #{doc['error']['message']}")
45
+ end
31
46
  end
47
+ return []
32
48
  end
33
49
 
34
50
  def query_url_params(query)
@@ -41,8 +57,58 @@ module Geocoder::Lookup
41
57
  else
42
58
  params[:text] = query.sanitized_text
43
59
  end
60
+
61
+ params[:token] = token(query)
62
+
63
+ if for_storage_value = for_storage(query)
64
+ params[:forStorage] = for_storage_value
65
+ end
66
+ params[:sourceCountry] = configuration[:source_country] if configuration[:source_country]
67
+ params[:preferredLabelValues] = configuration[:preferred_label_values] if configuration[:preferred_label_values]
68
+
44
69
  params.merge(super)
45
70
  end
46
71
 
72
+ def for_storage(query)
73
+ if query.options.has_key?(:for_storage)
74
+ query.options[:for_storage]
75
+ else
76
+ configuration[:for_storage]
77
+ end
78
+ end
79
+
80
+ def token(query)
81
+ token_instance = if query.options[:token]
82
+ query.options[:token]
83
+ else
84
+ configuration[:token]
85
+ end
86
+
87
+ if !valid_token_configured?(token_instance) && configuration.api_key
88
+ token_instance = create_and_save_token!(query)
89
+ end
90
+
91
+ token_instance.to_s unless token_instance.nil?
92
+ end
93
+
94
+ def valid_token_configured?(token_instance)
95
+ !token_instance.nil? && token_instance.active?
96
+ end
97
+
98
+ def create_and_save_token!(query)
99
+ token_instance = create_token
100
+
101
+ if query.options[:token]
102
+ query.options[:token] = token_instance
103
+ else
104
+ Geocoder.merge_into_lookup_config(:esri, token: token_instance)
105
+ end
106
+
107
+ token_instance
108
+ end
109
+
110
+ def create_token
111
+ Geocoder::EsriToken.generate_token(*configuration.api_key)
112
+ end
47
113
  end
48
114
  end
@@ -8,19 +8,34 @@ module Geocoder::Lookup
8
8
  "FreeGeoIP"
9
9
  end
10
10
 
11
- def query_url(query)
12
- "#{protocol}://#{host}/json/#{query.sanitized_text}"
11
+ def supported_protocols
12
+ if configuration[:host]
13
+ [:https]
14
+ else
15
+ # use https for default host
16
+ [:https]
17
+ end
13
18
  end
14
19
 
15
20
  private # ---------------------------------------------------------------
16
21
 
22
+ def base_query_url(query)
23
+ "#{protocol}://#{host}/json/#{query.sanitized_text}?"
24
+ end
25
+
26
+ def query_url_params(query)
27
+ {
28
+ :apikey => configuration.api_key
29
+ }.merge(super)
30
+ end
31
+
17
32
  def parse_raw_data(raw_data)
18
33
  raw_data.match(/^<html><title>404/) ? nil : super(raw_data)
19
34
  end
20
35
 
21
36
  def results(query)
22
- # don't look up a loopback address, just return the stored result
23
- return [reserved_result(query.text)] if query.loopback_ip_address?
37
+ # don't look up a loopback or private address, just return the stored result
38
+ return [reserved_result(query.text)] if query.internal_ip_address?
24
39
  # note: Freegeoip.net returns plain text "Not Found" on bad request
25
40
  (doc = fetch_data(query)) ? [doc] : []
26
41
  end
@@ -31,8 +46,8 @@ module Geocoder::Lookup
31
46
  "city" => "",
32
47
  "region_code" => "",
33
48
  "region_name" => "",
34
- "metrocode" => "",
35
- "zipcode" => "",
49
+ "metro_code" => "",
50
+ "zip_code" => "",
36
51
  "latitude" => "0",
37
52
  "longitude" => "0",
38
53
  "country_name" => "Reserved",
@@ -41,7 +56,7 @@ module Geocoder::Lookup
41
56
  end
42
57
 
43
58
  def host
44
- configuration[:host] || "freegeoip.net"
59
+ configuration[:host] || "freegeoip.app"
45
60
  end
46
61
  end
47
62
  end
@@ -0,0 +1,78 @@
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 = if query.reverse_geocode?
26
+ 'reverse'
27
+ elsif query.options[:autocomplete]
28
+ 'autocomplete'
29
+ else
30
+ 'search'
31
+ end
32
+ "https://api.geoapify.com/v1/geocode/#{method}?"
33
+ end
34
+
35
+ def results(query)
36
+ return [] unless (doc = fetch_data(query))
37
+
38
+ # The rest of the status codes should be already handled by the default
39
+ # functionality as the API returns correct HTTP response codes in most
40
+ # cases. There may be some unhandled cases still (such as over query
41
+ # limit reached) but there is not enough documentation to cover them.
42
+ case doc['statusCode']
43
+ when 500
44
+ raise_error(Geocoder::InvalidRequest) || Geocoder.log(:warn, doc['message'])
45
+ end
46
+
47
+ return [] unless doc['type'] == 'FeatureCollection'
48
+ return [] unless doc['features'] || doc['features'].present?
49
+
50
+ doc['features']
51
+ end
52
+
53
+ def query_url_params(query)
54
+ lang = query.language || configuration.language
55
+ params = { apiKey: configuration.api_key, lang: lang, limit: query.options[:limit] }
56
+
57
+ if query.reverse_geocode?
58
+ params.merge!(query_url_params_reverse(query))
59
+ else
60
+ params.merge!(query_url_params_coordinates(query))
61
+ end
62
+
63
+ params.merge!(super)
64
+ end
65
+
66
+ def query_url_params_coordinates(query)
67
+ { text: query.sanitized_text }
68
+ end
69
+
70
+ def query_url_params_reverse(query)
71
+ {
72
+ lat: query.coordinates[0],
73
+ lon: query.coordinates[1]
74
+ }
75
+ end
76
+ end
77
+ end
78
+ end
@@ -8,12 +8,12 @@ module Geocoder::Lookup
8
8
  "Geocoder.ca"
9
9
  end
10
10
 
11
- def query_url(query)
12
- "#{protocol}://geocoder.ca/?" + url_query_string(query)
13
- end
14
-
15
11
  private # ---------------------------------------------------------------
16
12
 
13
+ def base_query_url(query)
14
+ "#{protocol}://geocoder.ca/?"
15
+ end
16
+
17
17
  def results(query)
18
18
  return [] unless doc = fetch_data(query)
19
19
  if doc['error'].nil?
@@ -21,7 +21,7 @@ module Geocoder::Lookup
21
21
  elsif doc['error']['code'] == "005"
22
22
  # "Postal Code is not in the proper Format" => no results, just shut up
23
23
  else
24
- warn "Geocoder.ca service error: #{doc['error']['code']} (#{doc['error']['description']})."
24
+ Geocoder.log(:warn, "Geocoder.ca service error: #{doc['error']['code']} (#{doc['error']['description']}).")
25
25
  end
26
26
  return []
27
27
  end
@@ -51,4 +51,3 @@ module Geocoder::Lookup
51
51
  end
52
52
  end
53
53
  end
54
-
@@ -8,30 +8,30 @@ module Geocoder::Lookup
8
8
  "Geocodio"
9
9
  end
10
10
 
11
- def query_url(query)
12
- path = query.reverse_geocode? ? "reverse" : "geocode"
13
- "#{protocol}://api.geocod.io/v1/#{path}?#{url_query_string(query)}"
14
- end
15
-
16
11
  def results(query)
17
12
  return [] unless doc = fetch_data(query)
18
13
  return doc["results"] if doc['error'].nil?
19
14
 
20
15
  if doc['error'] == 'Invalid API key'
21
16
  raise_error(Geocoder::InvalidApiKey) ||
22
- warn("Geocodio service error: invalid API key.")
17
+ Geocoder.log(:warn, "Geocodio service error: invalid API key.")
23
18
  elsif doc['error'].match(/You have reached your daily maximum/)
24
19
  raise_error(Geocoder::OverQueryLimitError, doc['error']) ||
25
- warn("Geocodio service error: #{doc['error']}.")
20
+ Geocoder.log(:warn, "Geocodio service error: #{doc['error']}.")
26
21
  else
27
22
  raise_error(Geocoder::InvalidRequest, doc['error']) ||
28
- warn("Geocodio service error: #{doc['error']}.")
23
+ Geocoder.log(:warn, "Geocodio service error: #{doc['error']}.")
29
24
  end
30
25
  []
31
26
  end
32
27
 
33
28
  private # ---------------------------------------------------------------
34
29
 
30
+ def base_query_url(query)
31
+ path = query.reverse_geocode? ? "reverse" : "geocode"
32
+ "#{protocol}://api.geocod.io/v1.6/#{path}?"
33
+ end
34
+
35
35
  def query_url_params(query)
36
36
  {
37
37
  :api_key => configuration.api_key,
@@ -4,6 +4,8 @@ require 'geocoder/results/geoip2'
4
4
  module Geocoder
5
5
  module Lookup
6
6
  class Geoip2 < Base
7
+ attr_reader :gem_name
8
+
7
9
  def initialize
8
10
  unless configuration[:file].nil?
9
11
  begin
@@ -12,6 +14,8 @@ module Geocoder
12
14
  rescue LoadError
13
15
  raise "Could not load Maxmind DB dependency. To use the GeoIP2 lookup you must add the #{@gem_name} gem to your Gemfile or have it installed in your system."
14
16
  end
17
+
18
+ @mmdb = db_class.new(configuration[:file].to_s)
15
19
  end
16
20
  super
17
21
  end
@@ -26,13 +30,18 @@ module Geocoder
26
30
 
27
31
  private
28
32
 
33
+ def db_class
34
+ gem_name == 'hive_geoip2' ? Hive::GeoIP2 : MaxMindDB
35
+ end
36
+
29
37
  def results(query)
30
38
  return [] unless configuration[:file]
31
- if @gem_name == 'hive_geoip2'
32
- result = Hive::GeoIP2.lookup(query.to_s, configuration[:file].to_s)
33
- else
34
- result = MaxMindDB.new(configuration[:file].to_s).lookup(query.to_s)
39
+
40
+ if @mmdb.respond_to?(:local_ip_alias) && !configuration[:local_ip_alias].nil?
41
+ @mmdb.local_ip_alias = configuration[:local_ip_alias]
35
42
  end
43
+
44
+ result = @mmdb.lookup(query.to_s)
36
45
  result.nil? ? [] : [result]
37
46
  end
38
47
  end
@@ -0,0 +1,65 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/geoportail_lu"
3
+
4
+ module Geocoder
5
+ module Lookup
6
+ class GeoportailLu < Base
7
+
8
+ def name
9
+ "Geoportail.lu"
10
+ end
11
+
12
+ private # ---------------------------------------------------------------
13
+
14
+ def base_query_url(query)
15
+ if query.reverse_geocode?
16
+ reverse_geocode_url_base_path
17
+ else
18
+ search_url_base_path
19
+ end
20
+ end
21
+
22
+ def search_url_base_path
23
+ "#{protocol}://api.geoportail.lu/geocoder/search?"
24
+ end
25
+
26
+ def reverse_geocode_url_base_path
27
+ "#{protocol}://api.geoportail.lu/geocoder/reverseGeocode?"
28
+ end
29
+
30
+ def query_url_geoportail_lu_params(query)
31
+ query.reverse_geocode? ? reverse_geocode_params(query) : search_params(query)
32
+ end
33
+
34
+ def search_params(query)
35
+ {
36
+ queryString: query.sanitized_text
37
+ }
38
+ end
39
+
40
+ def reverse_geocode_params(query)
41
+ lat_lon = query.coordinates
42
+ {
43
+ lat: lat_lon.first,
44
+ lon: lat_lon.last
45
+ }
46
+ end
47
+
48
+ def query_url_params(query)
49
+ query_url_geoportail_lu_params(query).merge(super)
50
+ end
51
+
52
+ def results(query)
53
+ return [] unless doc = fetch_data(query)
54
+ if doc['success'] == true
55
+ result = doc['results']
56
+ else
57
+ result = []
58
+ raise_error(Geocoder::Error) ||
59
+ Geocoder.log(:warn, "Geportail.lu Geocoding API error")
60
+ end
61
+ result
62
+ end
63
+ end
64
+ end
65
+ end
@@ -12,40 +12,70 @@ module Geocoder::Lookup
12
12
  "http://maps.google.com/maps?q=#{coordinates.join(',')}"
13
13
  end
14
14
 
15
- def query_url(query)
16
- "#{protocol}://maps.googleapis.com/maps/api/geocode/json?" + url_query_string(query)
15
+ def supported_protocols
16
+ # Google requires HTTPS if an API key is used.
17
+ if configuration.api_key
18
+ [:https]
19
+ else
20
+ [:http, :https]
21
+ end
17
22
  end
18
23
 
19
24
  private # ---------------------------------------------------------------
20
25
 
26
+ def base_query_url(query)
27
+ "#{protocol}://maps.googleapis.com/maps/api/geocode/json?"
28
+ end
29
+
30
+ def configure_ssl!(client)
31
+ client.instance_eval {
32
+ @ssl_context = OpenSSL::SSL::SSLContext.new
33
+ options = OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3
34
+ if OpenSSL::SSL.const_defined?('OP_NO_COMPRESSION')
35
+ options |= OpenSSL::SSL::OP_NO_COMPRESSION
36
+ end
37
+ @ssl_context.set_params({options: options})
38
+ }
39
+ end
40
+
21
41
  def valid_response?(response)
22
- status = parse_json(response.body)["status"]
42
+ json = parse_json(response.body)
43
+ status = json["status"] if json
23
44
  super(response) and ['OK', 'ZERO_RESULTS'].include?(status)
24
45
  end
25
46
 
47
+ def result_root_attr
48
+ 'results'
49
+ end
50
+
26
51
  def results(query)
27
52
  return [] unless doc = fetch_data(query)
28
- case doc['status']; when "OK" # OK status implies >0 results
29
- return doc['results']
53
+ case doc['status']
54
+ when "OK" # OK status implies >0 results
55
+ return doc[result_root_attr]
30
56
  when "OVER_QUERY_LIMIT"
31
57
  raise_error(Geocoder::OverQueryLimitError) ||
32
- warn("Google Geocoding API error: over query limit.")
58
+ Geocoder.log(:warn, "#{name} API error: over query limit.")
33
59
  when "REQUEST_DENIED"
34
- raise_error(Geocoder::RequestDenied) ||
35
- warn("Google Geocoding API error: request denied.")
60
+ raise_error(Geocoder::RequestDenied, doc['error_message']) ||
61
+ Geocoder.log(:warn, "#{name} API error: request denied (#{doc['error_message']}).")
36
62
  when "INVALID_REQUEST"
37
- raise_error(Geocoder::InvalidRequest) ||
38
- warn("Google Geocoding API error: invalid request.")
63
+ raise_error(Geocoder::InvalidRequest, doc['error_message']) ||
64
+ Geocoder.log(:warn, "#{name} API error: invalid request (#{doc['error_message']}).")
39
65
  end
40
66
  return []
41
67
  end
42
68
 
43
69
  def query_url_google_params(query)
44
70
  params = {
45
- (query.reverse_geocode? ? :latlng : :address) => query.sanitized_text,
46
71
  :sensor => "false",
47
72
  :language => (query.language || configuration.language)
48
73
  }
74
+ if query.options[:google_place_id]
75
+ params[:place_id] = query.sanitized_text
76
+ else
77
+ params[(query.reverse_geocode? ? :latlng : :address)] = query.sanitized_text
78
+ end
49
79
  unless (bounds = query.options[:bounds]).nil?
50
80
  params[:bounds] = bounds.map{ |point| "%f,%f" % point }.join('|')
51
81
  end
@@ -55,6 +85,9 @@ module Geocoder::Lookup
55
85
  unless (components = query.options[:components]).nil?
56
86
  params[:components] = components.is_a?(Array) ? components.join("|") : components
57
87
  end
88
+ unless (result_type = query.options[:result_type]).nil?
89
+ params[:result_type] = result_type.is_a?(Array) ? result_type.join("|") : result_type
90
+ end
58
91
  params
59
92
  end
60
93
 
@@ -12,36 +12,50 @@ module Geocoder
12
12
  ["key"]
13
13
  end
14
14
 
15
- def use_ssl?
16
- true
15
+ def supported_protocols
16
+ [:https]
17
17
  end
18
18
 
19
- def query_url(query)
20
- "#{protocol}://maps.googleapis.com/maps/api/place/details/json?#{url_query_string(query)}"
19
+ private
20
+
21
+ def base_query_url(query)
22
+ "#{protocol}://maps.googleapis.com/maps/api/place/details/json?"
21
23
  end
22
24
 
23
- private
25
+ def result_root_attr
26
+ 'result'
27
+ end
24
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) || warn("Google Places Details API error: over query limit.")
33
- when "REQUEST_DENIED"
34
- raise_error(Geocoder::RequestDenied) || warn("Google Places Details API error: request denied.")
35
- when "INVALID_REQUEST"
36
- raise_error(Geocoder::InvalidRequest) || warn("Google Places Details API error: invalid request.")
30
+ result = super(query)
31
+ return [result] unless result.is_a? Array
32
+
33
+ result
34
+ end
35
+
36
+ def fields(query)
37
+ if query.options.has_key?(:fields)
38
+ return format_fields(query.options[:fields])
39
+ end
40
+
41
+ if configuration.has_key?(:fields)
42
+ return format_fields(configuration[:fields])
37
43
  end
38
44
 
39
- []
45
+ nil # use Google Places defaults
46
+ end
47
+
48
+ def format_fields(*fields)
49
+ flattened = fields.flatten.compact
50
+ return if flattened.empty?
51
+
52
+ flattened.join(',')
40
53
  end
41
54
 
42
55
  def query_url_google_params(query)
43
56
  {
44
57
  placeid: query.text,
58
+ fields: fields(query),
45
59
  language: query.language || configuration.language
46
60
  }
47
61
  end