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
@@ -10,12 +10,6 @@ module Geocoder
10
10
  #
11
11
  COMPASS_POINTS = %w[N NE E SE S SW W NW]
12
12
 
13
- ##
14
- # Radius of the Earth, in kilometers.
15
- # Value taken from: http://en.wikipedia.org/wiki/Earth_radius
16
- #
17
- EARTH_RADIUS = 6371.0
18
-
19
13
  ##
20
14
  # Conversion factor: multiply by kilometers to get miles.
21
15
  #
@@ -31,6 +25,16 @@ module Geocoder
31
25
  #
32
26
  DEGREES_PER_RADIAN = 57.2957795
33
27
 
28
+ ##
29
+ # Radius of the Earth, in kilometers.
30
+ # Value taken from: http://en.wikipedia.org/wiki/Earth_radius
31
+ #
32
+ EARTH_RADII = {km: 6371.0}
33
+ EARTH_RADII[:mi] = EARTH_RADII[:km] * KM_IN_MI
34
+ EARTH_RADII[:nm] = EARTH_RADII[:km] * KM_IN_NM
35
+
36
+ EARTH_RADIUS = EARTH_RADII[:km] # TODO: deprecate this constant (use `EARTH_RADII[:km]`)
37
+
34
38
  # Not a number constant
35
39
  NAN = defined?(::Float::NAN) ? ::Float::NAN : 0 / 0.0
36
40
 
@@ -50,7 +54,6 @@ module Geocoder
50
54
  # Distance spanned by one degree of latitude in the given units.
51
55
  #
52
56
  def latitude_degree_distance(units = nil)
53
- units ||= Geocoder.config.units
54
57
  2 * Math::PI * earth_radius(units) / 360
55
58
  end
56
59
 
@@ -59,7 +62,6 @@ module Geocoder
59
62
  # This ranges from around 69 miles at the equator to zero at the poles.
60
63
  #
61
64
  def longitude_degree_distance(latitude, units = nil)
62
- units ||= Geocoder.config.units
63
65
  latitude_degree_distance(units) * Math.cos(to_radians(latitude))
64
66
  end
65
67
 
@@ -80,10 +82,6 @@ module Geocoder
80
82
  # Use Geocoder.configure(:units => ...) to configure default units.
81
83
  #
82
84
  def distance_between(point1, point2, options = {})
83
-
84
- # set default options
85
- options[:units] ||= Geocoder.config.units
86
-
87
85
  # convert to coordinate arrays
88
86
  point1 = extract_coordinates(point1)
89
87
  point2 = extract_coordinates(point2)
@@ -156,7 +154,7 @@ module Geocoder
156
154
  # Translate a bearing (float) into a compass direction (string, eg "North").
157
155
  #
158
156
  def compass_point(bearing, points = COMPASS_POINTS)
159
- seg_size = 360 / points.size
157
+ seg_size = 360.0 / points.size
160
158
  points[((bearing + (seg_size / 2)) % 360) / seg_size]
161
159
  end
162
160
 
@@ -212,12 +210,11 @@ module Geocoder
212
210
  def bounding_box(point, radius, options = {})
213
211
  lat,lon = extract_coordinates(point)
214
212
  radius = radius.to_f
215
- units = options[:units] || Geocoder.config.units
216
213
  [
217
- lat - (radius / latitude_degree_distance(units)),
218
- lon - (radius / longitude_degree_distance(lat, units)),
219
- lat + (radius / latitude_degree_distance(units)),
220
- lon + (radius / longitude_degree_distance(lat, units))
214
+ lat - (radius / latitude_degree_distance(options[:units])),
215
+ lon - (radius / longitude_degree_distance(lat, options[:units])),
216
+ lat + (radius / latitude_degree_distance(options[:units])),
217
+ lon + (radius / longitude_degree_distance(lat, options[:units]))
221
218
  ]
222
219
  end
223
220
 
@@ -237,10 +234,9 @@ module Geocoder
237
234
  #
238
235
  # * <tt>:units</tt> - <tt>:mi</tt> or <tt>:km</tt>
239
236
  # Use Geocoder.configure(:units => ...) to configure default units.
237
+ # * <tt>:seed</tt> - The seed for the random number generator
240
238
  def random_point_near(center, radius, options = {})
241
-
242
- # set default options
243
- options[:units] ||= Geocoder.config.units
239
+ random = Random.new(options[:seed] || Random.new_seed)
244
240
 
245
241
  # convert to coordinate arrays
