geocoder 1.2.6 → 1.6.1

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 (276) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +189 -1
  3. data/LICENSE +1 -1
  4. data/README.md +387 -755
  5. data/examples/autoexpire_cache_redis.rb +5 -3
  6. data/examples/reverse_geocode_job.rb +40 -0
  7. data/lib/generators/geocoder/config/templates/initializer.rb +17 -16
  8. data/lib/generators/geocoder/maxmind/geolite_city_generator.rb +2 -0
  9. data/lib/generators/geocoder/maxmind/geolite_country_generator.rb +2 -0
  10. data/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb +1 -1
  11. data/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb +1 -1
  12. data/lib/generators/geocoder/migration_version.rb +15 -0
  13. data/lib/geocoder/cache.rb +6 -2
  14. data/lib/geocoder/calculations.rb +30 -38
  15. data/lib/geocoder/cli.rb +2 -2
  16. data/lib/geocoder/configuration.rb +18 -5
  17. data/lib/geocoder/esri_token.rb +38 -0
  18. data/lib/geocoder/exceptions.rb +19 -0
  19. data/lib/geocoder/ip_address.rb +16 -11
  20. data/lib/geocoder/kernel_logger.rb +25 -0
  21. data/lib/geocoder/logger.rb +47 -0
  22. data/lib/geocoder/lookup.rb +31 -12
  23. data/lib/geocoder/lookups/amap.rb +63 -0
  24. data/lib/geocoder/lookups/baidu.rb +17 -9
  25. data/lib/geocoder/lookups/baidu_ip.rb +7 -31
  26. data/lib/geocoder/lookups/ban_data_gouv_fr.rb +143 -0
  27. data/lib/geocoder/lookups/base.rb +73 -25
  28. data/lib/geocoder/lookups/bing.rb +38 -15
  29. data/lib/geocoder/lookups/db_ip_com.rb +52 -0
  30. data/lib/geocoder/lookups/dstk.rb +4 -2
  31. data/lib/geocoder/lookups/esri.rb +55 -8
  32. data/lib/geocoder/lookups/freegeoip.rb +18 -5
  33. data/lib/geocoder/lookups/geocoder_ca.rb +5 -6
  34. data/lib/geocoder/lookups/geocodio.rb +8 -8
  35. data/lib/geocoder/lookups/geoip2.rb +10 -5
  36. data/lib/geocoder/lookups/geoportail_lu.rb +65 -0
  37. data/lib/geocoder/lookups/google.rb +37 -9
  38. data/lib/geocoder/lookups/google_places_details.rb +9 -9
  39. data/lib/geocoder/lookups/google_places_search.rb +33 -0
  40. data/lib/geocoder/lookups/google_premier.rb +11 -1
  41. data/lib/geocoder/lookups/here.rb +29 -23
  42. data/lib/geocoder/lookups/ip2location.rb +67 -0
  43. data/lib/geocoder/lookups/ipapi_com.rb +82 -0
  44. data/lib/geocoder/lookups/ipdata_co.rb +62 -0
  45. data/lib/geocoder/lookups/ipgeolocation.rb +51 -0
  46. data/lib/geocoder/lookups/ipinfo_io.rb +44 -0
  47. data/lib/geocoder/lookups/ipregistry.rb +68 -0
  48. data/lib/geocoder/lookups/ipstack.rb +63 -0
  49. data/lib/geocoder/lookups/latlon.rb +59 -0
  50. data/lib/geocoder/lookups/location_iq.rb +50 -0
  51. data/lib/geocoder/lookups/mapbox.rb +59 -0
  52. data/lib/geocoder/lookups/mapquest.rb +7 -9
  53. data/lib/geocoder/lookups/maxmind.rb +7 -7
  54. data/lib/geocoder/lookups/maxmind_geoip2.rb +70 -0
  55. data/lib/geocoder/lookups/maxmind_local.rb +9 -2
  56. data/lib/geocoder/lookups/nominatim.rb +18 -6
  57. data/lib/geocoder/lookups/opencagedata.rb +16 -9
  58. data/lib/geocoder/lookups/osmnames.rb +57 -0
  59. data/lib/geocoder/lookups/pelias.rb +63 -0
  60. data/lib/geocoder/lookups/pickpoint.rb +41 -0
  61. data/lib/geocoder/lookups/pointpin.rb +14 -13
  62. data/lib/geocoder/lookups/postcode_anywhere_uk.rb +7 -8
  63. data/lib/geocoder/lookups/postcodes_io.rb +31 -0
  64. data/lib/geocoder/lookups/smarty_streets.rb +23 -5
  65. data/lib/geocoder/lookups/telize.rb +42 -7
  66. data/lib/geocoder/lookups/tencent.rb +59 -0
  67. data/lib/geocoder/lookups/yandex.rb +17 -9
  68. data/lib/geocoder/models/active_record.rb +4 -3
  69. data/lib/geocoder/models/mongo_base.rb +0 -2
  70. data/lib/geocoder/query.rb +15 -1
  71. data/lib/geocoder/railtie.rb +1 -1
  72. data/lib/geocoder/request.rb +103 -14
  73. data/lib/geocoder/results/amap.rb +87 -0
  74. data/lib/geocoder/results/baidu.rb +10 -14
  75. data/lib/geocoder/results/ban_data_gouv_fr.rb +257 -0
  76. data/lib/geocoder/results/base.rb +13 -1
  77. data/lib/geocoder/results/bing.rb +5 -1
  78. data/lib/geocoder/results/db_ip_com.rb +58 -0
  79. data/lib/geocoder/results/esri.rb +30 -6
  80. data/lib/geocoder/results/freegeoip.rb +2 -7
  81. data/lib/geocoder/results/geocoder_ca.rb +3 -3
  82. data/lib/geocoder/results/geocodio.rb +15 -3
  83. data/lib/geocoder/results/geoip2.rb +37 -25
  84. data/lib/geocoder/results/geoportail_lu.rb +71 -0
  85. data/lib/geocoder/results/google.rb +26 -0
  86. data/lib/geocoder/results/google_places_details.rb +4 -0
  87. data/lib/geocoder/results/google_places_search.rb +52 -0
  88. data/lib/geocoder/results/here.rb +21 -1
  89. data/lib/geocoder/results/ip2location.rb +22 -0
  90. data/lib/geocoder/results/ipapi_com.rb +45 -0
  91. data/lib/geocoder/results/ipdata_co.rb +40 -0
  92. data/lib/geocoder/results/ipgeolocation.rb +59 -0
  93. data/lib/geocoder/results/ipinfo_io.rb +48 -0
  94. data/lib/geocoder/results/ipregistry.rb +308 -0
  95. data/lib/geocoder/results/ipstack.rb +60 -0
  96. data/lib/geocoder/results/latlon.rb +71 -0
  97. data/lib/geocoder/results/location_iq.rb +6 -0
  98. data/lib/geocoder/results/mapbox.rb +57 -0
  99. data/lib/geocoder/results/mapquest.rb +5 -8
  100. data/lib/geocoder/results/maxmind.rb +0 -5
  101. data/lib/geocoder/results/maxmind_geoip2.rb +9 -0
  102. data/lib/geocoder/results/maxmind_local.rb +0 -5
  103. data/lib/geocoder/results/nominatim.rb +18 -3
  104. data/lib/geocoder/results/opencagedata.rb +20 -2
  105. data/lib/geocoder/results/osmnames.rb +56 -0
  106. data/lib/geocoder/results/pelias.rb +58 -0
  107. data/lib/geocoder/results/pickpoint.rb +6 -0
  108. data/lib/geocoder/results/pointpin.rb +0 -4
  109. data/lib/geocoder/results/postcodes_io.rb +40 -0
  110. data/lib/geocoder/results/smarty_streets.rb +55 -19
  111. data/lib/geocoder/results/telize.rb +0 -5
  112. data/lib/geocoder/results/tencent.rb +72 -0
  113. data/lib/geocoder/results/test.rb +1 -1
  114. data/lib/geocoder/results/yandex.rb +57 -7
  115. data/lib/geocoder/sql.rb +9 -6
  116. data/lib/geocoder/stores/active_record.rb +49 -10
  117. data/lib/geocoder/stores/base.rb +2 -14
  118. data/lib/geocoder/stores/mongo_base.rb +0 -31
  119. data/lib/geocoder/version.rb +1 -1
  120. data/lib/geocoder.rb +2 -1
  121. data/lib/hash_recursive_merge.rb +1 -2
  122. data/lib/maxmind_database.rb +4 -4
  123. data/lib/tasks/geocoder.rake +29 -4
  124. metadata +56 -159
  125. data/.gitignore +0 -6
  126. data/.travis.yml +0 -31
  127. data/Rakefile +0 -25
  128. data/gemfiles/Gemfile.mongoid-2.4.x +0 -16
  129. data/lib/geocoder/lookups/geocoder_us.rb +0 -39
  130. data/lib/geocoder/lookups/okf.rb +0 -43
  131. data/lib/geocoder/lookups/ovi.rb +0 -62
  132. data/lib/geocoder/lookups/yahoo.rb +0 -88
  133. data/lib/geocoder/results/geocoder_us.rb +0 -39
  134. data/lib/geocoder/results/okf.rb +0 -106
  135. data/lib/geocoder/results/ovi.rb +0 -62
  136. data/lib/geocoder/results/yahoo.rb +0 -55
  137. data/lib/oauth_util.rb +0 -112
  138. data/test/fixtures/baidu_invalid_key +0 -1
  139. data/test/fixtures/baidu_ip_202_198_16_3 +0 -19
  140. data/test/fixtures/baidu_ip_invalid_key +0 -1
  141. data/test/fixtures/baidu_ip_no_results +0 -1
  142. data/test/fixtures/baidu_no_results +0 -1
  143. data/test/fixtures/baidu_reverse +0 -1
  144. data/test/fixtures/baidu_shanghai_pearl_tower +0 -12
  145. data/test/fixtures/bing_invalid_key +0 -1
  146. data/test/fixtures/bing_madison_square_garden +0 -40
  147. data/test/fixtures/bing_no_results +0 -16
  148. data/test/fixtures/bing_reverse +0 -42
  149. data/test/fixtures/cloudmade_invalid_key +0 -1
  150. data/test/fixtures/cloudmade_madison_square_garden +0 -1
  151. data/test/fixtures/cloudmade_no_results +0 -1
  152. data/test/fixtures/esri_madison_square_garden +0 -59
  153. data/test/fixtures/esri_no_results +0 -8
  154. data/test/fixtures/esri_reverse +0 -21
  155. data/test/fixtures/freegeoip_74_200_247_59 +0 -12
  156. data/test/fixtures/freegeoip_no_results +0 -1
  157. data/test/fixtures/geocoder_ca_madison_square_garden +0 -1
  158. data/test/fixtures/geocoder_ca_no_results +0 -1
  159. data/test/fixtures/geocoder_ca_reverse +0 -34
  160. data/test/fixtures/geocoder_us_madison_square_garden +0 -1
  161. data/test/fixtures/geocoder_us_no_results +0 -1
  162. data/test/fixtures/geocodio_1101_pennsylvania_ave +0 -1
  163. data/test/fixtures/geocodio_bad_api_key +0 -3
  164. data/test/fixtures/geocodio_invalid +0 -4
  165. data/test/fixtures/geocodio_no_results +0 -1
  166. data/test/fixtures/geocodio_over_query_limit +0 -4
  167. data/test/fixtures/google_garbage +0 -456
  168. data/test/fixtures/google_madison_square_garden +0 -57
  169. data/test/fixtures/google_no_city_data +0 -44
  170. data/test/fixtures/google_no_locality +0 -51
  171. data/test/fixtures/google_no_results +0 -4
  172. data/test/fixtures/google_over_limit +0 -4
  173. data/test/fixtures/google_places_details_invalid_request +0 -4
  174. data/test/fixtures/google_places_details_madison_square_garden +0 -120
  175. data/test/fixtures/google_places_details_no_results +0 -4
  176. data/test/fixtures/google_places_details_no_reviews +0 -60
  177. data/test/fixtures/google_places_details_no_types +0 -66
  178. data/test/fixtures/here_madison_square_garden +0 -72
  179. data/test/fixtures/here_no_results +0 -8
  180. data/test/fixtures/mapquest_error +0 -16
  181. data/test/fixtures/mapquest_invalid_api_key +0 -16
  182. data/test/fixtures/mapquest_invalid_request +0 -16
  183. data/test/fixtures/mapquest_madison_square_garden +0 -52
  184. data/test/fixtures/mapquest_no_results +0 -16
  185. data/test/fixtures/maxmind_24_24_24_21 +0 -1
  186. data/test/fixtures/maxmind_24_24_24_22 +0 -1
  187. data/test/fixtures/maxmind_24_24_24_23 +0 -1
  188. data/test/fixtures/maxmind_24_24_24_24 +0 -1
  189. data/test/fixtures/maxmind_74_200_247_59 +0 -1
  190. data/test/fixtures/maxmind_invalid_key +0 -1
  191. data/test/fixtures/maxmind_no_results +0 -1
  192. data/test/fixtures/nominatim_madison_square_garden +0 -150
  193. data/test/fixtures/nominatim_no_results +0 -1
  194. data/test/fixtures/nominatim_over_limit +0 -1
  195. data/test/fixtures/okf_kirstinmaki +0 -67
  196. data/test/fixtures/okf_no_results +0 -4
  197. data/test/fixtures/opencagedata_invalid_api_key +0 -25
  198. data/test/fixtures/opencagedata_invalid_request +0 -26
  199. data/test/fixtures/opencagedata_madison_square_garden +0 -73
  200. data/test/fixtures/opencagedata_no_results +0 -29
  201. data/test/fixtures/opencagedata_over_limit +0 -31
  202. data/test/fixtures/ovi_madison_square_garden +0 -72
  203. data/test/fixtures/ovi_no_results +0 -8
  204. data/test/fixtures/pointpin_10_10_10_10 +0 -1
  205. data/test/fixtures/pointpin_555_555_555_555 +0 -1
  206. data/test/fixtures/pointpin_80_111_555_555 +0 -1
  207. data/test/fixtures/pointpin_no_results +0 -1
  208. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_WR26NJ +0 -1
  209. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_generic_error +0 -1
  210. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_hampshire +0 -1
  211. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_key_limit_exceeded +0 -1
  212. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_no_results +0 -1
  213. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_romsey +0 -1
  214. data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_unknown_key +0 -1
  215. data/test/fixtures/smarty_streets_11211 +0 -1
  216. data/test/fixtures/smarty_streets_madison_square_garden +0 -47
  217. data/test/fixtures/smarty_streets_no_results +0 -1
  218. data/test/fixtures/telize_10_10_10_10 +0 -1
  219. data/test/fixtures/telize_555_555_555_555 +0 -4
  220. data/test/fixtures/telize_74_200_247_59 +0 -1
  221. data/test/fixtures/telize_no_results +0 -1
  222. data/test/fixtures/yahoo_error +0 -1
  223. data/test/fixtures/yahoo_invalid_key +0 -2
  224. data/test/fixtures/yahoo_madison_square_garden +0 -52
  225. data/test/fixtures/yahoo_no_results +0 -10
  226. data/test/fixtures/yahoo_over_limit +0 -2
  227. data/test/fixtures/yandex_canada_rue_dupuis_14 +0 -446
  228. data/test/fixtures/yandex_invalid_key +0 -1
  229. data/test/fixtures/yandex_kremlin +0 -48
  230. data/test/fixtures/yandex_new_york +0 -1
  231. data/test/fixtures/yandex_no_city_and_town +0 -112
  232. data/test/fixtures/yandex_no_results +0 -16
  233. data/test/integration/http_client_test.rb +0 -31
  234. data/test/mongoid_test_helper.rb +0 -43
  235. data/test/test_helper.rb +0 -416
  236. data/test/unit/active_record_test.rb +0 -16
  237. data/test/unit/cache_test.rb +0 -37
  238. data/test/unit/calculations_test.rb +0 -220
  239. data/test/unit/configuration_test.rb +0 -55
  240. data/test/unit/error_handling_test.rb +0 -56
  241. data/test/unit/geocoder_test.rb +0 -78
  242. data/test/unit/https_test.rb +0 -17
  243. data/test/unit/ip_address_test.rb +0 -27
  244. data/test/unit/lookup_test.rb +0 -153
  245. data/test/unit/lookups/bing_test.rb +0 -68
  246. data/test/unit/lookups/dstk_test.rb +0 -26
  247. data/test/unit/lookups/esri_test.rb +0 -48
  248. data/test/unit/lookups/freegeoip_test.rb +0 -27
  249. data/test/unit/lookups/geocoder_ca_test.rb +0 -17
  250. data/test/unit/lookups/geocodio_test.rb +0 -55
  251. data/test/unit/lookups/geoip2_test.rb +0 -27
  252. data/test/unit/lookups/google_places_details_test.rb +0 -122
  253. data/test/unit/lookups/google_premier_test.rb +0 -22
  254. data/test/unit/lookups/google_test.rb +0 -84
  255. data/test/unit/lookups/mapquest_test.rb +0 -60
  256. data/test/unit/lookups/maxmind_local_test.rb +0 -28
  257. data/test/unit/lookups/maxmind_test.rb +0 -63
  258. data/test/unit/lookups/nominatim_test.rb +0 -31
  259. data/test/unit/lookups/okf_test.rb +0 -38
  260. data/test/unit/lookups/opencagedata_test.rb +0 -64
  261. data/test/unit/lookups/pointpin_test.rb +0 -30
  262. data/test/unit/lookups/postcode_anywhere_uk_test.rb +0 -70
  263. data/test/unit/lookups/smarty_streets_test.rb +0 -71
  264. data/test/unit/lookups/telize_test.rb +0 -36
  265. data/test/unit/lookups/yahoo_test.rb +0 -35
  266. data/test/unit/method_aliases_test.rb +0 -26
  267. data/test/unit/model_test.rb +0 -38
  268. data/test/unit/mongoid_test.rb +0 -47
  269. data/test/unit/near_test.rb +0 -87
  270. data/test/unit/oauth_util_test.rb +0 -31
  271. data/test/unit/proxy_test.rb +0 -37
  272. data/test/unit/query_test.rb +0 -52
  273. data/test/unit/rake_task_test.rb +0 -21
  274. data/test/unit/request_test.rb +0 -35
  275. data/test/unit/result_test.rb +0 -72
  276. data/test/unit/test_mode_test.rb +0 -70
