geocoder 1.5.1 → 1.8.5
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 +107 -0
- data/LICENSE +1 -1
- data/README.md +364 -243
- data/bin/console +13 -0
- data/examples/app_defined_lookup_services.rb +22 -0
- data/lib/easting_northing.rb +171 -0
- data/lib/generators/geocoder/config/templates/initializer.rb +6 -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 +19 -5
- data/lib/geocoder/configuration_hash.rb +4 -4
- data/lib/geocoder/ip_address.rb +11 -1
- data/lib/geocoder/lookup.rb +42 -6
- data/lib/geocoder/lookups/abstract_api.rb +46 -0
- data/lib/geocoder/lookups/amap.rb +2 -2
- data/lib/geocoder/lookups/amazon_location_service.rb +58 -0
- data/lib/geocoder/lookups/azure.rb +56 -0
- data/lib/geocoder/lookups/ban_data_gouv_fr.rb +15 -2
- data/lib/geocoder/lookups/base.rb +4 -1
- data/lib/geocoder/lookups/bing.rb +2 -2
- data/lib/geocoder/lookups/esri.rb +24 -5
- data/lib/geocoder/lookups/freegeoip.rb +12 -10
- data/lib/geocoder/lookups/geoapify.rb +78 -0
- data/lib/geocoder/lookups/geocodio.rb +1 -1
- data/lib/geocoder/lookups/geoip2.rb +4 -0
- data/lib/geocoder/lookups/geoportail_lu.rb +1 -1
- data/lib/geocoder/lookups/google.rb +7 -2
- data/lib/geocoder/lookups/google_places_details.rb +26 -12
- data/lib/geocoder/lookups/google_places_search.rb +44 -2
- data/lib/geocoder/lookups/google_premier.rb +4 -0
- data/lib/geocoder/lookups/here.rb +27 -31
- data/lib/geocoder/lookups/ip2location.rb +10 -14
- data/lib/geocoder/lookups/ip2location_io.rb +62 -0
- data/lib/geocoder/lookups/ip2location_lite.rb +40 -0
- data/lib/geocoder/lookups/ipbase.rb +49 -0
- 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/location_iq.rb +5 -1
- data/lib/geocoder/lookups/mapbox.rb +3 -3
- 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/pc_miler.rb +85 -0
- data/lib/geocoder/lookups/pdok_nl.rb +43 -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 +5 -0
- data/lib/geocoder/lookups/twogis.rb +58 -0
- data/lib/geocoder/lookups/uk_ordnance_survey_names.rb +59 -0
- data/lib/geocoder/lookups/yandex.rb +6 -7
- data/lib/geocoder/query.rb +1 -1
- data/lib/geocoder/results/abstract_api.rb +146 -0
- data/lib/geocoder/results/amazon_location_service.rb +62 -0
- data/lib/geocoder/results/azure.rb +65 -0
- data/lib/geocoder/results/baidu.rb +0 -4
- data/lib/geocoder/results/ban_data_gouv_fr.rb +28 -3
- 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 +20 -22
- data/lib/geocoder/results/ip2location_io.rb +21 -0
- data/lib/geocoder/results/ip2location_lite.rb +47 -0
- data/lib/geocoder/results/ipbase.rb +40 -0
- 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 +34 -10
- 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/pc_miler.rb +98 -0
- data/lib/geocoder/results/pdok_nl.rb +62 -0
- data/lib/geocoder/results/photon.rb +119 -0
- data/lib/geocoder/results/twogis.rb +76 -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 +12 -12
- data/lib/tasks/maxmind.rake +1 -1
- metadata +81 -23
- data/examples/autoexpire_cache_dalli.rb +0 -62
- data/examples/autoexpire_cache_redis.rb +0 -28
- data/lib/geocoder/lookups/dstk.rb +0 -22
- data/lib/geocoder/lookups/geocoder_us.rb +0 -51
- data/lib/geocoder/results/dstk.rb +0 -6
- 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,22 @@
|
|
1
|
+
# To extend the Geocoder with additional lookups that come from the application,
|
2
|
+
# not shipped with the gem, define a "child" lookup in your application, based on existing one.
|
3
|
+
# This is required because the Geocoder::Configuration is a Singleton and stores one api key per lookup.
|
4
|
+
|
5
|
+
# in app/libs/geocoder/lookup/my_preciousss.rb
|
6
|
+
module Geocoder::Lookup
|
7
|
+
class MyPreciousss < Google
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# Update Geocoder's street_services on initialize:
|
12
|
+
# config/initializers/geocoder.rb
|
13
|
+
Geocoder::Lookup.street_services << :my_preciousss
|
14
|
+
|
15
|
+
# Override the configuration when necessary (e.g. provide separate Google API key for the account):
|
16
|
+
Geocoder.configure(my_preciousss: { api_key: 'abcdef' })
|
17
|
+
|
18
|
+
# Lastly, search using your custom lookup service/api keys
|
19
|
+
Geocoder.search("Paris", lookup: :my_preciousss)
|
20
|
+
|
21
|
+
# This is useful when we have groups of users in the application who use Google paid services
|
22
|
+
# and we want to properly separate them and allow using individual API KEYS or timeouts.
|
@@ -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,6 @@ 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:', # prefix (string) to use for all cache keys
|
13
12
|
|
14
13
|
# Exceptions that should not be rescued by default
|
15
14
|
# (if you want to implement custom error handling);
|
@@ -19,4 +18,10 @@ Geocoder.configure(
|
|
19
18
|
# Calculation options
|
20
19
|
# units: :mi, # :km for kilometers or :mi for miles
|
21
20
|
# distances: :linear # :spherical or :linear
|
21
|
+
|
22
|
+
# Cache configuration
|
23
|
+
# cache_options: {
|
24
|
+
# expiration: 2.days,
|
25
|
+
# prefix: 'geocoder:'
|
26
|
+
# }
|
22
27
|
)
|
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 = (Geocoder::CacheStore.const_get("#{store.class}", false) 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
|
+
Geocoder.log(: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
|
+
Geocoder.log(: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,19 +55,20 @@ 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,
|
60
62
|
:https_proxy,
|
61
63
|
:api_key,
|
62
64
|
:cache,
|
63
|
-
:cache_prefix,
|
64
65
|
:always_raise,
|
65
66
|
:units,
|
66
67
|
:distances,
|
67
68
|
:basic_auth,
|
68
69
|
:logger,
|
69
|
-
:kernel_logger_level
|
70
|
+
:kernel_logger_level,
|
71
|
+
:cache_options
|
70
72
|
]
|
71
73
|
|
72
74
|
attr_accessor :data
|
@@ -75,6 +77,10 @@ module Geocoder
|
|
75
77
|
instance.set_defaults
|
76
78
|
end
|
77
79
|
|
80
|
+
def self.initialize
|
81
|
+
instance.send(:initialize)
|
82
|
+
end
|
83
|
+
|
78
84
|
OPTIONS.each do |o|
|
79
85
|
define_method o do
|
80
86
|
@data[o]
|
@@ -85,7 +91,7 @@ module Geocoder
|
|
85
91
|
end
|
86
92
|
|
87
93
|
def configure(options)
|
88
|
-
@data
|
94
|
+
Util.recursive_hash_merge(@data, options)
|
89
95
|
end
|
90
96
|
|
91
97
|
def initialize # :nodoc
|
@@ -105,8 +111,6 @@ module Geocoder
|
|
105
111
|
@data[:http_proxy] = nil # HTTP proxy server (user:pass@host:port)
|
106
112
|
@data[:https_proxy] = nil # HTTPS proxy server (user:pass@host:port)
|
107
113
|
@data[:api_key] = nil # API key for geocoding service
|
108
|
-
@data[:cache] = nil # cache object (must respond to #[], #[]=, and #keys)
|
109
|
-
@data[:cache_prefix] = "geocoder:" # prefix (string) to use for all cache keys
|
110
114
|
@data[:basic_auth] = {} # user and password for basic auth ({:user => "user", :password => "password"})
|
111
115
|
@data[:logger] = :kernel # :kernel or Logger instance
|
112
116
|
@data[:kernel_logger_level] = ::Logger::WARN # log level, if kernel logger is used
|
@@ -119,6 +123,16 @@ module Geocoder
|
|
119
123
|
# calculation options
|
120
124
|
@data[:units] = :mi # :mi or :km
|
121
125
|
@data[:distances] = :linear # :linear or :spherical
|
126
|
+
|
127
|
+
# Set the default values for the caching mechanism
|
128
|
+
# By default, the cache keys will not expire as IP addresses and phyiscal
|
129
|
+
# addresses will rarely change.
|
130
|
+
@data[:cache] = nil # cache object (must respond to #[], #[]=, and optionally #keys)
|
131
|
+
@data[:cache_prefix] = nil # - DEPRECATED - prefix (string) to use for all cache keys
|
132
|
+
@data[:cache_options] = {
|
133
|
+
prefix: 'geocoder:',
|
134
|
+
expiration: nil
|
135
|
+
}
|
122
136
|
end
|
123
137
|
|
124
138
|
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,15 @@ 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
|
+
if ip.is_a?(Hash)
|
13
|
+
super(**ip)
|
14
|
+
else
|
15
|
+
super(ip)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
10
19
|
def internal?
|
11
20
|
loopback? || private?
|
12
21
|
end
|
@@ -20,7 +29,8 @@ module Geocoder
|
|
20
29
|
end
|
21
30
|
|
22
31
|
def valid?
|
23
|
-
|
32
|
+
ip = self[/(?<=\[)(.*?)(?=\])/] || self
|
33
|
+
!!((ip =~ Resolv::IPv4::Regex) || (ip =~ Resolv::IPv6::Regex))
|
24
34
|
end
|
25
35
|
end
|
26
36
|
end
|
data/lib/geocoder/lookup.rb
CHANGED
@@ -18,13 +18,21 @@ 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, :maxmind_local, :geoip2, :ip2location_lite]
|
27
|
+
end
|
28
|
+
|
21
29
|
##
|
22
30
|
# All street address lookup services, default first.
|
23
31
|
#
|
24
32
|
def street_services
|
25
33
|
@street_services ||= [
|
26
34
|
:location_iq,
|
27
|
-
:
|
35
|
+
:azure,
|
28
36
|
:esri,
|
29
37
|
:google,
|
30
38
|
:google_premier,
|
@@ -32,13 +40,15 @@ 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,
|
51
|
+
:pdok_nl,
|
42
52
|
:pickpoint,
|
43
53
|
:here,
|
44
54
|
:baidu,
|
@@ -51,7 +61,14 @@ module Geocoder
|
|
51
61
|
:ban_data_gouv_fr,
|
52
62
|
:test,
|
53
63
|
:latlon,
|
54
|
-
:amap
|
64
|
+
:amap,
|
65
|
+
:osmnames,
|
66
|
+
:melissa_street,
|
67
|
+
:amazon_location_service,
|
68
|
+
:geoapify,
|
69
|
+
:photon,
|
70
|
+
:twogis,
|
71
|
+
:pc_miler
|
55
72
|
]
|
56
73
|
end
|
57
74
|
|
@@ -61,6 +78,7 @@ module Geocoder
|
|
61
78
|
def ip_services
|
62
79
|
@ip_services ||= [
|
63
80
|
:baidu_ip,
|
81
|
+
:abstract_api,
|
64
82
|
:freegeoip,
|
65
83
|
:geoip2,
|
66
84
|
:maxmind,
|
@@ -69,11 +87,17 @@ module Geocoder
|
|
69
87
|
:pointpin,
|
70
88
|
:maxmind_geoip2,
|
71
89
|
:ipinfo_io,
|
90
|
+
:ipregistry,
|
72
91
|
:ipapi_com,
|
73
92
|
:ipdata_co,
|
74
93
|
:db_ip_com,
|
75
94
|
:ipstack,
|
76
|
-
:ip2location
|
95
|
+
:ip2location,
|
96
|
+
:ipgeolocation,
|
97
|
+
:ipqualityscore,
|
98
|
+
:ipbase,
|
99
|
+
:ip2location_io,
|
100
|
+
:ip2location_lite
|
77
101
|
]
|
78
102
|
end
|
79
103
|
|
@@ -99,8 +123,7 @@ module Geocoder
|
|
99
123
|
def spawn(name)
|
100
124
|
if all_services.include?(name)
|
101
125
|
name = name.to_s
|
102
|
-
|
103
|
-
Geocoder::Lookup.const_get(classify_name(name)).new
|
126
|
+
instantiate_lookup(name)
|
104
127
|
else
|
105
128
|
valids = all_services.map(&:inspect).join(", ")
|
106
129
|
raise ConfigurationError, "Please specify a valid lookup for Geocoder " +
|
@@ -114,5 +137,18 @@ module Geocoder
|
|
114
137
|
def classify_name(filename)
|
115
138
|
filename.to_s.split("_").map{ |i| i[0...1].upcase + i[1..-1] }.join
|
116
139
|
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# Safely instantiate Lookup
|
143
|
+
#
|
144
|
+
def instantiate_lookup(name)
|
145
|
+
class_name = classify_name(name)
|
146
|
+
begin
|
147
|
+
Geocoder::Lookup.const_get(class_name, inherit=false)
|
148
|
+
rescue NameError
|
149
|
+
require "geocoder/lookups/#{name}"
|
150
|
+
end
|
151
|
+
Geocoder::Lookup.const_get(class_name).new
|
152
|
+
end
|
117
153
|
end
|
118
154
|
end
|