246
242
  center = extract_coordinates(center)
@@ -249,18 +245,18 @@ module Geocoder
249
245
  max_degree_delta = 360.0 * (radius / earth_circumference)
250
246
 
251
247
  # random bearing in radians
252
- theta = 2 * Math::PI * rand
248
+ theta = 2 * Math::PI * random.rand
253
249
 
254
250
  # random radius, use the square root to ensure a uniform
255
251
  # distribution of points over the circle
256
- r = Math.sqrt(rand) * max_degree_delta
252
+ r = Math.sqrt(random.rand) * max_degree_delta
257
253
 
258
254
  delta_lat, delta_long = [r * Math.cos(theta), r * Math.sin(theta)]
259
255
  [center[0] + delta_lat, center[1] + delta_long]
260
256
  end
261
257
 
262
258
  ##
263
- # Given a start point, distance, and heading (in degrees), provides
259
+ # Given a start point, heading (in degrees), and distance, provides
264
260
  # an endpoint.
265
261
  # The starting point is given in the same way that points are given to all
266
262
  # Geocoder methods that accept points as arguments. It can be:
@@ -271,7 +267,6 @@ module Geocoder
271
267
  # which returns a [lat,lon] array
272
268
  #
273
269
  def endpoint(start, heading, distance, options = {})
274
- options[:units] ||= Geocoder.config.units
275
270
  radius = earth_radius(options[:units])
276
271
 
277
272
  start = extract_coordinates(start)
@@ -322,12 +317,10 @@ module Geocoder
322
317
  end
323
318
 
324
319
  def distance_to_radians(distance, units = nil)
325
- units ||= Geocoder.config.units
326
320
  distance.to_f / earth_radius(units)
327
321
  end
328
322
 
329
323
  def radians_to_distance(radians, units = nil)
330
- units ||= Geocoder.config.units
331
324
  radians * earth_radius(units)
332
325
  end
333
326
 
@@ -335,6 +328,7 @@ module Geocoder
335
328
  # Convert miles to kilometers.
336
329
  #
337
330
  def to_kilometers(mi)
331
+ Geocoder.log(:warn, "DEPRECATION WARNING: Geocoder::Calculations.to_kilometers is deprecated and will be removed in Geocoder 1.5.0. Please multiply by MI_IN_KM instead.")
338
332
  mi * mi_in_km
339
333
  end
340
334
 
@@ -342,14 +336,16 @@ module Geocoder
342
336
  # Convert kilometers to miles.
343
337
  #
344
338
  def to_miles(km)
345
- km * km_in_mi
339
+ Geocoder.log(:warn, "DEPRECATION WARNING: Geocoder::Calculations.to_miles is deprecated and will be removed in Geocoder 1.5.0. Please multiply by KM_IN_MI instead.")
340
+ km * KM_IN_MI
346
341
  end
347
342
 
348
343
  ##
349
344
  # Convert kilometers to nautical miles.
350
345
  #
351
346
  def to_nautical_miles(km)
352
- km * km_in_nm
347
+ Geocoder.log(:warn, "DEPRECATION WARNING: Geocoder::Calculations.to_nautical_miles is deprecated and will be removed in Geocoder 1.5.0. Please multiply by KM_IN_NM instead.")
348
+ km * KM_IN_NM
353
349
  end
354
350
 
355
351
  ##
@@ -357,18 +353,14 @@ module Geocoder
357
353
  # Use Geocoder.configure(:units => ...) to configure default units.
358
354
  #
359
355
  def earth_radius(units = nil)
360
- units ||= Geocoder.config.units
361
- case units
362
- when :km; EARTH_RADIUS
363
- when :mi; to_miles(EARTH_RADIUS)
364
- when :nm; to_nautical_miles(EARTH_RADIUS)
365
- end
356
+ EARTH_RADII[units || Geocoder.config.units]
366
357
  end
367
358
 
368
359
  ##
369
360
  # Conversion factor: km to mi.
370
361
  #
371
362
  def km_in_mi
363
+ Geocoder.log(:warn, "DEPRECATION WARNING: Geocoder::Calculations.km_in_mi is deprecated and will be removed in Geocoder 1.5.0. Please use the constant KM_IN_MI instead.")
372
364
  KM_IN_MI
373
365
  end
374
366
 
@@ -376,15 +368,15 @@ module Geocoder
376
368
  # Conversion factor: km to nm.
377
369
  #
378
370
  def km_in_nm