@@ -1,3 +1,5 @@
1
+ require "geocoder/lookups/test"
2
+
1
3
  module Geocoder
2
4
  module Lookup
3
5
  extend self
@@ -20,28 +22,36 @@ module Geocoder
20
22
  # All street address lookup services, default first.
21
23
  #
22
24
  def street_services
23
- [
25
+ @street_services ||= [
26
+ :location_iq,
24
27
  :dstk,
25
28
  :esri,
26
29
  :google,
27
30
  :google_premier,
28
31
  :google_places_details,
29
- :yahoo,
32
+ :google_places_search,
30
33
  :bing,
31
34
  :geocoder_ca,
32
- :geocoder_us,
33
35
  :yandex,
34
36
  :nominatim,
37
+ :mapbox,
35
38
  :mapquest,
36
39
  :opencagedata,
37
- :ovi,
40
+ :pelias,
41
+ :pickpoint,
38
42
  :here,
39
43
  :baidu,
44
+ :tencent,
40
45
  :geocodio,
41
46
  :smarty_streets,
42
- :okf,
43
47
  :postcode_anywhere_uk,
44
- :test
48
+ :postcodes_io,
49
+ :geoportail_lu,
50
+ :ban_data_gouv_fr,
51
+ :test,
52
+ :latlon,
53
+ :amap,
54
+ :osmnames
45
55
  ]
46
56
  end
47
57
 
@@ -49,17 +59,28 @@ module Geocoder
49
59
  # All IP address lookup services, default first.
50
60
  #
51
61
  def ip_services
52
- [
62
+ @ip_services ||= [
53
63
  :baidu_ip,
54
64
  :freegeoip,
55
65
  :geoip2,
56
66
  :maxmind,
57
67
  :maxmind_local,
58
68
  :telize,
59
- :pointpin
69
+ :pointpin,
70
+ :maxmind_geoip2,
71
+ :ipinfo_io,
72
+ :ipregistry,
73
+ :ipapi_com,
74
+ :ipdata_co,
75
+ :db_ip_com,
76
+ :ipstack,
77
+ :ip2location,
78
+ :ipgeolocation
60
79
  ]
61
80
  end
62
81
 
82
+ attr_writer :street_services, :ip_services
83
+
63
84
  ##
64
85
  # Retrieve a Lookup object from the store.
65
86
  # Use this instead of Geocoder::Lookup::X.new to get an
@@ -79,6 +100,8 @@ module Geocoder
79
100
  #
80
101
  def spawn(name)
81
102
  if all_services.include?(name)
103
+ name = name.to_s
104
+ require "geocoder/lookups/#{name}"
82
105
  Geocoder::Lookup.const_get(classify_name(name)).new
83
106
  else
84
107
  valids = all_services.map(&:inspect).join(", ")
@@ -95,7 +118,3 @@ module Geocoder
95
118
  end
96
119
  end
97
120
  end
98
-
99
- Geocoder::Lookup.all_services.each do |name|
100
- require "geocoder/lookups/#{name}"
101
- 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
+ warn("#{self.name} Geocoding API error: invalid api key.")
36
+ else
37
+ raise_error(Geocoder::Error, "server error.") ||
38
+ 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
@@ -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'].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 village town city).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
  ##
@@ -86,8 +89,25 @@ module Geocoder
86
89
  @cache
87
90
  end
88
91
 
92
+ ##
93
+ # Array containing the protocols supported by the api.
94
+ # Should be set to [:http] if only HTTP is supported
95
+ # or [:https] if only HTTPS is supported.
96
+ #
97
+ def supported_protocols
98
+ [:http, :https]
99
+ end
100
+
89
101
  private # -------------------------------------------------------------
90
102
 
103
+ ##
104
+ # String which, when concatenated with url_query_string(query)
105
+ # produces the full query URL. Should include the "?" a the end.
106
+ #
107
+ def base_query_url(query)
108
+ fail
109
+ end
110
+
91
111
  ##
92
112
  # An object with configuration data for this particular lookup.
93
113
  #
@@ -99,7 +119,6 @@ module Geocoder
99
119
  # Object used to make HTTP requests.
100
120
  #
101
121
  def http_client
102
- protocol = "http#{'s' if use_ssl?}"
103
122
  proxy_name = "#{protocol}_proxy"
104
123
  if proxy = configuration.send(proxy_name)
105
124
  proxy_url = !!(proxy =~ /^#{protocol}/) ? proxy : protocol + '://' + proxy
@@ -139,7 +158,14 @@ module Geocoder
139
158
  # something else (like the URL before OAuth encoding).
140
159
  #
141
160
  def cache_key(query)
142
- query_url(query)
161
+ base_query_url(query) + hash_to_query(cache_key_params(query))
162
+ end
163
+
164
+ def cache_key_params(query)
165
+ # omit api_key and token because they may vary among requests
166
+ query_url_params(query).reject do |key,value|
167
+ key.to_s.match(/(key|token)/)
168
+ end
143
169
  end
144
170
 
145
171
  ##
@@ -168,12 +194,14 @@ module Geocoder
168
194
  def fetch_data(query)
169
195
  parse_raw_data fetch_raw_data(query)
170
196
  rescue SocketError => err
171
- raise_error(err) or warn "Geocoding API connection cannot be established."
197
+ raise_error(err) or Geocoder.log(:warn, "Geocoding API connection cannot be established.")
172
198
  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)."
199
+ raise_error(err) or Geocoder.log(:warn, "Geocoding API connection refused.")
200
+ rescue Geocoder::NetworkError => err
201
+ raise_error(err) or Geocoder.log(:warn, "Geocoding API connection is either unreacheable or reset by the peer")
202
+ rescue Timeout::Error => err
203
+ raise_error(err) or Geocoder.log(:warn, "Geocoding API not responding fast enough " +
204
+ "(use Geocoder.configure(:timeout => ...) to set limit).")
177
205
  end
178
206
 
179
207
  def parse_json(data)
@@ -182,6 +210,11 @@ module Geocoder
182
210
  else
183
211
  JSON.parse(data)
184
212
  end
213
+ rescue
214
+ unless raise_error(ResponseParseError.new(data))
215
+ Geocoder.log(:warn, "Geocoding API's response was not valid JSON")
216
+ Geocoder.log(:debug, "Raw response: #{data}")
217
+ end
185
218
  end
186
219
 
187
220
  ##
@@ -189,8 +222,6 @@ module Geocoder
189
222
  #
190
223
  def parse_raw_data(raw_data)
191
224
  parse_json(raw_data)
192
- rescue
193
- warn "Geocoding API's response was not valid JSON."
194
225
  end
195
226
 
196
227
  ##
@@ -242,16 +273,19 @@ module Geocoder
242
273
  def check_response_for_errors!(response)
243
274
  if response.code.to_i == 400
244
275
  raise_error(Geocoder::InvalidRequest) ||
245
- warn("Geocoding API error: 400 Bad Request")
276
+ Geocoder.log(:warn, "Geocoding API error: 400 Bad Request")
246
277
  elsif response.code.to_i == 401
247
278
  raise_error(Geocoder::RequestDenied) ||
248
- warn("Geocoding API error: 401 Unauthorized")
279
+ Geocoder.log(:warn, "Geocoding API error: 401 Unauthorized")
249
280
  elsif response.code.to_i == 402
250
281
  raise_error(Geocoder::OverQueryLimitError) ||
251
- warn("Geocoding API error: 402 Payment Required")
282
+ Geocoder.log(:warn, "Geocoding API error: 402 Payment Required")
252
283
  elsif response.code.to_i == 429
253
284
  raise_error(Geocoder::OverQueryLimitError) ||
254
- warn("Geocoding API error: 429 Too Many Requests")
285
+ Geocoder.log(:warn, "Geocoding API error: 429 Too Many Requests")
286
+ elsif response.code.to_i == 503
287
+ raise_error(Geocoder::ServiceUnavailable) ||
288
+ Geocoder.log(:warn, "Geocoding API error: 503 Service Unavailable")
255
289
  end
256
290
  end
257
291
 
@@ -260,23 +294,37 @@ module Geocoder
260
294
  # return the response object.
261
295
  #
262
296
  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)
297
+ uri = URI.parse(query_url(query))
298
+ Geocoder.log(:debug, "Geocoder: HTTP request being made for #{uri.to_s}")
299
+ http_client.start(uri.host, uri.port, use_ssl: use_ssl?, open_timeout: configuration.timeout, read_timeout: configuration.timeout) do |client|
300
+ configure_ssl!(client) if use_ssl?
301
+ req = Net::HTTP::Get.new(uri.request_uri, configuration.http_headers)
302
+ if configuration.basic_auth[:user] and configuration.basic_auth[:password]
303
+ req.basic_auth(
304
+ configuration.basic_auth[:user],
305
+ configuration.basic_auth[:password]
306
+ )
272
307
  end
308
+ client.request(req)
273
309
  end
310
+ rescue Timeout::Error
311
+ raise Geocoder::LookupTimeout
312
+ rescue Errno::EHOSTUNREACH, Errno::ETIMEDOUT, Errno::ENETUNREACH, Errno::ECONNRESET
313
+ raise Geocoder::NetworkError
274
314
  end
275
315
 
276
316
  def use_ssl?
277
- configuration.use_https
317
+ if supported_protocols == [:https]
318
+ true
319
+ elsif supported_protocols == [:http]
320
+ false
321
+ else
322
+ configuration.use_https
323
+ end
278
324
  end
279
325
 
326
+ def configure_ssl!(client); end
327
+
280
328
  def check_api_key_configuration!(query)
281
329
  key_parts = query.lookup.required_api_key_parts
282
330
  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
+ language: (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