geocoder 1.5.1 → 1.7.3
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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +65 -0
- data/LICENSE +1 -1
- data/README.md +333 -238
- data/bin/console +13 -0
- data/lib/easting_northing.rb +171 -0
- data/lib/generators/geocoder/config/templates/initializer.rb +7 -1
- data/lib/geocoder/cache.rb +16 -33
- data/lib/geocoder/cache_stores/base.rb +40 -0
- data/lib/geocoder/cache_stores/generic.rb +35 -0
- data/lib/geocoder/cache_stores/redis.rb +34 -0
- data/lib/geocoder/configuration.rb +11 -4
- data/lib/geocoder/configuration_hash.rb +4 -4
- data/lib/geocoder/ip_address.rb +8 -1
- data/lib/geocoder/lookup.rb +21 -3
- data/lib/geocoder/lookups/abstract_api.rb +46 -0
- data/lib/geocoder/lookups/amazon_location_service.rb +54 -0
- data/lib/geocoder/lookups/ban_data_gouv_fr.rb +14 -1
- data/lib/geocoder/lookups/base.rb +10 -2
- data/lib/geocoder/lookups/bing.rb +1 -1
- data/lib/geocoder/lookups/esri.rb +6 -0
- data/lib/geocoder/lookups/freegeoip.rb +4 -4
- data/lib/geocoder/lookups/geoapify.rb +72 -0
- data/lib/geocoder/lookups/geocodio.rb +1 -1
- data/lib/geocoder/lookups/geoip2.rb +4 -0
- data/lib/geocoder/lookups/google.rb +7 -2
- data/lib/geocoder/lookups/google_places_details.rb +8 -14
- data/lib/geocoder/lookups/google_places_search.rb +28 -2
- data/lib/geocoder/lookups/google_premier.rb +4 -0
- data/lib/geocoder/lookups/here.rb +7 -16
- data/lib/geocoder/lookups/ip2location.rb +10 -14
- data/lib/geocoder/lookups/ipdata_co.rb +1 -1
- data/lib/geocoder/lookups/ipgeolocation.rb +51 -0
- data/lib/geocoder/lookups/ipqualityscore.rb +50 -0
- data/lib/geocoder/lookups/ipregistry.rb +68 -0
- data/lib/geocoder/lookups/latlon.rb +1 -2
- data/lib/geocoder/lookups/maxmind_local.rb +7 -1
- data/lib/geocoder/lookups/melissa_street.rb +41 -0
- data/lib/geocoder/lookups/nationaal_georegister_nl.rb +38 -0
- data/lib/geocoder/lookups/osmnames.rb +57 -0
- data/lib/geocoder/lookups/photon.rb +89 -0
- data/lib/geocoder/lookups/pickpoint.rb +1 -1
- data/lib/geocoder/lookups/smarty_streets.rb +6 -1
- data/lib/geocoder/lookups/telize.rb +1 -1
- data/lib/geocoder/lookups/tencent.rb +9 -9
- data/lib/geocoder/lookups/test.rb +4 -0
- data/lib/geocoder/lookups/uk_ordnance_survey_names.rb +59 -0
- data/lib/geocoder/lookups/yandex.rb +3 -4
- data/lib/geocoder/results/abstract_api.rb +146 -0
- data/lib/geocoder/results/amazon_location_service.rb +57 -0
- data/lib/geocoder/results/baidu.rb +0 -4
- data/lib/geocoder/results/ban_data_gouv_fr.rb +27 -2
- data/lib/geocoder/results/db_ip_com.rb +1 -1
- data/lib/geocoder/results/esri.rb +5 -2
- data/lib/geocoder/results/geoapify.rb +179 -0
- data/lib/geocoder/results/here.rb +4 -1
- data/lib/geocoder/results/ipgeolocation.rb +59 -0
- data/lib/geocoder/results/ipqualityscore.rb +54 -0
- data/lib/geocoder/results/ipregistry.rb +304 -0
- data/lib/geocoder/results/mapbox.rb +10 -4
- data/lib/geocoder/results/melissa_street.rb +46 -0
- data/lib/geocoder/results/nationaal_georegister_nl.rb +62 -0
- data/lib/geocoder/results/nominatim.rb +27 -15
- data/lib/geocoder/results/osmnames.rb +56 -0
- data/lib/geocoder/results/photon.rb +119 -0
- data/lib/geocoder/results/uk_ordnance_survey_names.rb +59 -0
- data/lib/geocoder/results/yandex.rb +217 -59
- data/lib/geocoder/sql.rb +4 -4
- data/lib/geocoder/util.rb +29 -0
- data/lib/geocoder/version.rb +1 -1
- data/lib/maxmind_database.rb +3 -3
- metadata +35 -18
- data/examples/autoexpire_cache_dalli.rb +0 -62
- data/examples/autoexpire_cache_redis.rb +0 -28
- data/lib/geocoder/lookups/geocoder_us.rb +0 -51
- data/lib/geocoder/results/geocoder_us.rb +0 -39
- data/lib/hash_recursive_merge.rb +0 -74
data/bin/console
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'geocoder'
|
5
|
+
|
6
|
+
if File.exist?("api_keys.yml")
|
7
|
+
require 'yaml'
|
8
|
+
@api_keys = YAML.load(File.read("api_keys.yml"), symbolize_names: true)
|
9
|
+
Geocoder.configure(@api_keys)
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'irb'
|
13
|
+
IRB.start
|
@@ -0,0 +1,171 @@
|
|
1
|
+
module Geocoder
|
2
|
+
class EastingNorthing
|
3
|
+
attr_reader :easting, :northing, :lat_lng
|
4
|
+
|
5
|
+
def initialize(opts)
|
6
|
+
@easting = opts[:easting]
|
7
|
+
@northing = opts[:northing]
|
8
|
+
|
9
|
+
@lat_lng = to_WGS84(to_osgb_36)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def to_osgb_36
|
15
|
+
osgb_fo = 0.9996012717
|
16
|
+
northing0 = -100_000.0
|
17
|
+
easting0 = 400_000.0
|
18
|
+
phi0 = deg_to_rad(49.0)
|
19
|
+
lambda0 = deg_to_rad(-2.0)
|
20
|
+
a = 6_377_563.396
|
21
|
+
b = 6_356_256.909
|
22
|
+
eSquared = ((a * a) - (b * b)) / (a * a)
|
23
|
+
phi = 0.0
|
24
|
+
lambda = 0.0
|
25
|
+
n = (a - b) / (a + b)
|
26
|
+
m = 0.0
|
27
|
+
phiPrime = ((northing - northing0) / (a * osgb_fo)) + phi0
|
28
|
+
|
29
|
+
while (northing - northing0 - m) >= 0.001
|
30
|
+
m =
|
31
|
+
(b * osgb_fo)\
|
32
|
+
* (((1 + n + ((5.0 / 4.0) * n * n) + ((5.0 / 4.0) * n * n * n))\
|
33
|
+
* (phiPrime - phi0))\
|
34
|
+
- (((3 * n) + (3 * n * n) + ((21.0 / 8.0) * n * n * n))\
|
35
|
+
* Math.sin(phiPrime - phi0)\
|
36
|
+
* Math.cos(phiPrime + phi0))\
|
37
|
+
+ ((((15.0 / 8.0) * n * n) + ((15.0 / 8.0) * n * n * n))\
|
38
|
+
* Math.sin(2.0 * (phiPrime - phi0))\
|
39
|
+
* Math.cos(2.0 * (phiPrime + phi0)))\
|
40
|
+
- (((35.0 / 24.0) * n * n * n)\
|
41
|
+
* Math.sin(3.0 * (phiPrime - phi0))\
|
42
|
+
* Math.cos(3.0 * (phiPrime + phi0))))
|
43
|
+
|
44
|
+
phiPrime += (northing - northing0 - m) / (a * osgb_fo)
|
45
|
+
end
|
46
|
+
|
47
|
+
v = a * osgb_fo * ((1.0 - eSquared * sin_pow_2(phiPrime))**-0.5)
|
48
|
+
rho =
|
49
|
+
a\
|
50
|
+
* osgb_fo\
|
51
|
+
* (1.0 - eSquared)\
|
52
|
+
* ((1.0 - eSquared * sin_pow_2(phiPrime))**-1.5)
|
53
|
+
etaSquared = (v / rho) - 1.0
|
54
|
+
vii = Math.tan(phiPrime) / (2 * rho * v)
|
55
|
+
viii =
|
56
|
+
(Math.tan(phiPrime) / (24.0 * rho * (v**3.0)))\
|
57
|
+
* (5.0\
|
58
|
+
+ (3.0 * tan_pow_2(phiPrime))\
|
59
|
+
+ etaSquared\
|
60
|
+
- (9.0 * tan_pow_2(phiPrime) * etaSquared))
|
61
|
+
ix =
|
62
|
+
(Math.tan(phiPrime) / (720.0 * rho * (v**5.0)))\
|
63
|
+
* (61.0\
|
64
|
+
+ (90.0 * tan_pow_2(phiPrime))\
|
65
|
+
+ (45.0 * tan_pow_2(phiPrime) * tan_pow_2(phiPrime)))
|
66
|
+
x = sec(phiPrime) / v
|
67
|
+
xi =
|
68
|
+
(sec(phiPrime) / (6.0 * v * v * v))\
|
69
|
+
* ((v / rho) + (2 * tan_pow_2(phiPrime)))
|
70
|
+
xiii =
|
71
|
+
(sec(phiPrime) / (120.0 * (v**5.0)))\
|
72
|
+
* (5.0\
|
73
|
+
+ (28.0 * tan_pow_2(phiPrime))\
|
74
|
+
+ (24.0 * tan_pow_2(phiPrime) * tan_pow_2(phiPrime)))
|
75
|
+
xiia =
|
76
|
+
(sec(phiPrime) / (5040.0 * (v**7.0)))\
|
77
|
+
* (61.0\
|
78
|
+
+ (662.0 * tan_pow_2(phiPrime))\
|
79
|
+
+ (1320.0 * tan_pow_2(phiPrime) * tan_pow_2(phiPrime))\
|
80
|
+
+ (720.0\
|
81
|
+
* tan_pow_2(phiPrime)\
|
82
|
+
* tan_pow_2(phiPrime)\
|
83
|
+
* tan_pow_2(phiPrime)))
|
84
|
+
phi =
|
85
|
+
phiPrime\
|
86
|
+
- (vii * ((easting - easting0)**2.0))\
|
87
|
+
+ (viii * ((easting - easting0)**4.0))\
|
88
|
+
- (ix * ((easting - easting0)**6.0))
|
89
|
+
lambda =
|
90
|
+
lambda0\
|
91
|
+
+ (x * (easting - easting0))\
|
92
|
+
- (xi * ((easting - easting0)**3.0))\
|
93
|
+
+ (xiii * ((easting - easting0)**5.0))\
|
94
|
+
- (xiia * ((easting - easting0)**7.0))
|
95
|
+
|
96
|
+
[rad_to_deg(phi), rad_to_deg(lambda)]
|
97
|
+
end
|
98
|
+
|
99
|
+
def to_WGS84(latlng)
|
100
|
+
latitude = latlng[0]
|
101
|
+
longitude = latlng[1]
|
102
|
+
|
103
|
+
a = 6_377_563.396
|
104
|
+
b = 6_356_256.909
|
105
|
+
eSquared = ((a * a) - (b * b)) / (a * a)
|
106
|
+
|
107
|
+
phi = deg_to_rad(latitude)
|
108
|
+
lambda = deg_to_rad(longitude)
|
109
|
+
v = a / Math.sqrt(1 - eSquared * sin_pow_2(phi))
|
110
|
+
h = 0
|
111
|
+
x = (v + h) * Math.cos(phi) * Math.cos(lambda)
|
112
|
+
y = (v + h) * Math.cos(phi) * Math.sin(lambda)
|
113
|
+
z = ((1 - eSquared) * v + h) * Math.sin(phi)
|
114
|
+
|
115
|
+
tx = 446.448
|
116
|
+
ty = -124.157
|
117
|
+
tz = 542.060
|
118
|
+
|
119
|
+
s = -0.0000204894
|
120
|
+
rx = deg_to_rad(0.00004172222)
|
121
|
+
ry = deg_to_rad(0.00006861111)
|
122
|
+
rz = deg_to_rad(0.00023391666)
|
123
|
+
|
124
|
+
xB = tx + (x * (1 + s)) + (-rx * y) + (ry * z)
|
125
|
+
yB = ty + (rz * x) + (y * (1 + s)) + (-rx * z)
|
126
|
+
zB = tz + (-ry * x) + (rx * y) + (z * (1 + s))
|
127
|
+
|
128
|
+
a = 6_378_137.000
|
129
|
+
b = 6_356_752.3141
|
130
|
+
eSquared = ((a * a) - (b * b)) / (a * a)
|
131
|
+
|
132
|
+
lambdaB = rad_to_deg(Math.atan(yB / xB))
|
133
|
+
p = Math.sqrt((xB * xB) + (yB * yB))
|
134
|
+
phiN = Math.atan(zB / (p * (1 - eSquared)))
|
135
|
+
|
136
|
+
(1..10).each do |_i|
|
137
|
+
v = a / Math.sqrt(1 - eSquared * sin_pow_2(phiN))
|
138
|
+
phiN1 = Math.atan((zB + (eSquared * v * Math.sin(phiN))) / p)
|
139
|
+
phiN = phiN1
|
140
|
+
end
|
141
|
+
|
142
|
+
phiB = rad_to_deg(phiN)
|
143
|
+
|
144
|
+
[phiB, lambdaB]
|
145
|
+
end
|
146
|
+
|
147
|
+
def deg_to_rad(degrees)
|
148
|
+
degrees / 180.0 * Math::PI
|
149
|
+
end
|
150
|
+
|
151
|
+
def rad_to_deg(r)
|
152
|
+
(r / Math::PI) * 180
|
153
|
+
end
|
154
|
+
|
155
|
+
def sin_pow_2(x)
|
156
|
+
Math.sin(x) * Math.sin(x)
|
157
|
+
end
|
158
|
+
|
159
|
+
def cos_pow_2(x)
|
160
|
+
Math.cos(x) * Math.cos(x)
|
161
|
+
end
|
162
|
+
|
163
|
+
def tan_pow_2(x)
|
164
|
+
Math.tan(x) * Math.tan(x)
|
165
|
+
end
|
166
|
+
|
167
|
+
def sec(x)
|
168
|
+
1.0 / Math.cos(x)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -9,7 +9,7 @@ Geocoder.configure(
|
|
9
9
|
# https_proxy: nil, # HTTPS proxy server (user:pass@host:port)
|
10
10
|
# api_key: nil, # API key for geocoding service
|
11
11
|
# cache: nil, # cache object (must respond to #[], #[]=, and #del)
|
12
|
-
# cache_prefix: 'geocoder:', #
|
12
|
+
# cache_prefix: 'geocoder:', # DEPRECATED, please use cache_options[:prefix] instead
|
13
13
|
|
14
14
|
# Exceptions that should not be rescued by default
|
15
15
|
# (if you want to implement custom error handling);
|
@@ -19,4 +19,10 @@ Geocoder.configure(
|
|
19
19
|
# Calculation options
|
20
20
|
# units: :mi, # :km for kilometers or :mi for miles
|
21
21
|
# distances: :linear # :spherical or :linear
|
22
|
+
|
23
|
+
# Cache configuration
|
24
|
+
# cache_options: {
|
25
|
+
# expiration: 2.days,
|
26
|
+
# prefix: 'geocoder:'
|
27
|
+
# }
|
22
28
|
)
|
data/lib/geocoder/cache.rb
CHANGED
@@ -1,37 +1,29 @@
|
|
1
|
+
Dir["#{__dir__}/cache_stores/*.rb"].each {|file| require file }
|
2
|
+
|
1
3
|
module Geocoder
|
2
4
|
class Cache
|
3
5
|
|
4
|
-
def initialize(store,
|
5
|
-
@
|
6
|
-
@
|
6
|
+
def initialize(store, config)
|
7
|
+
@class = (Object.const_get("Geocoder::CacheStore::#{store.class}") rescue Geocoder::CacheStore::Generic)
|
8
|
+
@store_service = @class.new(store, config)
|
7
9
|
end
|
8
10
|
|
9
11
|
##
|
10
12
|
# Read from the Cache.
|
11
13
|
#
|
12
14
|
def [](url)
|
13
|
-
interpret
|
14
|
-
|
15
|
-
|
16
|
-
when store.respond_to?(:get)
|
17
|
-
store.get key_for(url)
|
18
|
-
when store.respond_to?(:read)
|
19
|
-
store.read key_for(url)
|
20
|
-
end
|
15
|
+
interpret store_service.read(url)
|
16
|
+
rescue => e
|
17
|
+
warn "Geocoder cache read error: #{e}"
|
21
18
|
end
|
22
19
|
|
23
20
|
##
|
24
21
|
# Write to the Cache.
|
25
22
|
#
|
26
23
|
def []=(url, value)
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
when store.respond_to?(:set)
|
31
|
-
store.set key_for(url), value
|
32
|
-
when store.respond_to?(:write)
|
33
|
-
store.write key_for(url), value
|
34
|
-
end
|
24
|
+
store_service.write(url, value)
|
25
|
+
rescue => e
|
26
|
+
warn "Geocoder cache write error: #{e}"
|
35
27
|
end
|
36
28
|
|
37
29
|
##
|
@@ -40,7 +32,7 @@ module Geocoder
|
|
40
32
|
#
|
41
33
|
def expire(url)
|
42
34
|
if url == :all
|
43
|
-
if
|
35
|
+
if store_service.respond_to?(:keys)
|
44
36
|
urls.each{ |u| expire(u) }
|
45
37
|
else
|
46
38
|
raise(NoMethodError, "The Geocoder cache store must implement `#keys` for `expire(:all)` to work")
|
@@ -53,29 +45,21 @@ module Geocoder
|
|
53
45
|
|
54
46
|
private # ----------------------------------------------------------------
|
55
47
|
|
56
|
-
def
|
57
|
-
def store; @store; end
|
58
|
-
|
59
|
-
##
|
60
|
-
# Cache key for a given URL.
|
61
|
-
#
|
62
|
-
def key_for(url)
|
63
|
-
[prefix, url].join
|
64
|
-
end
|
48
|
+
def store_service; @store_service; end
|
65
49
|
|
66
50
|
##
|
67
51
|
# Array of keys with the currently configured prefix
|
68
52
|
# that have non-nil values.
|
69
53
|
#
|
70
54
|
def keys
|
71
|
-
|
55
|
+
store_service.keys
|
72
56
|
end
|
73
57
|
|
74
58
|
##
|
75
59
|
# Array of cached URLs.
|
76
60
|
#
|
77
61
|
def urls
|
78
|
-
|
62
|
+
store_service.urls
|
79
63
|
end
|
80
64
|
|
81
65
|
##
|
@@ -87,8 +71,7 @@ module Geocoder
|
|
87
71
|
end
|
88
72
|
|
89
73
|
def expire_single_url(url)
|
90
|
-
|
91
|
-
store.respond_to?(:del) ? store.del(key) : store.delete(key)
|
74
|
+
store_service.remove(url)
|
92
75
|
end
|
93
76
|
end
|
94
77
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Geocoder::CacheStore
|
2
|
+
class Base
|
3
|
+
def initialize(store, options)
|
4
|
+
@store = store
|
5
|
+
@config = options
|
6
|
+
@prefix = config[:prefix]
|
7
|
+
end
|
8
|
+
|
9
|
+
##
|
10
|
+
# Array of keys with the currently configured prefix
|
11
|
+
# that have non-nil values.
|
12
|
+
def keys
|
13
|
+
store.keys.select { |k| k.match(/^#{prefix}/) and self[k] }
|
14
|
+
end
|
15
|
+
|
16
|
+
##
|
17
|
+
# Array of cached URLs.
|
18
|
+
#
|
19
|
+
def urls
|
20
|
+
keys
|
21
|
+
end
|
22
|
+
|
23
|
+
protected # ----------------------------------------------------------------
|
24
|
+
|
25
|
+
def prefix; @prefix; end
|
26
|
+
def store; @store; end
|
27
|
+
def config; @config; end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Cache key for a given URL.
|
31
|
+
#
|
32
|
+
def key_for(url)
|
33
|
+
if url.match(/^#{prefix}/)
|
34
|
+
url
|
35
|
+
else
|
36
|
+
[prefix, url].join
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'geocoder/cache_stores/base'
|
2
|
+
|
3
|
+
module Geocoder::CacheStore
|
4
|
+
class Generic < Base
|
5
|
+
def write(url, value)
|
6
|
+
case
|
7
|
+
when store.respond_to?(:[]=)
|
8
|
+
store[key_for(url)] = value
|
9
|
+
when store.respond_to?(:set)
|
10
|
+
store.set key_for(url), value
|
11
|
+
when store.respond_to?(:write)
|
12
|
+
store.write key_for(url), value
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def read(url)
|
17
|
+
case
|
18
|
+
when store.respond_to?(:[])
|
19
|
+
store[key_for(url)]
|
20
|
+
when store.respond_to?(:get)
|
21
|
+
store.get key_for(url)
|
22
|
+
when store.respond_to?(:read)
|
23
|
+
store.read key_for(url)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def keys
|
28
|
+
store.keys
|
29
|
+
end
|
30
|
+
|
31
|
+
def remove(key)
|
32
|
+
store.delete(key)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'geocoder/cache_stores/base'
|
2
|
+
|
3
|
+
module Geocoder::CacheStore
|
4
|
+
class Redis < Base
|
5
|
+
def initialize(store, options)
|
6
|
+
super
|
7
|
+
@expiration = options[:expiration]
|
8
|
+
end
|
9
|
+
|
10
|
+
def write(url, value, expire = @expiration)
|
11
|
+
if expire.present?
|
12
|
+
store.set key_for(url), value, ex: expire
|
13
|
+
else
|
14
|
+
store.set key_for(url), value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def read(url)
|
19
|
+
store.get key_for(url)
|
20
|
+
end
|
21
|
+
|
22
|
+
def keys
|
23
|
+
store.keys("#{prefix}*")
|
24
|
+
end
|
25
|
+
|
26
|
+
def remove(key)
|
27
|
+
store.del(key)
|
28
|
+
end
|
29
|
+
|
30
|
+
private # ----------------------------------------------------------------
|
31
|
+
|
32
|
+
def expire; @expiration; end
|
33
|
+
end
|
34
|
+
end
|
@@ -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
|
|
@@ -54,6 +55,7 @@ module Geocoder
|
|
54
55
|
:lookup,
|
55
56
|
:ip_lookup,
|
56
57
|
:language,
|
58
|
+
:host,
|
57
59
|
:http_headers,
|
58
60
|
:use_https,
|
59
61
|
:http_proxy,
|
@@ -66,7 +68,8 @@ module Geocoder
|
|
66
68
|
:distances,
|
67
69
|
:basic_auth,
|
68
70
|
:logger,
|
69
|
-
:kernel_logger_level
|
71
|
+
:kernel_logger_level,
|
72
|
+
:cache_options
|
70
73
|
]
|
71
74
|
|
72
75
|
attr_accessor :data
|
@@ -85,7 +88,7 @@ module Geocoder
|
|
85
88
|
end
|
86
89
|
|
87
90
|
def configure(options)
|
88
|
-
@data
|
91
|
+
Util.recursive_hash_merge(@data, options)
|
89
92
|
end
|
90
93
|
|
91
94
|
def initialize # :nodoc
|
@@ -105,8 +108,8 @@ module Geocoder
|
|
105
108
|
@data[:http_proxy] = nil # HTTP proxy server (user:pass@host:port)
|
106
109
|
@data[:https_proxy] = nil # HTTPS proxy server (user:pass@host:port)
|
107
110
|
@data[:api_key] = nil # API key for geocoding service
|
108
|
-
@data[:cache] = nil # cache object (must respond to #[], #[]=, and #keys)
|
109
|
-
@data[:cache_prefix] =
|
111
|
+
@data[:cache] = nil # cache object (must respond to #[], #[]=, and optionally #keys)
|
112
|
+
@data[:cache_prefix] = nil # - DEPRECATED - prefix (string) to use for all cache keys
|
110
113
|
@data[:basic_auth] = {} # user and password for basic auth ({:user => "user", :password => "password"})
|
111
114
|
@data[:logger] = :kernel # :kernel or Logger instance
|
112
115
|
@data[:kernel_logger_level] = ::Logger::WARN # log level, if kernel logger is used
|
@@ -119,6 +122,10 @@ module Geocoder
|
|
119
122
|
# calculation options
|
120
123
|
@data[:units] = :mi # :mi or :km
|
121
124
|
@data[:distances] = :linear # :linear or :spherical
|
125
|
+
|
126
|
+
# explicit cache service options
|
127
|
+
@data[:cache_options] ||= {}
|
128
|
+
@data[:cache_options][:prefix] = "geocoder:"
|
122
129
|
end
|
123
130
|
|
124
131
|
instance_eval(OPTIONS.map do |option|
|
@@ -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
|
data/lib/geocoder/ip_address.rb
CHANGED
@@ -7,6 +7,12 @@ module Geocoder
|
|
7
7
|
'192.168.0.0/16',
|
8
8
|
].map { |ip| IPAddr.new(ip) }.freeze
|
9
9
|
|
10
|
+
def initialize(ip)
|
11
|
+
ip = ip.to_string if ip.is_a?(IPAddr)
|
12
|
+
|
13
|
+
super(ip)
|
14
|
+
end
|
15
|
+
|
10
16
|
def internal?
|
11
17
|
loopback? || private?
|
12
18
|
end
|
@@ -20,7 +26,8 @@ module Geocoder
|
|
20
26
|
end
|
21
27
|
|
22
28
|
def valid?
|
23
|
-
|
29
|
+
ip = self[/(?<=\[)(.*?)(?=\])/] || self
|
30
|
+
!!((ip =~ Resolv::IPv4::Regex) || (ip =~ Resolv::IPv6::Regex))
|
24
31
|
end
|
25
32
|
end
|
26
33
|
end
|
data/lib/geocoder/lookup.rb
CHANGED
@@ -18,6 +18,14 @@ module Geocoder
|
|
18
18
|
all_services - [:test]
|
19
19
|
end
|
20
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
|
+
|
21
29
|
##
|
22
30
|
# All street address lookup services, default first.
|
23
31
|
#
|
@@ -32,11 +40,12 @@ module Geocoder
|
|
32
40
|
:google_places_search,
|
33
41
|
:bing,
|
34
42
|
:geocoder_ca,
|
35
|
-
:geocoder_us,
|
36
43
|
:yandex,
|
44
|
+
:nationaal_georegister_nl,
|
37
45
|
:nominatim,
|
38
46
|
:mapbox,
|
39
47
|
:mapquest,
|
48
|
+
:uk_ordnance_survey_names,
|
40
49
|
:opencagedata,
|
41
50
|
:pelias,
|
42
51
|
:pickpoint,
|
@@ -51,7 +60,12 @@ module Geocoder
|
|
51
60
|
:ban_data_gouv_fr,
|
52
61
|
:test,
|
53
62
|
:latlon,
|
54
|
-
:amap
|
63
|
+
:amap,
|
64
|
+
:osmnames,
|
65
|
+
:melissa_street,
|
66
|
+
:amazon_location_service,
|
67
|
+
:geoapify,
|
68
|
+
:photon
|
55
69
|
]
|
56
70
|
end
|
57
71
|
|
@@ -61,6 +75,7 @@ module Geocoder
|
|
61
75
|
def ip_services
|
62
76
|
@ip_services ||= [
|
63
77
|
:baidu_ip,
|
78
|
+
:abstract_api,
|
64
79
|
:freegeoip,
|
65
80
|
:geoip2,
|
66
81
|
:maxmind,
|
@@ -69,11 +84,14 @@ module Geocoder
|
|
69
84
|
:pointpin,
|
70
85
|
:maxmind_geoip2,
|
71
86
|
:ipinfo_io,
|
87
|
+
:ipregistry,
|
72
88
|
:ipapi_com,
|
73
89
|
:ipdata_co,
|
74
90
|
:db_ip_com,
|
75
91
|
:ipstack,
|
76
|
-
:ip2location
|
92
|
+
:ip2location,
|
93
|
+
:ipgeolocation,
|
94
|
+
:ipqualityscore
|
77
95
|
]
|
78
96
|
end
|
79
97
|
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'geocoder/lookups/base'
|
4
|
+
require 'geocoder/results/abstract_api'
|
5
|
+
|
6
|
+
module Geocoder::Lookup
|
7
|
+
class AbstractApi < Base
|
8
|
+
|
9
|
+
def name
|
10
|
+
"Abstract API"
|
11
|
+
end
|
12
|
+
|
13
|
+
def required_api_key_parts
|
14
|
+
['api_key']
|
15
|
+
end
|
16
|
+
|
17
|
+
def supported_protocols
|
18
|
+
[:https]
|
19
|
+
end
|
20
|
+
|
21
|
+
private # ---------------------------------------------------------------
|
22
|
+
|
23
|
+
def base_query_url(query)
|
24
|
+
"#{protocol}://ipgeolocation.abstractapi.com/v1/?"
|
25
|
+
end
|
26
|
+
|
27
|
+
def query_url_params(query)
|
28
|
+
params = {api_key: configuration.api_key}
|
29
|
+
|
30
|
+
ip_address = query.sanitized_text
|
31
|
+
if ip_address.is_a?(String) && ip_address.length > 0
|
32
|
+
params[:ip_address] = ip_address
|
33
|
+
end
|
34
|
+
|
35
|
+
params.merge(super)
|
36
|
+
end
|
37
|
+
|
38
|
+
def results(query, reverse = false)
|
39
|
+
if doc = fetch_data(query)
|
40
|
+
[doc]
|
41
|
+
else
|
42
|
+
[]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'geocoder/lookups/base'
|
2
|
+
require 'geocoder/results/amazon_location_service'
|
3
|
+
|
4
|
+
module Geocoder::Lookup
|
5
|
+
class AmazonLocationService < Base
|
6
|
+
def results(query)
|
7
|
+
params = query.options.dup
|
8
|
+
|
9
|
+
# index_name is required
|
10
|
+
# Aws::ParamValidator raises ArgumentError on missing required keys
|
11
|
+
params.merge!(index_name: configuration[:index_name])
|
12
|
+
|
13
|
+
# Aws::ParamValidator raises ArgumentError on unexpected keys
|
14
|
+
params.delete(:lookup)
|
15
|
+
|
16
|
+
resp = if query.reverse_geocode?
|
17
|
+
client.search_place_index_for_position(params.merge(position: query.coordinates.reverse))
|
18
|
+
else
|
19
|
+
client.search_place_index_for_text(params.merge(text: query.text))
|
20
|
+
end
|
21
|
+
|
22
|
+
resp.results.map(&:place)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def client
|
28
|
+
return @client if @client
|
29
|
+
require_sdk
|
30
|
+
keys = configuration.api_key
|
31
|
+
if keys
|
32
|
+
@client = Aws::LocationService::Client.new(
|
33
|
+
access_key_id: keys[:access_key_id],
|
34
|
+
secret_access_key: keys[:secret_access_key],
|
35
|
+
)
|
36
|
+
else
|
37
|
+
@client = Aws::LocationService::Client.new
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def require_sdk
|
42
|
+
begin
|
43
|
+
require 'aws-sdk-locationservice'
|
44
|
+
rescue LoadError
|
45
|
+
raise_error(Geocoder::ConfigurationError) ||
|
46
|
+
Geocoder.log(
|
47
|
+
:error,
|
48
|
+
"Couldn't load the Amazon Location Service SDK. " +
|
49
|
+
"Install it with: gem install aws-sdk-locationservice -v '~> 1.4'"
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|