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,6 +1,8 @@
1
1
  # This class implements a cache with simple delegation to the Redis store, but
2
2
  # when it creates a key/value pair, it also sends an EXPIRE command with a TTL.
3
3
  # It should be fairly simple to do the same thing with Memcached.
4
+ # Alternatively, this class could inherit from Redis, which would make most
5
+ # of the below methods unnecessary.
4
6
  class AutoexpireCacheRedis
5
7
  def initialize(store, ttl = 86400)
6
8
  @store = store
@@ -8,11 +10,11 @@ class AutoexpireCacheRedis
8
10
  end
9
11
 
10
12
  def [](url)
11
- @store.[](url)
13
+ @store.get(url)
12
14
  end
13
15
 
14
16
  def []=(url, value)
15
- @store.[]=(url, value)
17
+ @store.set(url, value)
16
18
  @store.expire(url, @ttl)
17
19
  end
18
20
 
@@ -25,4 +27,4 @@ class AutoexpireCacheRedis
25
27
  end
26
28
  end
27
29
 
28
- Geocoder.configure(:cache => AutoexpireCacheRedis.new(Redis.new))
30
+ Geocoder.configure(:cache => AutoexpireCacheRedis.new(Redis.new))
@@ -0,0 +1,40 @@
1
+ # This class implements an ActiveJob job for performing reverse-geocoding
2
+ # asynchronously. Example usage:
3
+
4
+ # if @location.save && @location.address.blank?
5
+ # ReverseGeocodeJob.perform_later(@location)
6
+ # end
7
+
8
+ # Be sure to configure the queue adapter in config/application.rb:
9
+ # config.active_job.queue_adapter = :sidekiq
10
+
11
+ # You can read the Rails docs for more information on configuring ActiveJob:
12
+ # http://edgeguides.rubyonrails.org/active_job_basics.html
13
+
14
+ class ReverseGeocodeJob < ActiveJob::Base
15
+ queue_as :high
16
+
17
+ def perform(location)
18
+ address = address(location)
19
+
20
+ if address.present?
21
+ location.update(address: address)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def address(location)
28
+ Geocoder.address(location.coordinates)
29
+ rescue => exception
30
+ MonitoringService.notify(exception, location: { id: location.id })
31
+
32
+ if retryable?(exception)
33
+ raise exception
34
+ end
35
+ end
36
+
37
+ def retryable?(exception)
38
+ exception.is_a?(Timeout::Error) || exception.is_a?(SocketError)
39
+ end
40
+ end
@@ -1,21 +1,22 @@
1
1
  Geocoder.configure(
2
- # geocoding options
3
- # :timeout => 3, # geocoding service timeout (secs)
4
- # :lookup => :google, # name of geocoding service (symbol)
5
- # :language => :en, # ISO-639 language code
6
- # :use_https => false, # use HTTPS for lookup requests? (if supported)
7
- # :http_proxy => nil, # HTTP proxy server (user:pass@host:port)
8
- # :https_proxy => nil, # HTTPS proxy server (user:pass@host:port)
9
- # :api_key => nil, # API key for geocoding service
10
- # :cache => nil, # cache object (must respond to #[], #[]=, and #keys)
11
- # :cache_prefix => "geocoder:", # prefix (string) to use for all cache keys
2
+ # Geocoding options
3
+ # timeout: 3, # geocoding service timeout (secs)
4
+ # lookup: :nominatim, # name of geocoding service (symbol)
5
+ # ip_lookup: :ipinfo_io, # name of IP address geocoding service (symbol)
6
+ # language: :en, # ISO-639 language code
7
+ # use_https: false, # use HTTPS for lookup requests? (if supported)
8
+ # http_proxy: nil, # HTTP proxy server (user:pass@host:port)
9
+ # https_proxy: nil, # HTTPS proxy server (user:pass@host:port)
10
+ # api_key: nil, # API key for geocoding service
11
+ # cache: nil, # cache object (must respond to #[], #[]=, and #del)
12
+ # cache_prefix: 'geocoder:', # prefix (string) to use for all cache keys
12
13
 
13
- # exceptions that should not be rescued by default
14
+ # Exceptions that should not be rescued by default
14
15
  # (if you want to implement custom error handling);
15
- # supports SocketError and TimeoutError
16
- # :always_raise => [],
16
+ # supports SocketError and Timeout::Error
17
+ # always_raise: [],
17
18
 
18
- # calculation options
19
- # :units => :mi, # :km for kilometers or :mi for miles
20
- # :distances => :linear # :spherical or :linear
19
+ # Calculation options
20
+ # units: :mi, # :km for kilometers or :mi for miles
21
+ # distances: :linear # :spherical or :linear
21
22
  )
@@ -1,10 +1,12 @@
1
1
  require 'rails/generators/migration'
2
+ require 'generators/geocoder/migration_version'
2
3
 
3
4
  module Geocoder
4
5
  module Generators
5
6
  module Maxmind
6
7
  class GeoliteCityGenerator < Rails::Generators::Base
7
8
  include Rails::Generators::Migration
9
+ include Generators::MigrationVersion
8
10
 
9
11
  source_root File.expand_path('../templates', __FILE__)
10
12
 
@@ -1,10 +1,12 @@
1
1
  require 'rails/generators/migration'
2
+ require 'generators/geocoder/migration_version'
2
3
 
3
4
  module Geocoder