371
+ Geocoder.log(:warn, "DEPRECATION WARNING: Geocoder::Calculations.km_in_nm is deprecated and will be removed in Geocoder 1.5.0. Please use the constant KM_IN_NM instead.")
379
372
  KM_IN_NM
380
373
  end
381
374
 
382
-
383
-
384
375
  ##
385
376
  # Conversion factor: mi to km.
386
377
  #
387
378
  def mi_in_km
379
+ Geocoder.log(:warn, "DEPRECATION WARNING: Geocoder::Calculations.mi_in_km is deprecated and will be removed in Geocoder 1.5.0. Please use 1.0 / KM_IN_MI instead.")
388
380
  1.0 / KM_IN_MI
389
381
  end
390
382
 
@@ -392,6 +384,7 @@ module Geocoder
392
384
  # Conversion factor: nm to km.
393
385
  #
394
386
  def nm_in_km
387
+ Geocoder.log(:warn, "DEPRECATION WARNING: Geocoder::Calculations.nm_in_km is deprecated and will be removed in Geocoder 1.5.0. Please use 1.0 / KM_IN_NM instead.")
395
388
  1.0 / KM_IN_NM
396
389
  end
397
390
 
@@ -425,4 +418,3 @@ module Geocoder
425
418
  end
426
419
  end
427
420
  end
428
-
data/lib/geocoder/cli.rb CHANGED
@@ -97,7 +97,7 @@ module Geocoder
97
97
  end
98
98
 
99
99
  if (result = Geocoder.search(query).first)
100
- google = Geocoder::Lookup.get(:google)
100
+ nominatim = Geocoder::Lookup.get(:nominatim)
101
101
  lines = [
102
102
  ["Latitude", result.latitude],
103
103
  ["Longitude", result.longitude],
@@ -106,7 +106,7 @@ module Geocoder
106
106
  ["State/province", result.state],
107
107
  ["Postal code", result.postal_code],
108
108
  ["Country", result.country],
109
- ["Google map", google.map_link_url(result.coordinates)],
109
+ ["Map", nominatim.map_link_url(result.coordinates)],
110
110
  ]
111
111
  lines.each do |line|
112
112
  out << (line[0] + ": ").ljust(18) + line[1].to_s + "\n"
@@ -1,5 +1,6 @@
1
1
  require 'singleton'
2
2
  require 'geocoder/configuration_hash'
3
+ require 'geocoder/util'
3
4
 
4
5
  module Geocoder
5
6
 
@@ -38,6 +39,14 @@ module Geocoder
38
39
  data
39
40
  end
40
41
 
42
+ ##
43
+ # Merge the given hash into a lookup's existing configuration.
44
+ #
45
+ def self.merge_into_lookup_config(lookup_name, options)
46
+ base = Geocoder.config[lookup_name]
47
+ Geocoder.configure(lookup_name => base.merge(options))
48
+ end
49
+
41
50
  class Configuration
42
51
  include Singleton
43
52
 
@@ -46,16 +55,20 @@ module Geocoder
46
55
  :lookup,
47
56
  :ip_lookup,
48
57
  :language,
58
+ :host,
49
59
  :http_headers,
50
60
  :use_https,
51
61
  :http_proxy,
52
62
  :https_proxy,
53
63
  :api_key,
54
64
  :cache,
55
- :cache_prefix,
56
65
  :always_raise,
57
66
  :units,
58
- :distances
67
+ :distances,
68
+ :basic_auth,
69
+ :logger,
70
+ :kernel_logger_level,
71
+ :cache_options
59
72
  ]
60
73
 
61
74
  attr_accessor :data
@@ -64,6 +77,10 @@ module Geocoder
64
77
  instance.set_defaults
65
78
  end
66
79
 
80
+ def self.initialize
81
+ instance.send(:initialize)
82
+ end
83
+
67
84
  OPTIONS.each do |o|
68
85
  define_method o do
69
86
  @data[o]
@@ -74,7 +91,7 @@ module Geocoder
74
91
  end
75
92
 
76
93
  def configure(options)
77
- @data.rmerge!(options)
94
+ Util.recursive_hash_merge(@data, options)
78
95
  end
79
96
 
80
97
  def initialize # :nodoc
@@ -86,25 +103,36 @@ module Geocoder
86
103
 
87
104
  # geocoding options
88
105
  @data[:timeout] = 3 # geocoding service timeout (secs)
