geocoder 1.7.1 → 1.8.0
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 +4 -4
- data/CHANGELOG.md +24 -0
- data/README.md +11 -6
- data/examples/app_defined_lookup_services.rb +22 -0
- data/lib/generators/geocoder/config/templates/initializer.rb +0 -1
- data/lib/geocoder/cache_stores/generic.rb +3 -1
- data/lib/geocoder/cache_stores/redis.rb +3 -1
- data/lib/geocoder/configuration.rb +9 -5
- data/lib/geocoder/lookup.rb +16 -3
- data/lib/geocoder/lookups/base.rb +1 -6
- data/lib/geocoder/lookups/freegeoip.rb +8 -6
- data/lib/geocoder/lookups/google_places_details.rb +20 -0
- data/lib/geocoder/lookups/google_places_search.rb +20 -3
- data/lib/geocoder/lookups/here.rb +25 -20
- data/lib/geocoder/lookups/location_iq.rb +5 -1
- data/lib/geocoder/lookups/twogis.rb +58 -0
- data/lib/geocoder/results/here.rb +20 -25
- data/lib/geocoder/results/nominatim.rb +24 -16
- data/lib/geocoder/results/twogis.rb +76 -0
- data/lib/geocoder/version.rb +1 -1
- metadata +5 -4
- data/examples/autoexpire_cache_dalli.rb +0 -62
- data/examples/autoexpire_cache_redis.rb +0 -30
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3a0d33121c080f317bcfcad5c3547491676b1edcef61e33cb3a090e91cccdeee
|
|
4
|
+
data.tar.gz: 066ff69c5443b18d9f5b4e1af94481b588bf18560050e0da49129b3630f5047b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3e47b46a3c299023708b9a2444315d0e9b2788cf682e7e72e1d2ae8d0be40c9d6b7cf25793f20c946f6941662c6512d86bea29bd48e81485546facf00f9cdea3
|
|
7
|
+
data.tar.gz: 0bd121ae2aa3b8e2232e343d70557a7c9201f06dc47a8ae59d5b28e8610c8627ed6beefb251020537979de472e35d0174ab5fad20994e1414914a28f3d91ba1c
|
data/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,30 @@ Changelog
|
|
|
3
3
|
|
|
4
4
|
Major changes to Geocoder for each release. Please see the Git log for complete list of changes.
|
|
5
5
|
|
|
6
|
+
1.8.0 (2022 May 17)
|
|
7
|
+
-------------------
|
|
8
|
+
* Add support for 2GIS lookup (thanks github.com/ggrikgg).
|
|
9
|
+
* Change cache configuration structure and add an expiration option. Cache prefix is now set via {cache_options: {prefix: ...}} instead of {cache_prefix: ...}. See README for details.
|
|
10
|
+
* Add `:fields` parameter for :google_places_details and :google_places_search lookups. If you haven't been requesting specific fields, you may start getting different data (defaults are now the APIs' defaults). See for details: https://github.com/alexreisner/geocoder/pull/1572 (thanks github.com/czlee).
|
|
11
|
+
* Update :here lookup to use API version 7. Query options are different, API key must be a string (not an array). See API docs at https://developer.here.com/documentation/geocoding-search-api/api-reference-swagger.html (thanks github.com/Pritilender).
|
|
12
|
+
|
|
13
|
+
1.7.5 (2022 Mar 14)
|
|
14
|
+
-------------------
|
|
15
|
+
* Avoid lookup naming collisions in some environments.
|
|
16
|
+
|
|
17
|
+
1.7.4 (2022 Mar 14)
|
|
18
|
+
-------------------
|
|
19
|
+
* Add ability to use app-defined lookups (thanks github.com/januszm).
|
|
20
|
+
* Updates to LocationIQ and FreeGeoIP lookups.
|
|
21
|
+
|
|
22
|
+
1.7.3 (2022 Jan 17)
|
|
23
|
+
-------------------
|
|
24
|
+
* Get rid of unnecessary cache_prefix deprecation warnings.
|
|
25
|
+
|
|
26
|
+
1.7.2 (2022 Jan 2)
|
|
27
|
+
-------------------
|
|
28
|
+
* Fix uninitialized constant error (occurring on some systems with v1.7.1).
|
|
29
|
+
|
|
6
30
|
1.7.1 (2022 Jan 1)
|
|
7
31
|
-------------------
|
|
8
32
|
* Various bugfixes and refactorings.
|
data/README.md
CHANGED
|
@@ -20,7 +20,7 @@ Compatibility:
|
|
|
20
20
|
|
|
21
21
|
* Ruby versions: 2.1+, and JRuby.
|
|
22
22
|
* Databases: MySQL, PostgreSQL, SQLite, and MongoDB.
|
|
23
|
-
* Rails: 5.x and
|
|
23
|
+
* Rails: 5.x, 6.x, and 7.x.
|
|
24
24
|
* Works outside of Rails with the `json` (for MRI) or `json_pure` (for JRuby) gem.
|
|
25
25
|
|
|
26
26
|
|
|
@@ -78,7 +78,7 @@ results.first.address
|
|
|
78
78
|
# => "Hôtel de Ville, 75004 Paris, France"
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
-
You can also look up the location of an IP
|
|
81
|
+
You can also look up the location of an IP address:
|
|
82
82
|
|
|
83
83
|
```ruby
|
|
84
84
|
results = Geocoder.search("172.56.21.89")
|
|
@@ -246,11 +246,10 @@ Geocoder.configure(
|
|
|
246
246
|
units: :km,
|
|
247
247
|
|
|
248
248
|
# caching (see Caching section below for details):
|
|
249
|
-
# warning: `cache_prefix` is deprecated, use `cache_options` instead
|
|
250
249
|
cache: Redis.new,
|
|
251
250
|
cache_options: {
|
|
252
|
-
expiration:
|
|
253
|
-
prefix: "
|
|
251
|
+
expiration: 1.day, # Defaults to `nil`
|
|
252
|
+
prefix: "another_key:" # Defaults to `geocoder:`
|
|
254
253
|
}
|
|
255
254
|
)
|
|
256
255
|
```
|
|
@@ -350,10 +349,16 @@ This example uses Redis, but the cache store can be any object that supports the
|
|
|
350
349
|
|
|
351
350
|
Even a plain Ruby hash will work, though it's not a great choice (cleared out when app is restarted, not shared between app instances, etc).
|
|
352
351
|
|
|
352
|
+
When using Rails use the Generic cache store as an adapter around `Rails.cache`:
|
|
353
|
+
|
|
354
|
+
```ruby
|
|
355
|
+
Geocoder.configure(cache: Geocoder::CacheStore::Generic.new(Rails.cache, {}))
|
|
356
|
+
```
|
|
357
|
+
|
|
353
358
|
You can also set a custom prefix to be used for cache keys:
|
|
354
359
|
|
|
355
360
|
```ruby
|
|
356
|
-
Geocoder.configure(
|
|
361
|
+
Geocoder.configure(cache_options: { prefix: "..." })
|
|
357
362
|
```
|
|
358
363
|
|
|
359
364
|
By default the prefix is `geocoder:`
|
|
@@ -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.
|
|
@@ -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:', # DEPRECATED, please use cache_options[:prefix] instead
|
|
13
12
|
|
|
14
13
|
# Exceptions that should not be rescued by default
|
|
15
14
|
# (if you want to implement custom error handling);
|
|
@@ -62,7 +62,6 @@ module Geocoder
|
|
|
62
62
|
:https_proxy,
|
|
63
63
|
:api_key,
|
|
64
64
|
:cache,
|
|
65
|
-
:cache_prefix,
|
|
66
65
|
:always_raise,
|
|
67
66
|
:units,
|
|
68
67
|
:distances,
|
|
@@ -108,8 +107,6 @@ module Geocoder
|
|
|
108
107
|
@data[:http_proxy] = nil # HTTP proxy server (user:pass@host:port)
|
|
109
108
|
@data[:https_proxy] = nil # HTTPS proxy server (user:pass@host:port)
|
|
110
109
|
@data[:api_key] = nil # API key for geocoding service
|
|
111
|
-
@data[:cache] = nil # cache object (must respond to #[], #[]=, and #keys)
|
|
112
|
-
@data[:cache_prefix] = "geocoder:" # - DEPRECATED - prefix (string) to use for all cache keys
|
|
113
110
|
@data[:basic_auth] = {} # user and password for basic auth ({:user => "user", :password => "password"})
|
|
114
111
|
@data[:logger] = :kernel # :kernel or Logger instance
|
|
115
112
|
@data[:kernel_logger_level] = ::Logger::WARN # log level, if kernel logger is used
|
|
@@ -123,8 +120,15 @@ module Geocoder
|
|
|
123
120
|
@data[:units] = :mi # :mi or :km
|
|
124
121
|
@data[:distances] = :linear # :linear or :spherical
|
|
125
122
|
|
|
126
|
-
#
|
|
127
|
-
|
|
123
|
+
# Set the default values for the caching mechanism
|
|
124
|
+
# By default, the cache keys will not expire as IP addresses and phyiscal
|
|
125
|
+
# addresses will rarely change.
|
|
126
|
+
@data[:cache] = nil # cache object (must respond to #[], #[]=, and optionally #keys)
|
|
127
|
+
@data[:cache_prefix] = nil # - DEPRECATED - prefix (string) to use for all cache keys
|
|
128
|
+
@data[:cache_options] = {
|
|
129
|
+
prefix: 'geocoder:',
|
|
130
|
+
expiration: nil
|
|
131
|
+
}
|
|
128
132
|
end
|
|
129
133
|
|
|
130
134
|
instance_eval(OPTIONS.map do |option|
|
data/lib/geocoder/lookup.rb
CHANGED
|
@@ -65,7 +65,8 @@ module Geocoder
|
|
|
65
65
|
:melissa_street,
|
|
66
66
|
:amazon_location_service,
|
|
67
67
|
:geoapify,
|
|
68
|
-
:photon
|
|
68
|
+
:photon,
|
|
69
|
+
:twogis
|
|
69
70
|
]
|
|
70
71
|
end
|
|
71
72
|
|
|
@@ -117,8 +118,7 @@ module Geocoder
|
|
|
117
118
|
def spawn(name)
|
|
118
119
|
if all_services.include?(name)
|
|
119
120
|
name = name.to_s
|
|
120
|
-
|
|
121
|
-
Geocoder::Lookup.const_get(classify_name(name)).new
|
|
121
|
+
instantiate_lookup(name)
|
|
122
122
|
else
|
|
123
123
|
valids = all_services.map(&:inspect).join(", ")
|
|
124
124
|
raise ConfigurationError, "Please specify a valid lookup for Geocoder " +
|
|
@@ -132,5 +132,18 @@ module Geocoder
|
|
|
132
132
|
def classify_name(filename)
|
|
133
133
|
filename.to_s.split("_").map{ |i| i[0...1].upcase + i[1..-1] }.join
|
|
134
134
|
end
|
|
135
|
+
|
|
136
|
+
##
|
|
137
|
+
# Safely instantiate Lookup
|
|
138
|
+
#
|
|
139
|
+
def instantiate_lookup(name)
|
|
140
|
+
class_name = "Geocoder::Lookup::#{classify_name(name)}"
|
|
141
|
+
begin
|
|
142
|
+
Geocoder::Lookup.const_get(class_name)
|
|
143
|
+
rescue NameError
|
|
144
|
+
require "geocoder/lookups/#{name}"
|
|
145
|
+
end
|
|
146
|
+
Geocoder::Lookup.const_get(class_name).new
|
|
147
|
+
end
|
|
135
148
|
end
|
|
136
149
|
end
|
|
@@ -83,13 +83,8 @@ module Geocoder
|
|
|
83
83
|
# The working Cache object.
|
|
84
84
|
#
|
|
85
85
|
def cache
|
|
86
|
-
if @cache.nil?
|
|
86
|
+
if @cache.nil? and store = configuration.cache
|
|
87
87
|
cache_options = configuration.cache_options
|
|
88
|
-
cache_prefix = (configuration.cache_prefix rescue false)
|
|
89
|
-
if cache_prefix
|
|
90
|
-
cache_options[:prefix] ||= configuration.cache_prefix
|
|
91
|
-
warn '[Geocoder] cache_prefix is deprecated, please change to cache_options.prefix instead'
|
|
92
|
-
end
|
|
93
88
|
@cache = Cache.new(store, cache_options)
|
|
94
89
|
end
|
|
95
90
|
@cache
|
|
@@ -17,14 +17,16 @@ module Geocoder::Lookup
|
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
def query_url(query)
|
|
21
|
-
"#{protocol}://#{host}/json/#{query.sanitized_text}"
|
|
22
|
-
end
|
|
23
|
-
|
|
24
20
|
private # ---------------------------------------------------------------
|
|
25
21
|
|
|
26
|
-
def
|
|
27
|
-
|
|
22
|
+
def base_query_url(query)
|
|
23
|
+
"#{protocol}://#{host}/json/#{query.sanitized_text}?"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def query_url_params(query)
|
|
27
|
+
{
|
|
28
|
+
:apikey => configuration.api_key
|
|
29
|
+
}.merge(super)
|
|
28
30
|
end
|
|
29
31
|
|
|
30
32
|
def parse_raw_data(raw_data)
|
|
@@ -33,9 +33,29 @@ module Geocoder
|
|
|
33
33
|
result
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
def fields(query)
|
|
37
|
+
if query.options.has_key?(:fields)
|
|
38
|
+
return format_fields(query.options[:fields])
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
if configuration.has_key?(:fields)
|
|
42
|
+
return format_fields(configuration[:fields])
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
nil # use Google Places defaults
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def format_fields(*fields)
|
|
49
|
+
flattened = fields.flatten.compact
|
|
50
|
+
return if flattened.empty?
|
|
51
|
+
|
|
52
|
+
flattened.join(',')
|
|
53
|
+
end
|
|
54
|
+
|
|
36
55
|
def query_url_google_params(query)
|
|
37
56
|
{
|
|
38
57
|
placeid: query.text,
|
|
58
|
+
fields: fields(query),
|
|
39
59
|
language: query.language || configuration.language
|
|
40
60
|
}
|
|
41
61
|
end
|
|
@@ -31,13 +31,19 @@ module Geocoder
|
|
|
31
31
|
input: query.text,
|
|
32
32
|
inputtype: 'textquery',
|
|
33
33
|
fields: fields(query),
|
|
34
|
+
locationbias: locationbias(query),
|
|
34
35
|
language: query.language || configuration.language
|
|
35
36
|
}
|
|
36
37
|
end
|
|
37
38
|
|
|
38
39
|
def fields(query)
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
if query.options.has_key?(:fields)
|
|
41
|
+
return format_fields(query.options[:fields])
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
if configuration.has_key?(:fields)
|
|
45
|
+
return format_fields(configuration[:fields])
|
|
46
|
+
end
|
|
41
47
|
|
|
42
48
|
default_fields
|
|
43
49
|
end
|
|
@@ -52,7 +58,18 @@ module Geocoder
|
|
|
52
58
|
end
|
|
53
59
|
|
|
54
60
|
def format_fields(*fields)
|
|
55
|
-
fields.flatten.
|
|
61
|
+
flattened = fields.flatten.compact
|
|
62
|
+
return if flattened.empty?
|
|
63
|
+
|
|
64
|
+
flattened.join(',')
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def locationbias(query)
|
|
68
|
+
if query.options.has_key?(:locationbias)
|
|
69
|
+
query.options[:locationbias]
|
|
70
|
+
else
|
|
71
|
+
configuration[:locationbias]
|
|
72
|
+
end
|
|
56
73
|
end
|
|
57
74
|
end
|
|
58
75
|
end
|
|
@@ -19,50 +19,55 @@ module Geocoder::Lookup
|
|
|
19
19
|
private # ---------------------------------------------------------------
|
|
20
20
|
|
|
21
21
|
def base_query_url(query)
|
|
22
|
-
|
|
22
|
+
service = query.reverse_geocode? ? "revgeocode" : "geocode"
|
|
23
|
+
|
|
24
|
+
"#{protocol}://#{service}.search.hereapi.com/v1/#{service}?"
|
|
23
25
|
end
|
|
24
26
|
|
|
25
27
|
def results(query)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return [] if r.nil? || !r.is_a?(Array) || r.empty?
|
|
30
|
-
return r.first['Result']
|
|
28
|
+
unless configuration.api_key.is_a?(String)
|
|
29
|
+
api_key_not_string!
|
|
30
|
+
return []
|
|
31
31
|
end
|
|
32
|
-
[]
|
|
32
|
+
return [] unless doc = fetch_data(query)
|
|
33
|
+
return [] if doc["items"].nil?
|
|
34
|
+
|
|
35
|
+
doc["items"]
|
|
33
36
|
end
|
|
34
37
|
|
|
35
38
|
def query_url_here_options(query, reverse_geocode)
|
|
36
39
|
options = {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
language: (query.language || configuration.language)
|
|
40
|
+
apiKey: configuration.api_key,
|
|
41
|
+
lang: (query.language || configuration.language)
|
|
40
42
|
}
|
|
41
|
-
if reverse_geocode
|
|
42
|
-
options[:mode] = :retrieveAddresses
|
|
43
|
-
return options
|
|
44
|
-
end
|
|
43
|
+
return options if reverse_geocode
|
|
45
44
|
|
|
46
45
|
unless (country = query.options[:country]).nil?
|
|
47
|
-
options[:
|
|
46
|
+
options[:in] = "countryCode:#{country}"
|
|
48
47
|
end
|
|
49
48
|
|
|
50
|
-
unless (mapview = query.options[:bounds]).nil?
|
|
51
|
-
options[:mapview] = mapview.map{ |point| "%f,%f" % point }.join(';')
|
|
52
|
-
end
|
|
53
49
|
options
|
|
54
50
|
end
|
|
55
51
|
|
|
56
52
|
def query_url_params(query)
|
|
57
53
|
if query.reverse_geocode?
|
|
58
54
|
super.merge(query_url_here_options(query, true)).merge(
|
|
59
|
-
|
|
55
|
+
at: query.sanitized_text
|
|
60
56
|
)
|
|
61
57
|
else
|
|
62
58
|
super.merge(query_url_here_options(query, false)).merge(
|
|
63
|
-
|
|
59
|
+
q: query.sanitized_text
|
|
64
60
|
)
|
|
65
61
|
end
|
|
66
62
|
end
|
|
63
|
+
|
|
64
|
+
def api_key_not_string!
|
|
65
|
+
msg = <<~MSG
|
|
66
|
+
API key for HERE Geocoding and Search API should be a string.
|
|
67
|
+
For more info on how to obtain it, please see https://developer.here.com/documentation/identity-access-management/dev_guide/topics/plat-using-apikeys.html
|
|
68
|
+
MSG
|
|
69
|
+
|
|
70
|
+
raise_error(Geocoder::ConfigurationError, msg) || Geocoder.log(:warn, msg)
|
|
71
|
+
end
|
|
67
72
|
end
|
|
68
73
|
end
|
|
@@ -11,6 +11,10 @@ module Geocoder::Lookup
|
|
|
11
11
|
["api_key"]
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
+
def supported_protocols
|
|
15
|
+
[:https]
|
|
16
|
+
end
|
|
17
|
+
|
|
14
18
|
private # ----------------------------------------------------------------
|
|
15
19
|
|
|
16
20
|
def base_query_url(query)
|
|
@@ -25,7 +29,7 @@ module Geocoder::Lookup
|
|
|
25
29
|
end
|
|
26
30
|
|
|
27
31
|
def configured_host
|
|
28
|
-
configuration[:host] || "locationiq.
|
|
32
|
+
configuration[:host] || "us1.locationiq.com"
|
|
29
33
|
end
|
|
30
34
|
|
|
31
35
|
def results(query)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require 'geocoder/lookups/base'
|
|
2
|
+
require "geocoder/results/twogis"
|
|
3
|
+
|
|
4
|
+
module Geocoder::Lookup
|
|
5
|
+
class Twogis < Base
|
|
6
|
+
|
|
7
|
+
def name
|
|
8
|
+
"2gis"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def required_api_key_parts
|
|
12
|
+
["key"]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def map_link_url(coordinates)
|
|
16
|
+
"https://2gis.ru/?m=#{coordinates.join(',')}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def supported_protocols
|
|
20
|
+
[:https]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private # ---------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
def base_query_url(query)
|
|
26
|
+
"#{protocol}://catalog.api.2gis.com/3.0/items/geocode?"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def results(query)
|
|
30
|
+
return [] unless doc = fetch_data(query)
|
|
31
|
+
if doc['meta'] && doc['meta']['error']
|
|
32
|
+
Geocoder.log(:warn, "2gis Geocoding API error: #{doc['meta']["code"]} (#{doc['meta']['error']["message"]}).")
|
|
33
|
+
return []
|
|
34
|
+
end
|
|
35
|
+
if doc['result'] && doc = doc['result']['items']
|
|
36
|
+
return doc.to_a
|
|
37
|
+
else
|
|
38
|
+
Geocoder.log(:warn, "2gis Geocoding API error: unexpected response format.")
|
|
39
|
+
return []
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def query_url_params(query)
|
|
44
|
+
if query.reverse_geocode?
|
|
45
|
+
q = query.coordinates.reverse.join(",")
|
|
46
|
+
else
|
|
47
|
+
q = query.sanitized_text
|
|
48
|
+
end
|
|
49
|
+
params = {
|
|
50
|
+
:q => q,
|
|
51
|
+
:lang => "#{query.language || configuration.language}",
|
|
52
|
+
:key => configuration.api_key,
|
|
53
|
+
:fields => 'items.street,items.adm_div,items.full_address_name,items.point,items.geometry.centroid'
|
|
54
|
+
}
|
|
55
|
+
params.merge(super)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -7,76 +7,71 @@ module Geocoder::Result
|
|
|
7
7
|
# A string in the given format.
|
|
8
8
|
#
|
|
9
9
|
def address(format = :full)
|
|
10
|
-
address_data[
|
|
10
|
+
address_data["label"]
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
##
|
|
14
14
|
# A two-element array: [lat, lon].
|
|
15
15
|
#
|
|
16
16
|
def coordinates
|
|
17
|
-
fail unless d = @data[
|
|
18
|
-
[d[
|
|
17
|
+
fail unless d = @data["position"]
|
|
18
|
+
[d["lat"].to_f, d["lng"].to_f]
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def route
|
|
22
|
-
address_data[
|
|
22
|
+
address_data["street"]
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
def street_number
|
|
26
|
-
address_data[
|
|
26
|
+
address_data["houseNumber"]
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def state
|
|
30
|
-
|
|
31
|
-
if v = d.find{|ad| ad['key']=='StateName'}
|
|
32
|
-
return v['value']
|
|
33
|
-
end
|
|
30
|
+
address_data["state"]
|
|
34
31
|
end
|
|
35
32
|
|
|
36
33
|
def province
|
|
37
|
-
address_data[
|
|
34
|
+
address_data["county"]
|
|
38
35
|
end
|
|
39
36
|
|
|
40
37
|
def postal_code
|
|
41
|
-
address_data[
|
|
38
|
+
address_data["postalCode"]
|
|
42
39
|
end
|
|
43
40
|
|
|
44
41
|
def city
|
|
45
|
-
address_data[
|
|
42
|
+
address_data["city"]
|
|
46
43
|
end
|
|
47
44
|
|
|
48
45
|
def state_code
|
|
49
|
-
address_data[
|
|
46
|
+
address_data["stateCode"]
|
|
50
47
|
end
|
|
51
48
|
|
|
52
49
|
def province_code
|
|
53
|
-
address_data[
|
|
50
|
+
address_data["state"]
|
|
54
51
|
end
|
|
55
52
|
|
|
56
53
|
def country
|
|
57
|
-
|
|
58
|
-
if v = d.find{|ad| ad['key']=='CountryName'}
|
|
59
|
-
return v['value']
|
|
60
|
-
end
|
|
54
|
+
address_data["countryName"]
|
|
61
55
|
end
|
|
62
56
|
|
|
63
57
|
def country_code
|
|
64
|
-
address_data[
|
|
58
|
+
address_data["countryCode"]
|
|
65
59
|
end
|
|
66
60
|
|
|
67
61
|
def viewport
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
62
|
+
return [] if data["resultType"] == "place"
|
|
63
|
+
map_view = data["mapView"]
|
|
64
|
+
south = map_view["south"]
|
|
65
|
+
west = map_view["west"]
|
|
66
|
+
north = map_view["north"]
|
|
67
|
+
east = map_view["east"]
|
|
73
68
|
[south, west, north, east]
|
|
74
69
|
end
|
|
75
70
|
|
|
76
71
|
private # ----------------------------------------------------------------
|
|
77
72
|
|
|
78
73
|
def address_data
|
|
79
|
-
@data[
|
|
74
|
+
@data["address"] || fail
|
|
80
75
|
end
|
|
81
76
|
end
|
|
82
77
|
end
|
|
@@ -4,12 +4,12 @@ module Geocoder::Result
|
|
|
4
4
|
class Nominatim < Base
|
|
5
5
|
|
|
6
6
|
def poi
|
|
7
|
-
return
|
|
7
|
+
return address_data[place_type] if address_data.key?(place_type)
|
|
8
8
|
return nil
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def house_number
|
|
12
|
-
|
|
12
|
+
address_data['house_number']
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def address
|
|
@@ -18,69 +18,71 @@ module Geocoder::Result
|
|
|
18
18
|
|
|
19
19
|
def street
|
|
20
20
|
%w[road pedestrian highway].each do |key|
|
|
21
|
-
return
|
|
21
|
+
return address_data[key] if address_data.key?(key)
|
|
22
22
|
end
|
|
23
23
|
return nil
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def city
|
|
27
27
|
%w[city town village hamlet].each do |key|
|
|
28
|
-
return
|
|
28
|
+
return address_data[key] if address_data.key?(key)
|
|
29
29
|
end
|
|
30
30
|
return nil
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def village
|
|
34
|
-
|
|
34
|
+
address_data['village']
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
def town
|
|
38
|
-
|
|
38
|
+
address_data['town']
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
def state
|
|
42
|
-
|
|
42
|
+
address_data['state']
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
alias_method :state_code, :state
|
|
46
46
|
|
|
47
47
|
def postal_code
|
|
48
|
-
|
|
48
|
+
address_data['postcode']
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
def county
|
|
52
|
-
|
|
52
|
+
address_data['county']
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def country
|
|
56
|
-
|
|
56
|
+
address_data['country']
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
def country_code
|
|
60
|
-
|
|
60
|
+
address_data['country_code']
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
def suburb
|
|
64
|
-
|
|
64
|
+
address_data['suburb']
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def city_district
|
|
68
|
-
|
|
68
|
+
address_data['city_district']
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
def state_district
|
|
72
|
-
|
|
72
|
+
address_data['state_district']
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
def neighbourhood
|
|
76
|
-
|
|
76
|
+
address_data['neighbourhood']
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
def municipality
|
|
80
|
-
|
|
80
|
+
address_data['municipality']
|
|
81
81
|
end
|
|
82
82
|
|
|
83
83
|
def coordinates
|
|
84
|
+
return [] unless @data['lat'] && @data['lon']
|
|
85
|
+
|
|
84
86
|
[@data['lat'].to_f, @data['lon'].to_f]
|
|
85
87
|
end
|
|
86
88
|
|
|
@@ -109,5 +111,11 @@ module Geocoder::Result
|
|
|
109
111
|
end
|
|
110
112
|
end
|
|
111
113
|
end
|
|
114
|
+
|
|
115
|
+
private
|
|
116
|
+
|
|
117
|
+
def address_data
|
|
118
|
+
@data['address'] || {}
|
|
119
|
+
end
|
|
112
120
|
end
|
|
113
121
|
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require 'geocoder/results/base'
|
|
2
|
+
|
|
3
|
+
module Geocoder::Result
|
|
4
|
+
class Twogis < Base
|
|
5
|
+
def coordinates
|
|
6
|
+
['lat', 'lon'].map{ |i| @data['point'][i] } if @data['point']
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def address(_format = :full)
|
|
10
|
+
@data['full_address_name'] || ''
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def city
|
|
14
|
+
return '' unless @data['adm_div']
|
|
15
|
+
@data['adm_div'].select{|u| u["type"] == "city"}.first.try(:[], 'name') || ''
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def region
|
|
19
|
+
return '' unless @data['adm_div']
|
|
20
|
+
@data['adm_div'].select{|u| u["type"] == "region"}.first.try(:[], 'name') || ''
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def country
|
|
24
|
+
return '' unless @data['adm_div']
|
|
25
|
+
@data['adm_div'].select{|u| u["type"] == "country"}.first.try(:[], 'name') || ''
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def district
|
|
29
|
+
return '' unless @data['adm_div']
|
|
30
|
+
@data['adm_div'].select{|u| u["type"] == "district"}.first.try(:[], 'name') || ''
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def district_area
|
|
34
|
+
return '' unless @data['adm_div']
|
|
35
|
+
@data['adm_div'].select{|u| u["type"] == "district_area"}.first.try(:[], 'name') || ''
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def street_address
|
|
39
|
+
@data['address_name'] || ''
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def street
|
|
43
|
+
return '' unless @data['address_name']
|
|
44
|
+
@data['address_name'].split(', ').first
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def street_number
|
|
48
|
+
return '' unless @data['address_name']
|
|
49
|
+
@data['address_name'].split(', ')[1] || ''
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def type
|
|
53
|
+
@data['type'] || ''
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def purpose_name
|
|
57
|
+
@data['purpose_name'] || ''
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def building_name
|
|
61
|
+
@data['building_name'] || ''
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def subtype
|
|
65
|
+
@data['subtype'] || ''
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def subtype_specification
|
|
69
|
+
@data['subtype_specification'] || ''
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def name
|
|
73
|
+
@data['name'] || ''
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
data/lib/geocoder/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: geocoder
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex Reisner
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-
|
|
11
|
+
date: 2022-05-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Object geocoding (by street or IP address), reverse geocoding (coordinates
|
|
14
14
|
to street address), distance queries for ActiveRecord and Mongoid, result caching,
|
|
@@ -25,8 +25,7 @@ files:
|
|
|
25
25
|
- README.md
|
|
26
26
|
- bin/console
|
|
27
27
|
- bin/geocode
|
|
28
|
-
- examples/
|
|
29
|
-
- examples/autoexpire_cache_redis.rb
|
|
28
|
+
- examples/app_defined_lookup_services.rb
|
|
30
29
|
- examples/cache_bypass.rb
|
|
31
30
|
- examples/reverse_geocode_job.rb
|
|
32
31
|
- lib/easting_northing.rb
|
|
@@ -104,6 +103,7 @@ files:
|
|
|
104
103
|
- lib/geocoder/lookups/telize.rb
|
|
105
104
|
- lib/geocoder/lookups/tencent.rb
|
|
106
105
|
- lib/geocoder/lookups/test.rb
|
|
106
|
+
- lib/geocoder/lookups/twogis.rb
|
|
107
107
|
- lib/geocoder/lookups/uk_ordnance_survey_names.rb
|
|
108
108
|
- lib/geocoder/lookups/yandex.rb
|
|
109
109
|
- lib/geocoder/models/active_record.rb
|
|
@@ -166,6 +166,7 @@ files:
|
|
|
166
166
|
- lib/geocoder/results/telize.rb
|
|
167
167
|
- lib/geocoder/results/tencent.rb
|
|
168
168
|
- lib/geocoder/results/test.rb
|
|
169
|
+
- lib/geocoder/results/twogis.rb
|
|
169
170
|
- lib/geocoder/results/uk_ordnance_survey_names.rb
|
|
170
171
|
- lib/geocoder/results/yandex.rb
|
|
171
172
|
- lib/geocoder/sql.rb
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# This class implements a cache with simple delegation to the the Dalli Memcached client
|
|
2
|
-
# https://github.com/mperham/dalli
|
|
3
|
-
#
|
|
4
|
-
# A TTL is set on initialization
|
|
5
|
-
|
|
6
|
-
class AutoexpireCacheDalli
|
|
7
|
-
def initialize(store, ttl = 86400)
|
|
8
|
-
@store = store
|
|
9
|
-
@keys = 'GeocoderDalliClientKeys'
|
|
10
|
-
@ttl = ttl
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def [](url)
|
|
14
|
-
res = @store.get(url)
|
|
15
|
-
res = YAML::load(res) if res.present?
|
|
16
|
-
res
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def []=(url, value)
|
|
20
|
-
if value.nil?
|
|
21
|
-
del(url)
|
|
22
|
-
else
|
|
23
|
-
key_cache_add(url) if @store.add(url, YAML::dump(value), @ttl)
|
|
24
|
-
end
|
|
25
|
-
value
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def keys
|
|
29
|
-
key_cache
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def del(url)
|
|
33
|
-
key_cache_delete(url) if @store.delete(url)
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
private
|
|
37
|
-
|
|
38
|
-
def key_cache
|
|
39
|
-
the_keys = @store.get(@keys)
|
|
40
|
-
if the_keys.nil?
|
|
41
|
-
@store.add(@keys, YAML::dump([]))
|
|
42
|
-
[]
|
|
43
|
-
else
|
|
44
|
-
YAML::load(the_keys)
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def key_cache_add(key)
|
|
49
|
-
@store.replace(@keys, YAML::dump(key_cache << key))
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def key_cache_delete(key)
|
|
53
|
-
tmp = key_cache
|
|
54
|
-
tmp.delete(key)
|
|
55
|
-
@store.replace(@keys, YAML::dump(tmp))
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
# Here Dalli is set up as on Heroku using the Memcachier gem.
|
|
60
|
-
# https://devcenter.heroku.com/articles/memcachier#ruby
|
|
61
|
-
# On other setups you might have to specify your Memcached server in Dalli::Client.new
|
|
62
|
-
Geocoder.configure(:cache => AutoexpireCacheDalli.new(Dalli::Client.new))
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# This class implements a cache with simple delegation to the Redis store, but
|
|
2
|
-
# when it creates a key/value pair, it also sends an EXPIRE command with a TTL.
|
|
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.
|
|
6
|
-
class AutoexpireCacheRedis
|
|
7
|
-
def initialize(store, ttl = 86400)
|
|
8
|
-
@store = store
|
|
9
|
-
@ttl = ttl
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def [](url)
|
|
13
|
-
@store.get(url)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def []=(url, value)
|
|
17
|
-
@store.set(url, value)
|
|
18
|
-
@store.expire(url, @ttl)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def keys
|
|
22
|
-
@store.keys
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def del(url)
|
|
26
|
-
@store.del(url)
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
Geocoder.configure(:cache => AutoexpireCacheRedis.new(Redis.new))
|