geocoder 1.2.6 → 1.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +189 -1
- data/LICENSE +1 -1
- data/README.md +387 -755
- data/examples/autoexpire_cache_redis.rb +5 -3
- data/examples/reverse_geocode_job.rb +40 -0
- data/lib/generators/geocoder/config/templates/initializer.rb +17 -16
- data/lib/generators/geocoder/maxmind/geolite_city_generator.rb +2 -0
- data/lib/generators/geocoder/maxmind/geolite_country_generator.rb +2 -0
- data/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb +1 -1
- data/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb +1 -1
- data/lib/generators/geocoder/migration_version.rb +15 -0
- data/lib/geocoder/cache.rb +6 -2
- data/lib/geocoder/calculations.rb +30 -38
- data/lib/geocoder/cli.rb +2 -2
- data/lib/geocoder/configuration.rb +18 -5
- data/lib/geocoder/esri_token.rb +38 -0
- data/lib/geocoder/exceptions.rb +19 -0
- data/lib/geocoder/ip_address.rb +16 -11
- data/lib/geocoder/kernel_logger.rb +25 -0
- data/lib/geocoder/logger.rb +47 -0
- data/lib/geocoder/lookup.rb +31 -12
- data/lib/geocoder/lookups/amap.rb +63 -0
- data/lib/geocoder/lookups/baidu.rb +17 -9
- data/lib/geocoder/lookups/baidu_ip.rb +7 -31
- data/lib/geocoder/lookups/ban_data_gouv_fr.rb +143 -0
- data/lib/geocoder/lookups/base.rb +73 -25
- data/lib/geocoder/lookups/bing.rb +38 -15
- data/lib/geocoder/lookups/db_ip_com.rb +52 -0
- data/lib/geocoder/lookups/dstk.rb +4 -2
- data/lib/geocoder/lookups/esri.rb +55 -8
- data/lib/geocoder/lookups/freegeoip.rb +18 -5
- data/lib/geocoder/lookups/geocoder_ca.rb +5 -6
- data/lib/geocoder/lookups/geocodio.rb +8 -8
- data/lib/geocoder/lookups/geoip2.rb +10 -5
- data/lib/geocoder/lookups/geoportail_lu.rb +65 -0
- data/lib/geocoder/lookups/google.rb +37 -9
- data/lib/geocoder/lookups/google_places_details.rb +9 -9
- data/lib/geocoder/lookups/google_places_search.rb +33 -0
- data/lib/geocoder/lookups/google_premier.rb +11 -1
- data/lib/geocoder/lookups/here.rb +29 -23
- data/lib/geocoder/lookups/ip2location.rb +67 -0
- data/lib/geocoder/lookups/ipapi_com.rb +82 -0
- data/lib/geocoder/lookups/ipdata_co.rb +62 -0
- data/lib/geocoder/lookups/ipgeolocation.rb +51 -0
- data/lib/geocoder/lookups/ipinfo_io.rb +44 -0
- data/lib/geocoder/lookups/ipregistry.rb +68 -0
- data/lib/geocoder/lookups/ipstack.rb +63 -0
- data/lib/geocoder/lookups/latlon.rb +59 -0
- data/lib/geocoder/lookups/location_iq.rb +50 -0
- data/lib/geocoder/lookups/mapbox.rb +59 -0
- data/lib/geocoder/lookups/mapquest.rb +7 -9
- data/lib/geocoder/lookups/maxmind.rb +7 -7
- data/lib/geocoder/lookups/maxmind_geoip2.rb +70 -0
- data/lib/geocoder/lookups/maxmind_local.rb +9 -2
- data/lib/geocoder/lookups/nominatim.rb +18 -6
- data/lib/geocoder/lookups/opencagedata.rb +16 -9
- data/lib/geocoder/lookups/osmnames.rb +57 -0
- data/lib/geocoder/lookups/pelias.rb +63 -0
- data/lib/geocoder/lookups/pickpoint.rb +41 -0
- data/lib/geocoder/lookups/pointpin.rb +14 -13
- data/lib/geocoder/lookups/postcode_anywhere_uk.rb +7 -8
- data/lib/geocoder/lookups/postcodes_io.rb +31 -0
- data/lib/geocoder/lookups/smarty_streets.rb +23 -5
- data/lib/geocoder/lookups/telize.rb +42 -7
- data/lib/geocoder/lookups/tencent.rb +59 -0
- data/lib/geocoder/lookups/yandex.rb +17 -9
- data/lib/geocoder/models/active_record.rb +4 -3
- data/lib/geocoder/models/mongo_base.rb +0 -2
- data/lib/geocoder/query.rb +15 -1
- data/lib/geocoder/railtie.rb +1 -1
- data/lib/geocoder/request.rb +103 -14
- data/lib/geocoder/results/amap.rb +87 -0
- data/lib/geocoder/results/baidu.rb +10 -14
- data/lib/geocoder/results/ban_data_gouv_fr.rb +257 -0
- data/lib/geocoder/results/base.rb +13 -1
- data/lib/geocoder/results/bing.rb +5 -1
- data/lib/geocoder/results/db_ip_com.rb +58 -0
- data/lib/geocoder/results/esri.rb +30 -6
- data/lib/geocoder/results/freegeoip.rb +2 -7
- data/lib/geocoder/results/geocoder_ca.rb +3 -3
- data/lib/geocoder/results/geocodio.rb +15 -3
- data/lib/geocoder/results/geoip2.rb +37 -25
- data/lib/geocoder/results/geoportail_lu.rb +71 -0
- data/lib/geocoder/results/google.rb +26 -0
- data/lib/geocoder/results/google_places_details.rb +4 -0
- data/lib/geocoder/results/google_places_search.rb +52 -0
- data/lib/geocoder/results/here.rb +21 -1
- data/lib/geocoder/results/ip2location.rb +22 -0
- data/lib/geocoder/results/ipapi_com.rb +45 -0
- data/lib/geocoder/results/ipdata_co.rb +40 -0
- data/lib/geocoder/results/ipgeolocation.rb +59 -0
- data/lib/geocoder/results/ipinfo_io.rb +48 -0
- data/lib/geocoder/results/ipregistry.rb +308 -0
- data/lib/geocoder/results/ipstack.rb +60 -0
- data/lib/geocoder/results/latlon.rb +71 -0
- data/lib/geocoder/results/location_iq.rb +6 -0
- data/lib/geocoder/results/mapbox.rb +57 -0
- data/lib/geocoder/results/mapquest.rb +5 -8
- data/lib/geocoder/results/maxmind.rb +0 -5
- data/lib/geocoder/results/maxmind_geoip2.rb +9 -0
- data/lib/geocoder/results/maxmind_local.rb +0 -5
- data/lib/geocoder/results/nominatim.rb +18 -3
- data/lib/geocoder/results/opencagedata.rb +20 -2
- data/lib/geocoder/results/osmnames.rb +56 -0
- data/lib/geocoder/results/pelias.rb +58 -0
- data/lib/geocoder/results/pickpoint.rb +6 -0
- data/lib/geocoder/results/pointpin.rb +0 -4
- data/lib/geocoder/results/postcodes_io.rb +40 -0
- data/lib/geocoder/results/smarty_streets.rb +55 -19
- data/lib/geocoder/results/telize.rb +0 -5
- data/lib/geocoder/results/tencent.rb +72 -0
- data/lib/geocoder/results/test.rb +1 -1
- data/lib/geocoder/results/yandex.rb +57 -7
- data/lib/geocoder/sql.rb +9 -6
- data/lib/geocoder/stores/active_record.rb +49 -10
- data/lib/geocoder/stores/base.rb +2 -14
- data/lib/geocoder/stores/mongo_base.rb +0 -31
- data/lib/geocoder/version.rb +1 -1
- data/lib/geocoder.rb +2 -1
- data/lib/hash_recursive_merge.rb +1 -2
- data/lib/maxmind_database.rb +4 -4
- data/lib/tasks/geocoder.rake +29 -4
- metadata +56 -159
- data/.gitignore +0 -6
- data/.travis.yml +0 -31
- data/Rakefile +0 -25
- data/gemfiles/Gemfile.mongoid-2.4.x +0 -16
- data/lib/geocoder/lookups/geocoder_us.rb +0 -39
- data/lib/geocoder/lookups/okf.rb +0 -43
- data/lib/geocoder/lookups/ovi.rb +0 -62
- data/lib/geocoder/lookups/yahoo.rb +0 -88
- data/lib/geocoder/results/geocoder_us.rb +0 -39
- data/lib/geocoder/results/okf.rb +0 -106
- data/lib/geocoder/results/ovi.rb +0 -62
- data/lib/geocoder/results/yahoo.rb +0 -55
- data/lib/oauth_util.rb +0 -112
- data/test/fixtures/baidu_invalid_key +0 -1
- data/test/fixtures/baidu_ip_202_198_16_3 +0 -19
- data/test/fixtures/baidu_ip_invalid_key +0 -1
- data/test/fixtures/baidu_ip_no_results +0 -1
- data/test/fixtures/baidu_no_results +0 -1
- data/test/fixtures/baidu_reverse +0 -1
- data/test/fixtures/baidu_shanghai_pearl_tower +0 -12
- data/test/fixtures/bing_invalid_key +0 -1
- data/test/fixtures/bing_madison_square_garden +0 -40
- data/test/fixtures/bing_no_results +0 -16
- data/test/fixtures/bing_reverse +0 -42
- data/test/fixtures/cloudmade_invalid_key +0 -1
- data/test/fixtures/cloudmade_madison_square_garden +0 -1
- data/test/fixtures/cloudmade_no_results +0 -1
- data/test/fixtures/esri_madison_square_garden +0 -59
- data/test/fixtures/esri_no_results +0 -8
- data/test/fixtures/esri_reverse +0 -21
- data/test/fixtures/freegeoip_74_200_247_59 +0 -12
- data/test/fixtures/freegeoip_no_results +0 -1
- data/test/fixtures/geocoder_ca_madison_square_garden +0 -1
- data/test/fixtures/geocoder_ca_no_results +0 -1
- data/test/fixtures/geocoder_ca_reverse +0 -34
- data/test/fixtures/geocoder_us_madison_square_garden +0 -1
- data/test/fixtures/geocoder_us_no_results +0 -1
- data/test/fixtures/geocodio_1101_pennsylvania_ave +0 -1
- data/test/fixtures/geocodio_bad_api_key +0 -3
- data/test/fixtures/geocodio_invalid +0 -4
- data/test/fixtures/geocodio_no_results +0 -1
- data/test/fixtures/geocodio_over_query_limit +0 -4
- data/test/fixtures/google_garbage +0 -456
- data/test/fixtures/google_madison_square_garden +0 -57
- data/test/fixtures/google_no_city_data +0 -44
- data/test/fixtures/google_no_locality +0 -51
- data/test/fixtures/google_no_results +0 -4
- data/test/fixtures/google_over_limit +0 -4
- data/test/fixtures/google_places_details_invalid_request +0 -4
- data/test/fixtures/google_places_details_madison_square_garden +0 -120
- data/test/fixtures/google_places_details_no_results +0 -4
- data/test/fixtures/google_places_details_no_reviews +0 -60
- data/test/fixtures/google_places_details_no_types +0 -66
- data/test/fixtures/here_madison_square_garden +0 -72
- data/test/fixtures/here_no_results +0 -8
- data/test/fixtures/mapquest_error +0 -16
- data/test/fixtures/mapquest_invalid_api_key +0 -16
- data/test/fixtures/mapquest_invalid_request +0 -16
- data/test/fixtures/mapquest_madison_square_garden +0 -52
- data/test/fixtures/mapquest_no_results +0 -16
- data/test/fixtures/maxmind_24_24_24_21 +0 -1
- data/test/fixtures/maxmind_24_24_24_22 +0 -1
- data/test/fixtures/maxmind_24_24_24_23 +0 -1
- data/test/fixtures/maxmind_24_24_24_24 +0 -1
- data/test/fixtures/maxmind_74_200_247_59 +0 -1
- data/test/fixtures/maxmind_invalid_key +0 -1
- data/test/fixtures/maxmind_no_results +0 -1
- data/test/fixtures/nominatim_madison_square_garden +0 -150
- data/test/fixtures/nominatim_no_results +0 -1
- data/test/fixtures/nominatim_over_limit +0 -1
- data/test/fixtures/okf_kirstinmaki +0 -67
- data/test/fixtures/okf_no_results +0 -4
- data/test/fixtures/opencagedata_invalid_api_key +0 -25
- data/test/fixtures/opencagedata_invalid_request +0 -26
- data/test/fixtures/opencagedata_madison_square_garden +0 -73
- data/test/fixtures/opencagedata_no_results +0 -29
- data/test/fixtures/opencagedata_over_limit +0 -31
- data/test/fixtures/ovi_madison_square_garden +0 -72
- data/test/fixtures/ovi_no_results +0 -8
- data/test/fixtures/pointpin_10_10_10_10 +0 -1
- data/test/fixtures/pointpin_555_555_555_555 +0 -1
- data/test/fixtures/pointpin_80_111_555_555 +0 -1
- data/test/fixtures/pointpin_no_results +0 -1
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_WR26NJ +0 -1
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_generic_error +0 -1
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_hampshire +0 -1
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_key_limit_exceeded +0 -1
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_no_results +0 -1
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_romsey +0 -1
- data/test/fixtures/postcode_anywhere_uk_geocode_v2_00_unknown_key +0 -1
- data/test/fixtures/smarty_streets_11211 +0 -1
- data/test/fixtures/smarty_streets_madison_square_garden +0 -47
- data/test/fixtures/smarty_streets_no_results +0 -1
- data/test/fixtures/telize_10_10_10_10 +0 -1
- data/test/fixtures/telize_555_555_555_555 +0 -4
- data/test/fixtures/telize_74_200_247_59 +0 -1
- data/test/fixtures/telize_no_results +0 -1
- data/test/fixtures/yahoo_error +0 -1
- data/test/fixtures/yahoo_invalid_key +0 -2
- data/test/fixtures/yahoo_madison_square_garden +0 -52
- data/test/fixtures/yahoo_no_results +0 -10
- data/test/fixtures/yahoo_over_limit +0 -2
- data/test/fixtures/yandex_canada_rue_dupuis_14 +0 -446
- data/test/fixtures/yandex_invalid_key +0 -1
- data/test/fixtures/yandex_kremlin +0 -48
- data/test/fixtures/yandex_new_york +0 -1
- data/test/fixtures/yandex_no_city_and_town +0 -112
- data/test/fixtures/yandex_no_results +0 -16
- data/test/integration/http_client_test.rb +0 -31
- data/test/mongoid_test_helper.rb +0 -43
- data/test/test_helper.rb +0 -416
- data/test/unit/active_record_test.rb +0 -16
- data/test/unit/cache_test.rb +0 -37
- data/test/unit/calculations_test.rb +0 -220
- data/test/unit/configuration_test.rb +0 -55
- data/test/unit/error_handling_test.rb +0 -56
- data/test/unit/geocoder_test.rb +0 -78
- data/test/unit/https_test.rb +0 -17
- data/test/unit/ip_address_test.rb +0 -27
- data/test/unit/lookup_test.rb +0 -153
- data/test/unit/lookups/bing_test.rb +0 -68
- data/test/unit/lookups/dstk_test.rb +0 -26
- data/test/unit/lookups/esri_test.rb +0 -48
- data/test/unit/lookups/freegeoip_test.rb +0 -27
- data/test/unit/lookups/geocoder_ca_test.rb +0 -17
- data/test/unit/lookups/geocodio_test.rb +0 -55
- data/test/unit/lookups/geoip2_test.rb +0 -27
- data/test/unit/lookups/google_places_details_test.rb +0 -122
- data/test/unit/lookups/google_premier_test.rb +0 -22
- data/test/unit/lookups/google_test.rb +0 -84
- data/test/unit/lookups/mapquest_test.rb +0 -60
- data/test/unit/lookups/maxmind_local_test.rb +0 -28
- data/test/unit/lookups/maxmind_test.rb +0 -63
- data/test/unit/lookups/nominatim_test.rb +0 -31
- data/test/unit/lookups/okf_test.rb +0 -38
- data/test/unit/lookups/opencagedata_test.rb +0 -64
- data/test/unit/lookups/pointpin_test.rb +0 -30
- data/test/unit/lookups/postcode_anywhere_uk_test.rb +0 -70
- data/test/unit/lookups/smarty_streets_test.rb +0 -71
- data/test/unit/lookups/telize_test.rb +0 -36
- data/test/unit/lookups/yahoo_test.rb +0 -35
- data/test/unit/method_aliases_test.rb +0 -26
- data/test/unit/model_test.rb +0 -38
- data/test/unit/mongoid_test.rb +0 -47
- data/test/unit/near_test.rb +0 -87
- data/test/unit/oauth_util_test.rb +0 -31
- data/test/unit/proxy_test.rb +0 -37
- data/test/unit/query_test.rb +0 -52
- data/test/unit/rake_task_test.rb +0 -21
- data/test/unit/request_test.rb +0 -35
- data/test/unit/result_test.rb +0 -72
- 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.
|
13
|
+
@store.get(url)
|
12
14
|
end
|
13
15
|
|
14
16
|
def []=(url, value)
|
15
|
-
@store.
|
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
|
-
#
|
3
|
-
# :
|
4
|
-
# :
|
5
|
-
# :
|
6
|
-
# :
|
7
|
-
# :
|
8
|
-
# :
|
9
|
-
# :
|
10
|
-
# :
|
11
|
-
# :
|
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
|
-
#
|
14
|
+
# Exceptions that should not be rescued by default
|
14
15
|
# (if you want to implement custom error handling);
|
15
|
-
# supports SocketError and
|
16
|
-
# :
|
16
|
+
# supports SocketError and Timeout::Error
|
17
|
+
# always_raise: [],
|
17
18
|
|
18
|
-
#
|
19
|
-
# :
|
20
|
-
# :
|
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
|
|
data/lib/geocoder/cache.rb
CHANGED
@@ -40,7 +40,11 @@ module Geocoder
|
|
40
40
|
#
|
41
41
|
def expire(url)
|
42
42
|
if url == :all
|
43
|
-
|
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
|
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,
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
["
|
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] = :
|
90
|
-
@data[:ip_lookup] = :
|
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
|
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
|
data/lib/geocoder/exceptions.rb
CHANGED
@@ -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
|
data/lib/geocoder/ip_address.rb
CHANGED
@@ -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
|
-
|
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
|