89
- @data[:lookup] = :google # name of street address geocoding service (symbol)
90
- @data[:ip_lookup] = :freegeoip # name of IP address geocoding service (symbol)
106
+ @data[:lookup] = :nominatim # name of street address geocoding service (symbol)
107
+ @data[:ip_lookup] = :ipinfo_io # name of IP address geocoding service (symbol)
91
108
  @data[:language] = :en # ISO-639 language code
92
109
  @data[:http_headers] = {} # HTTP headers for lookup
93
110
  @data[:use_https] = false # use HTTPS for lookup requests? (if supported)
94
111
  @data[:http_proxy] = nil # HTTP proxy server (user:pass@host:port)
95
112
  @data[:https_proxy] = nil # HTTPS proxy server (user:pass@host:port)
96
113
  @data[:api_key] = nil # API key for geocoding service
97
- @data[:cache] = nil # cache object (must respond to #[], #[]=, and #keys)
98
- @data[:cache_prefix] = "geocoder:" # prefix (string) to use for all cache keys
114
+ @data[:basic_auth] = {} # user and password for basic auth ({:user => "user", :password => "password"})
115
+ @data[:logger] = :kernel # :kernel or Logger instance
116
+ @data[:kernel_logger_level] = ::Logger::WARN # log level, if kernel logger is used
99
117
 
100
118
  # exceptions that should not be rescued by default
101
119
  # (if you want to implement custom error handling);
102
- # supports SocketError and TimeoutError
120
+ # supports SocketError and Timeout::Error
103
121
  @data[:always_raise] = []
104
122
 
105
123
  # calculation options
106
124
  @data[:units] = :mi # :mi or :km
107
125
  @data[:distances] = :linear # :linear or :spherical
126
+
127
+ # Set the default values for the caching mechanism
128
+ # By default, the cache keys will not expire as IP addresses and phyiscal
129
+ # addresses will rarely change.
130
+ @data[:cache] = nil # cache object (must respond to #[], #[]=, and optionally #keys)
131
+ @data[:cache_prefix] = nil # - DEPRECATED - prefix (string) to use for all cache keys
132
+ @data[:cache_options] = {
133
+ prefix: 'geocoder:',
134
+ expiration: nil
135
+ }
108
136
  end
109
137
 
110
138
  instance_eval(OPTIONS.map do |option|
@@ -119,6 +147,5 @@ module Geocoder
119
147
  end
120
148
  EOS
121
149
  end.join("\n\n"))
122
-
123
150
  end
124
151
  end
@@ -1,11 +1,11 @@
1
- require 'hash_recursive_merge'
2
-
3
1
  module Geocoder
4
2
  class ConfigurationHash < Hash
5
- include HashRecursiveMerge
6
-
7
3
  def method_missing(meth, *args, &block)
8
4
  has_key?(meth) ? self[meth] : super
9
5
  end
6
+
7
+ def respond_to_missing?(meth, include_private = false)
8
+ has_key?(meth) || super
9
+ end
10
10
  end
11
11
  end
@@ -0,0 +1,38 @@
1
+ module Geocoder
2
+ class EsriToken
3
+ attr_accessor :value, :expires_at
4
+
5
+ def initialize(value, expires_at)
6
+ @value = value
7
+ @expires_at = expires_at
8
+ end
9
+
10
+ def to_s
11
+ @value
12
+ end
13
+
14
+ def active?
15
+ @expires_at > Time.now
16
+ end
17
+
18
+ def self.generate_token(client_id, client_secret, expires=1440)
19
+ # creates a new token that will expire in 1 day by default
20
+ getToken = Net::HTTP.post_form URI('https://www.arcgis.com/sharing/rest/oauth2/token'),
21
+ f: 'json',
22
+ client_id: client_id,
23
+ client_secret: client_secret,
24
+ grant_type: 'client_credentials',
25
+ expiration: expires # (minutes) max: 20160, default: 1 day
26
+
27
+ response = JSON.parse(getToken.body)
28
+
29
+ if response['error']
30
+ Geocoder.log(:warn, response['error'])
31
+ else
32
+ token_value = response['access_token']
33
+ expires_at = Time.now + (expires * 60)
34
+ new(token_value, expires_at)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,3 +1,5 @@
1
+ require 'timeout'
2
+
1
3
  module Geocoder
2
4
 
3
5
  class Error < StandardError
@@ -9,6 +11,14 @@ module Geocoder
9
11
  class OverQueryLimitError < Error
10
12
  end
11
13
 
14
+ class ResponseParseError < Error
15
+ attr_reader :response
16
+
17
+ def initialize(response)
18
+ @response = response
19
+ end
20
+ end
21
+
12
22
  class RequestDenied < Error
