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,76 @@
1
+ require "geocoder/lookups/google"
2
+ require "geocoder/results/google_places_search"
3
+
4
+ module Geocoder
5
+ module Lookup
6
+ class GooglePlacesSearch < Google
7
+ def name
8
+ "Google Places Search"
9
+ end
10
+
11
+ def required_api_key_parts
12
+ ["key"]
13
+ end
14
+
15
+ def supported_protocols
16
+ [:https]
17
+ end
18
+
19
+ private
20
+
21
+ def result_root_attr
22
+ 'candidates'
23
+ end
24
+
25
+ def base_query_url(query)
26
+ "#{protocol}://maps.googleapis.com/maps/api/place/findplacefromtext/json?"
27
+ end
28
+
29
+ def query_url_google_params(query)
30
+ {
31
+ input: query.text,
32
+ inputtype: 'textquery',
33
+ fields: fields(query),
34
+ locationbias: locationbias(query),
35
+ language: query.language || configuration.language
36
+ }
37
+ end
38
+
39
+ def fields(query)
40
+ if query.options.has_key?(:fields)
41
+ return format_fields(query.options[:fields])
42
+ end
43
+
44
+ if configuration.has_key?(:fields)
45
+ return format_fields(configuration[:fields])
46
+ end
47
+
48
+ default_fields
49
+ end
50
+
51
+ def default_fields
52
+ legacy = %w[id reference]
53
+ basic = %w[business_status formatted_address geometry icon name
54
+ photos place_id plus_code types]
55
+ contact = %w[opening_hours]
56
+ atmosphere = %W[price_level rating user_ratings_total]
57
+ format_fields(legacy, basic, contact, atmosphere)
58
+ end
59
+
60
+ def format_fields(*fields)
61
+ flattened = fields.flatten.compact
62
+ return if flattened.empty?
63
+
64
+ flattened.join(',')
65
+ end
66
+
67
+ def locationbias(query)
68
+ if query.options.has_key?(:locationbias)
69
+ query.options[:locationbias]
70
+ else
71
+ configuration[:locationbias]
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -11,7 +11,7 @@ module Geocoder::Lookup
11
11
  end
12
12
 
13
13
  def required_api_key_parts
14
- ["private key", "client", "channel"]
14
+ ["private key"]
15
15
  end
16
16
 
17
17
  def query_url(query)
@@ -21,6 +21,20 @@ module Geocoder::Lookup
21
21
 
22
22
  private # ---------------------------------------------------------------
23
23
 
24
+ def result_root_attr
25
+ 'results'
26
+ end
27
+
28
+ def cache_key(query)
29
+ "#{protocol}://maps.googleapis.com/maps/api/geocode/json?" + hash_to_query(cache_key_params(query))
30
+ end
31
+
32
+ def cache_key_params(query)
33
+ query_url_google_params(query).merge(super).reject do |k,v|
34
+ [:key, :client, :channel].include?(k)
35
+ end
36
+ end
37
+
24
38
  def query_url_params(query)