4
5
  module Generators
5
6
  module Maxmind
6
7
  class GeoliteCountryGenerator < Rails::Generators::Base
7
8
  include Rails::Generators::Migration
9
+ include Generators::MigrationVersion
8
10
 
9
11
  source_root File.expand_path('../templates', __FILE__)
10
12
 
@@ -1,4 +1,4 @@
1
- class GeocoderMaxmindGeoliteCity < ActiveRecord::Migration
1
+ class GeocoderMaxmindGeoliteCity < ActiveRecord::Migration<%= migration_version %>
2
2
  def self.up
3
3
  create_table :maxmind_geolite_city_blocks, id: false do |t|
4
4
  t.column :start_ip_num, :bigint, null: false
@@ -1,4 +1,4 @@
1
- class GeocoderMaxmindGeoliteCountry < ActiveRecord::Migration
1
+ class GeocoderMaxmindGeoliteCountry < ActiveRecord::Migration<%= migration_version %>
2
2
  def self.up
3
3
  create_table :maxmind_geolite_country, id: false do |t|
4
4
  t.column :start_ip, :string
@@ -0,0 +1,15 @@
1
+ module Geocoder
2
+ module Generators
3
+ module MigrationVersion
4
+ def rails_5?
5
+ Rails::VERSION::MAJOR == 5
6
+ end
7
+
8
+ def migration_version
9
+ if rails_5?
10
+ "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -40,7 +40,11 @@ module Geocoder
40
40
  #
41
41
  def expire(url)
42
42
  if url == :all
43
- urls.each{ |u| expire(u) }
43
+ if store.respond_to?(:keys)
44
+ urls.each{ |u| expire(u) }
45
+ else
46
+ raise(NoMethodError, "The Geocoder cache store must implement `#keys` for `expire(:all)` to work")
47
+ end
44
48
  else
45
49
  expire_single_url(url)
46
50
  end
@@ -64,7 +68,7 @@ module Geocoder
64
68
  # that have non-nil values.
65
69
  #
66
70
  def keys
67
- store.keys.select{ |k| k.match(/^#{prefix}/) and interpret(store[k]) }
71
+ store.keys.select{ |k| k.match(/^#{prefix}/) and self[k] }
68
72
  end
69
73
 
70
74
  ##
@@ -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"
@@ -38,6 +38,14 @@ module Geocoder
38
38
  data
39
39
  end
40
40
 
41
+ ##
42
+ # Merge the given hash into a lookup's existing configuration.
43
+ #
44
+ def self.merge_into_lookup_config(lookup_name, options)
45
+ base = Geocoder.config[lookup_name]
46
+ Geocoder.configure(lookup_name => base.merge(options))
47
+ end
48
+
41
49
  class Configuration
42
50
  include Singleton
43
51
 
@@ -55,7 +63,10 @@ module Geocoder
55
63
  :cache_prefix,
56
64
  :always_raise,
57
65
  :units,
58
- :distances
66
+ :distances,
67
+ :basic_auth,
68
+ :logger,
69
+ :kernel_logger_level
59
70
  ]
60
71
 
61
72
  attr_accessor :data
@@ -86,8 +97,8 @@ module Geocoder
86
97
 
87
98
  # geocoding options
88
99
  @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)
100
+ @data[:lookup] = :nominatim # name of street address geocoding service (symbol)
101
+ @data[:ip_lookup] = :ipinfo_io # name of IP address geocoding service (symbol)
91
102
  @data[:language] = :en # ISO-639 language code
92
103
  @data[:http_headers] = {} # HTTP headers for lookup
93
104
  @data[:use_https] = false # use HTTPS for lookup requests? (if supported)
@@ -96,10 +107,13 @@ module Geocoder
96
107
  @data[:api_key] = nil # API key for geocoding service
97
108
  @data[:cache] = nil # cache object (must respond to #[], #[]=, and #keys)
98
109
  @data[:cache_prefix] = "geocoder:" # prefix (string) to use for all cache keys
110
+ @data[:basic_auth] = {} # user and password for basic auth ({:user => "user", :password => "password"})
111
+ @data[:logger] = :kernel # :kernel or Logger instance
112
+ @data[:kernel_logger_level] = ::Logger::WARN # log level, if kernel logger is used
99
113
 
100
114
  # exceptions that should not be rescued by default
101
115
  # (if you want to implement custom error handling);
102
- # supports SocketError and TimeoutError
116
+ # supports SocketError and Timeout::Error
103
117
  @data[:always_raise] = []
104
118
 
105
119
  # calculation options
@@ -119,6 +133,5 @@ module Geocoder
119
133
  end
120
134
  EOS
121
135
  end.join("\n\n"))
122
-
123
136
  end
124
137
  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,26 @@
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 internal?
11
+ loopback? || private?
12
+ end
3
13
 
4
14
  def loopback?
5
- valid? and (self == "0.0.0.0" or self.match(/\A127\./) or self == "::1")
15
+ valid? and !!(self == "0.0.0.0" or self.match(/\A127\./) or self == "::1")
16
+ end
17
+
18
+ def private?
19
+ valid? && PRIVATE_IPS.any? { |ip| ip.include?(self) }
6
20
  end
7
21
 
8
22
  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)
23
+ !!((self =~ Resolv::IPv4::Regex) || (self =~ Resolv::IPv6::Regex))
19
24
  end
20
25
  end
21
26
  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