13
23
  end
14
24
 
@@ -18,4 +28,13 @@ module Geocoder
18
28
  class InvalidApiKey < Error
19
29
  end
20
30
 
31
+ class ServiceUnavailable < Error
32
+ end
33
+
34
+ class LookupTimeout < ::Timeout::Error
35
+ end
36
+
37
+ class NetworkError < Error
38
+ end
39
+
21
40
  end
@@ -1,21 +1,36 @@
1
+ require 'resolv'
1
2
  module Geocoder
2
3
  class IpAddress < String
4
+ PRIVATE_IPS = [
5
+ '10.0.0.0/8',
6
+ '172.16.0.0/12',
7
+ '192.168.0.0/16',
8
+ ].map { |ip| IPAddr.new(ip) }.freeze
9
+
10
+ def initialize(ip)
11
+ ip = ip.to_string if ip.is_a?(IPAddr)
12
+ if ip.is_a?(Hash)
13
+ super(**ip)
14
+ else
15
+ super(ip)
16
+ end
17
+ end
18
+
19
+ def internal?
20
+ loopback? || private?
21
+ end
3
22
 
4
23
  def loopback?
5
- valid? and (self == "0.0.0.0" or self.match(/\A127\./) or self == "::1")
24
+ valid? and !!(self == "0.0.0.0" or self.match(/\A127\./) or self == "::1")
25
+ end
26
+
27
+ def private?
28
+ valid? && PRIVATE_IPS.any? { |ip| ip.include?(self) }
6
29
  end
7
30
 
8
31
  def valid?
9
- ipregex = %r{
10
- \A( # String Starts
11
- ((::ffff:)?((\d{1,3})\.){3}\d{1,3}) # Check for IPv4
12
- | # .... Or
13
- (\S+?(:\S+?){6}\S+) # Check for IPv6
14
- | # .... Or
15
- (::1) # IPv6 loopback
16
- )\z
17
- }x
18
- !!self.match(ipregex)
32
+ ip = self[/(?<=\[)(.*?)(?=\])/] || self
33
+ !!((ip =~ Resolv::IPv4::Regex) || (ip =~ Resolv::IPv6::Regex))
19
34
  end
20
35
  end
21
36
  end
@@ -0,0 +1,25 @@
1
+ module Geocoder
2
+ class KernelLogger
3
+ include Singleton
4
+
5
+ def add(level, message)
6
+ return unless log_message_at_level?(level)
7
+ case level
8
+ when ::Logger::DEBUG, ::Logger::INFO
9
+ puts message
10
+ when ::Logger::WARN
11
+ warn message
12
+ when ::Logger::ERROR
13
+ raise message
14
+ when ::Logger::FATAL
15
+ fail message
16
+ end
17
+ end
18
+
19
+ private # ----------------------------------------------------------------
20
+
21
+ def log_message_at_level?(level)
22
+ level >= Geocoder.config.kernel_logger_level
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,47 @@
1
+ require 'logger'
2
+
3
+ module Geocoder
4
+
5
+ def self.log(level, message)
6
+ Logger.instance.log(level, message)
7
+ end
8
+
9
+ class Logger
10
+ include Singleton
11
+
12
+ SEVERITY = {
13
+ debug: ::Logger::DEBUG,
14
+ info: ::Logger::INFO,
15
+ warn: ::Logger::WARN,
16
+ error: ::Logger::ERROR,
17
+ fatal: ::Logger::FATAL
18
+ }
19
+
20
+ def log(level, message)
21
+ unless valid_level?(level)
22
+ raise StandardError, "Geocoder tried to log a message with an invalid log level."
23
+ end
24
+ if current_logger.respond_to? :add
25
+ current_logger.add(SEVERITY[level], message)
26
+ else
27
+ raise Geocoder::ConfigurationError, "Please specify valid logger for Geocoder. " +
28
+ "Logger specified must be :kernel or must respond to `add(level, message)`."
29
+ end
30
+ nil
31
+ end
32
+
33
+ private # ----------------------------------------------------------------
34
+
35
+ def current_logger
36
+ logger = Geocoder.config[:logger]
37
+ if logger == :kernel
38
+ logger = Geocoder::KernelLogger.instance
39
+ end
40
+ logger
41
+ end
42
+
43
+ def valid_level?(level)
44
+ SEVERITY.keys.include?(level)
45
+ end
46
+ end
47
+ end
@@ -1,3 +1,5 @@
1
+ require "geocoder/lookups/test"
2
+
1
3
  module Geocoder