25
39
  query_url_google_params(query).merge(super).merge(
26
40
  :key => nil, # don't use param inherited from Google lookup
@@ -9,54 +9,65 @@ module Geocoder::Lookup
9
9
  end
10
10
 
11
11
  def required_api_key_parts
12
- []
12
+ ['api_key']
13
13
  end
14
14
 
15
- def query_url(query)
16
- "#{protocol}://#{if query.reverse_geocode? then 'reverse.' end}geocoder.api.here.com/6.2/#{if query.reverse_geocode? then 'reverse' end}geocode.json?" + url_query_string(query)
15
+ def supported_protocols
16
+ [:https]
17
17
  end
18
18
 
19
19
  private # ---------------------------------------------------------------
20
20
 
21
+ def base_query_url(query)
22
+ service = query.reverse_geocode? ? "revgeocode" : "geocode"
23
+
24
+ "#{protocol}://#{service}.search.hereapi.com/v1/#{service}?"
25
+ end
26
+
21
27
  def results(query)
22
- return [] unless doc = fetch_data(query)
23
- return [] unless doc['Response'] && doc['Response']['View']
24
- if r=doc['Response']['View']
25
- return [] if r.nil? || !r.is_a?(Array) || r.empty?
26
- return r.first['Result']
28
+ unless configuration.api_key.is_a?(String)
29
+ api_key_not_string!
30
+ return []
27
31
  end
28
- []
32
+ return [] unless doc = fetch_data(query)
33
+ return [] if doc["items"].nil?
34
+
35
+ doc["items"]
29
36
  end
30
37
 
31
- def query_url_params(query)
38
+ def query_url_here_options(query, reverse_geocode)
32
39
  options = {
33
- :gen=>4,
34
- :app_id=>api_key,
35
- :app_code=>api_code
40
+ apiKey: configuration.api_key,
41
+ lang: (query.language || configuration.language)
36
42
  }
43
+ return options if reverse_geocode
37
44
 
45
+ unless (country = query.options[:country]).nil?
46
+ options[:in] = "countryCode:#{country}"
47
+ end
48
+
49
+ options
50
+ end
51
+
52
+ def query_url_params(query)
38
53
  if query.reverse_geocode?
39
- super.merge(options).merge(
40
- :prox=>query.sanitized_text,
41
- :mode=>:retrieveAddresses
54
+ super.merge(query_url_here_options(query, true)).merge(
55
+ at: query.sanitized_text
42
56
  )
43
57
  else
44
- super.merge(options).merge(
45
- :searchtext=>query.sanitized_text
58
+ super.merge(query_url_here_options(query, false)).merge(
59
+ q: query.sanitized_text
46
60
  )
47
61
  end
48
62
  end
49
63
 
50
- def api_key
51
- if a=configuration.api_key
52
- return a.first if a.is_a?(Array)
53
- end
54
- end
64
+ def api_key_not_string!
65
+ msg = <<~MSG
66
+ API key for HERE Geocoding and Search API should be a string.
67
+ For more info on how to obtain it, please see https://developer.here.com/documentation/identity-access-management/dev_guide/topics/plat-using-apikeys.html
68
+ MSG
55
69
 
56
- def api_code
57
- if a=configuration.api_key
58
- return a.last if a.is_a?(Array)
59
- end
70
+ raise_error(Geocoder::ConfigurationError, msg) || Geocoder.log(:warn, msg)
60
71
  end
61
72
  end
62
73
  end
@@ -0,0 +1,71 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/ip2location'
3
+
4
+ module Geocoder::Lookup
5
+ class Ip2location < Base
6
+
7
+ def name
8
+ "IP2LocationApi"
9
+ end
10
+
11
+ def required_api_key_parts
12
+ ['key']
13
+ end
14
+
15
+ def supported_protocols
16
+ [:http, :https]
17
+ end
18
+
19
+ private # ----------------------------------------------------------------
20
+
21
+ def base_query_url(query)
22
+ "#{protocol}://api.ip2location.com/v2/?"
23
+ end
24
+
25
+ def query_url_params(query)
26
+ super.merge(
27
+ key: configuration.api_key,
28
+ ip: query.sanitized_text,
29
+ package: configuration[:package],
30
+ )
31
+ end
32
+
33
+ def results(query)
34
+ # don't look up a loopback or private address, just return the stored result
35
+ return [reserved_result(query.text)] if query.internal_ip_address?
36
+ return [] unless doc = fetch_data(query)
37
+ if doc["response"] == "INVALID ACCOUNT"
38
+ raise_error(Geocoder::InvalidApiKey) || Geocoder.log(:warn, "INVALID ACCOUNT")
39
+ return []
40
+ else
41
+ return [doc]
42
+ end
43
+ end
44
+
45
+ def reserved_result(query)
46
+ {
47
+ "country_code" => "INVALID IP ADDRESS",
48
+ "country_name" => "INVALID IP ADDRESS",
49
+ "region_name" => "INVALID IP ADDRESS",
50
+ "city_name" => "INVALID IP ADDRESS",
51
+ "latitude" => "INVALID IP ADDRESS",
52
+ "longitude" => "INVALID IP ADDRESS",
53
+ "zip_code" => "INVALID IP ADDRESS",
54
+ "time_zone" => "INVALID IP ADDRESS",
55
+ "isp" => "INVALID IP ADDRESS",
56
+ "domain" => "INVALID IP ADDRESS",
57
+ "net_speed" => "INVALID IP ADDRESS",
58
+ "idd_code" => "INVALID IP ADDRESS",
59
+ "area_code" => "INVALID IP ADDRESS",
60
+ "weather_station_code" => "INVALID IP ADDRESS",
61
+ "weather_station_name" => "INVALID IP ADDRESS",
62
+ "mcc" => "INVALID IP ADDRESS",
63
+ "mnc" => "INVALID IP ADDRESS",
64
+ "mobile_brand" => "INVALID IP ADDRESS",
65
+ "elevation" => "INVALID IP ADDRESS",
66
+ "usage_type" => "INVALID IP ADDRESS"
67
+ }
68
+ end
69
+
70
+ end
71
+ end
@@ -0,0 +1,82 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/ipapi_com'
3
+
4
+ module Geocoder::Lookup
5
+ class IpapiCom < Base
6
+
7
+ def name
8
+ "ip-api.com"
9
+ end
10
+
11
+ def supported_protocols
12
+ if configuration.api_key
13
+ [:http, :https]
14
+ else
15
+ [:http]
16
+ end
17
+ end
18
+
19
+ private # ----------------------------------------------------------------
20
+
21
+ def base_query_url(query)
22
+ domain = configuration.api_key ? "pro.ip-api.com" : "ip-api.com"
23
+ url = "#{protocol}://#{domain}/json/#{query.sanitized_text}"
24
+ url << "?" if not url_query_string(query).empty?
25
+ url
26
+ end
27
+
28
+ def parse_raw_data(raw_data)
29
+ if raw_data.chomp == "invalid key"
30
+ invalid_key_result
31
+ else
32
+ super(raw_data)
33
+ end
34
+ end
35
+
36
+ def results(query)
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?
39
+
40
+ return [] unless doc = fetch_data(query)
41
+
42
+ if doc["message"] == "invalid key"
43
+ raise_error(Geocoder::InvalidApiKey) || Geocoder.log(:warn, "Invalid API key.")
44
+ return []
45
+ else
46
+ return [doc]
47
+ end
48
+ end
49
+
50
+ def reserved_result(query)
51
+ {
52
+ "message" => "reserved range",
53
+ "query" => query,
54
+ "status" => "fail",
55
+ "ip" => query,
56
+ "city" => "",
57
+ "region_code" => "",
58
+ "region_name" => "",
59
+ "metrocode" => "",
60
+ "zipcode" => "",
61
+ "latitude" => "0",
62
+ "longitude" => "0",
63
+ "country_name" => "Reserved",
64
+ "country_code" => "RD"
65
+ }
66
+ end
67
+
68
+ def invalid_key_result
69
+ {
70
+ "message" => "invalid key"
71
+ }
72
+ end
73
+
74
+ def query_url_params(query)
75
+ params = {}
76
+ params.merge!(fields: configuration[:fields]) if configuration.has_key?(:fields)
77
+ params.merge!(key: configuration.api_key) if configuration.api_key
78
+ params.merge(super)
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,49 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/ipbase'
3
+
4
+ module Geocoder::Lookup
5
+ class Ipbase < Base
6
+
7
+ def name
8
+ "ipbase.com"
9
+ end
10
+
11
+ def supported_protocols
12
+ [:https]
13
+ end
14
+
15
+ private # ---------------------------------------------------------------
16
+
17
+ def base_query_url(query)
18
+ "https://api.ipbase.com/v2/info?"
19
+ end
20
+
21
+ def query_url_params(query)
22
+ {
23
+ :ip => query.sanitized_text,
24
+ :apikey => configuration.api_key
25
+ }
26
+ end
27
+
28
+ def results(query)
29
+ # don't look up a loopback or private address, just return the stored result
30
+ return [reserved_result(query.text)] if query.internal_ip_address?
31
+ doc = fetch_data(query) || {}
32
+ doc.fetch("data", {})["location"] ? [doc] : []
33
+ end
34
+
35
+ def reserved_result(ip)
36
+ {
37
+ "data" => {
38
+ "ip" => ip,
39
+ "location" => {
40
+ "city" => { "name" => "" },
41
+ "country" => { "alpha2" => "RD", "name" => "Reserved" },
42
+ "region" => { "alpha2" => "", "name" => "" },
43
+ "zip" => ""
44
+ }
45
+ }
46
+ }
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,62 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/ipdata_co'
3
+
4
+ module Geocoder::Lookup
5
+ class IpdataCo < Base
6
+
7
+ def name
8
+ "ipdata.co"
9
+ end
10
+
11
+ def supported_protocols
12
+ [:https]
13
+ end
14
+
15
+ def query_url(query)
16
+ # Ipdata.co requires that the API key be sent as a query parameter.
17
+ # It no longer supports API keys sent as headers.
18
+ "#{protocol}://#{host}/#{query.sanitized_text}?api-key=#{configuration.api_key}"
19
+ end
20
+
21
+ private # ---------------------------------------------------------------
22
+
23
+ def cache_key(query)
24
+ query_url(query)
25
+ end
26
+
27
+ def results(query)
28
+ # don't look up a loopback or private address, just return the stored result
29
+ return [reserved_result(query.text)] if query.internal_ip_address?
30
+ # note: Ipdata.co returns plain text on bad request
31
+ (doc = fetch_data(query)) ? [doc] : []
32
+ end
33
+
34
+ def reserved_result(ip)
35
+ {
36
+ "ip" => ip,
37
+ "city" => "",
38
+ "region_code" => "",
39
+ "region_name" => "",
40
+ "metrocode" => "",
41
+ "zipcode" => "",
42
+ "latitude" => "0",
43
+ "longitude" => "0",
44
+ "country_name" => "Reserved",
45
+ "country_code" => "RD"
46
+ }
47
+ end
48
+
49
+ def host
50
+ configuration[:host] || "api.ipdata.co"
51
+ end
52
+
53
+ def check_response_for_errors!(response)
54
+ if response.code.to_i == 403
55
+ raise_error(Geocoder::RequestDenied) ||
56
+ Geocoder.log(:warn, "Geocoding API error: 403 API key does not exist")
57
+ else
58
+ super(response)
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,51 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/ipgeolocation'
3
+
4
+
5
+ module Geocoder::Lookup
6
+ class Ipgeolocation < Base
7
+
8
+ ERROR_CODES = {
9
+ 400 => Geocoder::RequestDenied, # subscription is paused
10
+ 401 => Geocoder::InvalidApiKey, # missing/invalid API key
11
+ 403 => Geocoder::InvalidRequest, # invalid IP address
12
+ 404 => Geocoder::InvalidRequest, # not found
13
+ 423 => Geocoder::InvalidRequest # bogon/reserved IP address
14
+ }
15
+ ERROR_CODES.default = Geocoder::Error
16
+
17
+ def name
18
+ "Ipgeolocation"
19
+ end
20
+
21
+ def supported_protocols
22
+ [:https]
23
+ end
24
+
25
+ private # ----------------------------------------------------------------
26
+
27
+ def base_query_url(query)
28
+ "#{protocol}://api.ipgeolocation.io/ipgeo?"
29
+ end
30
+ def query_url_params(query)
31
+ {
32
+ ip: query.sanitized_text,
33
+ apiKey: configuration.api_key
34
+ }.merge(super)
35
+ end
36
+
37
+ def results(query)
38
+ # don't look up a loopback or private address, just return the stored result
39
+ return [reserved_result(query.text)] if query.internal_ip_address?
40
+ [fetch_data(query)]
41
+ end
42
+
43
+ def reserved_result(ip)
44
+ {
45
+ "ip" => ip,
46
+ "country_name" => "Reserved",
47
+ "country_code2" => "RD"
48
+ }
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,44 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/ipinfo_io'
3
+
4
+ module Geocoder::Lookup
5
+ class IpinfoIo < Base
6
+
7
+ def name
8
+ "Ipinfo.io"
9
+ end
10
+
11
+ private # ---------------------------------------------------------------
12
+
13
+ def base_query_url(query)
14
+ url = "#{protocol}://ipinfo.io/#{query.sanitized_text}/geo"
15
+ url << "?" if configuration.api_key
16
+ url
17
+ end
18
+
19
+ def results(query)
20
+ # don't look up a loopback or private address, just return the stored result
21
+ return [reserved_result(query.text)] if query.internal_ip_address?
22
+
23
+ if !(doc = fetch_data(query)).is_a?(Hash) or doc['error']
24
+ []
25
+ else
26
+ [doc]
27
+ end
28
+ end
29
+
30
+ def reserved_result(ip)
31
+ {
32
+ "ip" => ip,
33
+ "bogon" => true
34
+ }
35
+ end
36
+
37
+ def query_url_params(query)
38
+ {
39
+ token: configuration.api_key
40
+ }.merge(super)
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ require 'geocoder/lookups/base'
4
+ require 'geocoder/results/ipqualityscore'
5
+
6
+ module Geocoder::Lookup
7
+ class Ipqualityscore < Base
8
+
9
+ def name
10
+ "IPQualityScore"
11
+ end
12
+
13
+ def required_api_key_parts
14
+ ['api_key']
15
+ end
16
+
17
+ private # ---------------------------------------------------------------
18
+
19
+ def base_query_url(query)
20
+ "#{protocol}://ipqualityscore.com/api/json/ip/#{configuration.api_key}/#{query.sanitized_text}?"
21
+ end
22
+
23
+ def valid_response?(response)
24
+ if (json = parse_json(response.body))
25
+ success = json['success']
26
+ end
27
+ super && success == true
28
+ end
29
+
30
+ def results(query, reverse = false)
31
+ return [] unless doc = fetch_data(query)
32
+
33
+ return [doc] if doc['success']
34
+
35
+ case doc['message']
36
+ when /invalid (.*) key/i
37
+ raise_error Geocoder::InvalidApiKey ||
38
+ Geocoder.log(:warn, "#{name} API error: invalid api key.")
39
+ when /insufficient credits/, /exceeded your request quota/
40
+ raise_error Geocoder::OverQueryLimitError ||
41
+ Geocoder.log(:warn, "#{name} API error: query limit exceeded.")
42
+ when /invalid (.*) address/i
43
+ raise_error Geocoder::InvalidRequest ||
44
+ Geocoder.log(:warn, "#{name} API error: invalid request.")
45
+ end
46
+
47
+ [doc]
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,68 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/ipregistry'
3
+
4
+ module Geocoder::Lookup
5
+ class Ipregistry < Base
6
+
7
+ ERROR_CODES = {
8
+ 400 => Geocoder::InvalidRequest,
9
+ 401 => Geocoder::InvalidRequest,
10
+ 402 => Geocoder::OverQueryLimitError,
11
+ 403 => Geocoder::InvalidApiKey,
12
+ 451 => Geocoder::RequestDenied,
13
+ 500 => Geocoder::Error
14
+ }
15
+ ERROR_CODES.default = Geocoder::Error
16
+
17
+ def name
18
+ "Ipregistry"
19
+ end
20
+
21
+ def supported_protocols
22
+ [:https, :http]
23
+ end
24
+
25
+ private
26
+
27
+ def base_query_url(query)
28
+ "#{protocol}://#{host}/#{query.sanitized_text}?"
29
+ end
30
+
31
+ def cache_key(query)
32
+ query_url(query)
33
+ end
34
+
35
+ def host
36
+ configuration[:host] || "api.ipregistry.co"
37
+ end
38
+
39
+ def query_url_params(query)
40
+ {
41
+ key: configuration.api_key
42
+ }.merge(super)
43
+ end
44
+
45
+ def results(query)
46
+ # don't look up a loopback or private address, just return the stored result
47
+ return [reserved_result(query.text)] if query.internal_ip_address?
48
+
49
+ return [] unless (doc = fetch_data(query))
50
+
51
+ if (error = doc['error'])
52
+ code = error['code']
53
+ msg = error['message']
54
+ raise_error(ERROR_CODES[code], msg ) || Geocoder.log(:warn, "Ipregistry API error: #{msg}")
55
+ return []
56
+ end
57
+ [doc]
58
+ end
59
+
60
+ def reserved_result(ip)
61
+ {
62
+ "ip" => ip,
63
+ "country_name" => "Reserved",
64
+ "country_code" => "RD"
65
+ }
66
+ end
67
+ end
68
+ end