geocoder 1.2.6 → 1.6.1

Sign up to get free protection for your applications and to get access to all the features.
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