2
4
  module Lookup
3
5
  extend self
@@ -16,32 +18,56 @@ module Geocoder
16
18
  all_services - [:test]
17
19
  end
18
20
 
21
+ ##
22
+ # Array of valid Lookup service names, excluding any that do not build their own HTTP requests.
23
+ # For example, Amazon Location Service uses the AWS gem, not HTTP REST requests, to fetch data.
24
+ #
25
+ def all_services_with_http_requests
26
+ all_services_except_test - [:amazon_location_service]
27
+ end
28
+
19
29
  ##
20
30
  # All street address lookup services, default first.
21
31
  #
22
32
  def street_services
23
- [
33
+ @street_services ||= [
34
+ :location_iq,
24
35
  :dstk,
25
36
  :esri,
26
37
  :google,
27
38
  :google_premier,
28
39
  :google_places_details,
29
- :yahoo,
40
+ :google_places_search,
30
41
  :bing,
31
42
  :geocoder_ca,
32
- :geocoder_us,
33
43
  :yandex,
44
+ :nationaal_georegister_nl,
34
45
  :nominatim,
46
+ :mapbox,
35
47
  :mapquest,
48
+ :uk_ordnance_survey_names,
36
49
  :opencagedata,
37
- :ovi,
50
+ :pelias,
51
+ :pickpoint,
38
52
  :here,
39
53
  :baidu,
54
+ :tencent,
40
55
  :geocodio,
41
56
  :smarty_streets,
42
- :okf,
43
57
  :postcode_anywhere_uk,
44
- :test
58
+ :postcodes_io,
59
+ :geoportail_lu,
60
+ :ban_data_gouv_fr,
61
+ :test,
62
+ :latlon,
63
+ :amap,
64
+ :osmnames,
65
+ :melissa_street,
66
+ :amazon_location_service,
67
+ :geoapify,
68
+ :photon,
69
+ :twogis,
70
+ :pc_miler
45
71
  ]
46
72
  end
47
73
 
@@ -49,17 +75,31 @@ module Geocoder
49
75
  # All IP address lookup services, default first.
50
76
  #
51
77
  def ip_services
52
- [
78
+ @ip_services ||= [
53
79
  :baidu_ip,
80
+ :abstract_api,
54
81
  :freegeoip,
55
82
  :geoip2,
56
83
  :maxmind,
57
84
  :maxmind_local,
58
85
  :telize,
59
- :pointpin
86
+ :pointpin,
87
+ :maxmind_geoip2,
88
+ :ipinfo_io,
89
+ :ipregistry,
90
+ :ipapi_com,
91
+ :ipdata_co,
92
+ :db_ip_com,
93
+ :ipstack,
94
+ :ip2location,
95
+ :ipgeolocation,
96
+ :ipqualityscore,
97
+ :ipbase
60
98
  ]
61
99
  end
62
100
 
101
+ attr_writer :street_services, :ip_services
102
+
63
103
  ##
64
104
  # Retrieve a Lookup object from the store.
65
105
  # Use this instead of Geocoder::Lookup::X.new to get an
@@ -79,7 +119,8 @@ module Geocoder
79
119
  #
80
120
  def spawn(name)
81
121
  if all_services.include?(name)
82
- Geocoder::Lookup.const_get(classify_name(name)).new
122
+ name = name.to_s
123
+ instantiate_lookup(name)
83
124
  else
84
125
  valids = all_services.map(&:inspect).join(", ")
85
126
  raise ConfigurationError, "Please specify a valid lookup for Geocoder " +
@@ -93,9 +134,18 @@ module Geocoder
93
134
  def classify_name(filename)
94
135
  filename.to_s.split("_").map{ |i| i[0...1].upcase + i[1..-1] }.join
95
136
  end
96
- end
97
- end
98
137
 
99
- Geocoder::Lookup.all_services.each do |name|
100
- require "geocoder/lookups/#{name}"
138
+ ##
139
+ # Safely instantiate Lookup
140
+ #
141
+ def instantiate_lookup(name)
142
+ class_name = classify_name(name)
143
+ begin
144
+ Geocoder::Lookup.const_get(class_name, inherit=false)
145
+ rescue NameError
146
+ require "geocoder/lookups/#{name}"
147
+ end
148
+ Geocoder::Lookup.const_get(class_name).new
149
+ end
150
+ end
101
151
  end