geocoder 1.6.4 → 1.8.2
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 +61 -0
- data/LICENSE +1 -1
- data/README.md +329 -235
- data/examples/app_defined_lookup_services.rb +22 -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 +17 -4
- data/lib/geocoder/ip_address.rb +9 -0
- data/lib/geocoder/lookup.rb +33 -4
- 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 +55 -0
- data/lib/geocoder/lookups/ban_data_gouv_fr.rb +1 -1
- data/lib/geocoder/lookups/base.rb +2 -1
- data/lib/geocoder/lookups/bing.rb +1 -1
- data/lib/geocoder/lookups/esri.rb +18 -5
- data/lib/geocoder/lookups/freegeoip.rb +8 -6
- data/lib/geocoder/lookups/geoapify.rb +78 -0
- data/lib/geocoder/lookups/geoip2.rb +4 -0
- data/lib/geocoder/lookups/geoportail_lu.rb +1 -1
- 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/ip2location.rb +10 -6
- data/lib/geocoder/lookups/ipbase.rb +49 -0
- data/lib/geocoder/lookups/ipdata_co.rb +1 -1
- data/lib/geocoder/lookups/ipqualityscore.rb +50 -0
- data/lib/geocoder/lookups/location_iq.rb +5 -1
- data/lib/geocoder/lookups/maxmind_local.rb +7 -1
- data/lib/geocoder/lookups/melissa_street.rb +41 -0
- data/lib/geocoder/lookups/pc_miler.rb +85 -0
- data/lib/geocoder/lookups/photon.rb +89 -0
- 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 +1 -1
- data/lib/geocoder/lookups/yandex.rb +3 -3
- data/lib/geocoder/results/abstract_api.rb +146 -0
- data/lib/geocoder/results/amazon_location_service.rb +57 -0
- data/lib/geocoder/results/ban_data_gouv_fr.rb +27 -2
- data/lib/geocoder/results/esri.rb +5 -2
- data/lib/geocoder/results/geoapify.rb +179 -0
- data/lib/geocoder/results/here.rb +20 -25
- data/lib/geocoder/results/ipbase.rb +40 -0
- data/lib/geocoder/results/ipqualityscore.rb +54 -0
- data/lib/geocoder/results/ipregistry.rb +4 -8
- 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 +1 -1
- data/lib/geocoder/results/nominatim.rb +24 -16
- data/lib/geocoder/results/pc_miler.rb +98 -0
- data/lib/geocoder/results/photon.rb +119 -0
- data/lib/geocoder/results/twogis.rb +76 -0
- data/lib/geocoder/version.rb +1 -1
- data/lib/maxmind_database.rb +8 -8
- data/lib/tasks/maxmind.rake +1 -1
- metadata +28 -8
- data/examples/autoexpire_cache_dalli.rb +0 -62
- data/examples/autoexpire_cache_redis.rb +0 -30
@@ -37,6 +37,10 @@ module Geocoder
|
|
37
37
|
def results(query)
|
38
38
|
return [] unless configuration[:file]
|
39
39
|
|
40
|
+
if @mmdb.respond_to?(:local_ip_alias) && !configuration[:local_ip_alias].nil?
|
41
|
+
@mmdb.local_ip_alias = configuration[:local_ip_alias]
|
42
|
+
end
|
43
|
+
|
40
44
|
result = @mmdb.lookup(query.to_s)
|
41
45
|
result.nil? ? [] : [result]
|
42
46
|
end
|
@@ -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
|
@@ -8,6 +8,10 @@ module Geocoder::Lookup
|
|
8
8
|
"IP2LocationApi"
|
9
9
|
end
|
10
10
|
|
11
|
+
def required_api_key_parts
|
12
|
+
['key']
|
13
|
+
end
|
14
|
+
|
11
15
|
def supported_protocols
|
12
16
|
[:http, :https]
|
13
17
|
end
|
@@ -15,15 +19,15 @@ module Geocoder::Lookup
|
|
15
19
|
private # ----------------------------------------------------------------
|
16
20
|
|
17
21
|
def base_query_url(query)
|
18
|
-
"#{protocol}://api.ip2location.com/?"
|
22
|
+
"#{protocol}://api.ip2location.com/v2/?"
|
19
23
|
end
|
20
24
|
|
21
25
|
def query_url_params(query)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
26
|
+
super.merge(
|
27
|
+
key: configuration.api_key,
|
28
|
+
ip: query.sanitized_text,
|
29
|
+
package: configuration[:package],
|
30
|
+
)
|
27
31
|
end
|
28
32
|
|
29
33
|
def results(query)
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'geocoder/lookups/base'
|
2
|
+
require 'geocoder/results/ipbase'
|
3
|
+
|
4
|
+
module Geocoder::Lookup
|
5
|
+
class Ipbase < Base
|
6
|
+
|
7
|
+
def name
|
8
|
+
"ipbase.com"
|
9
|
+
end
|
10
|
+
|
11
|
+
def supported_protocols
|
12
|
+
[:https]
|
13
|
+
end
|
14
|
+
|
15
|
+
private # ---------------------------------------------------------------
|
16
|
+
|
17
|
+
def base_query_url(query)
|
18
|
+
"https://api.ipbase.com/v2/info?"
|
19
|
+
end
|
20
|
+
|
21
|
+
def query_url_params(query)
|
22
|
+
{
|
23
|
+
:ip => query.sanitized_text,
|
24
|
+
:apikey => configuration.api_key
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def results(query)
|
29
|
+
# don't look up a loopback or private address, just return the stored result
|
30
|
+
return [reserved_result(query.text)] if query.internal_ip_address?
|
31
|
+
doc = fetch_data(query) || {}
|
32
|
+
doc.fetch("data", {})["location"] ? [doc] : []
|
33
|
+
end
|
34
|
+
|
35
|
+
def reserved_result(ip)
|
36
|
+
{
|
37
|
+
"data" => {
|
38
|
+
"ip" => ip,
|
39
|
+
"location" => {
|
40
|
+
"city" => { "name" => "" },
|
41
|
+
"country" => { "alpha2" => "RD", "name" => "Reserved" },
|
42
|
+
"region" => { "alpha2" => "", "name" => "" },
|
43
|
+
"zip" => ""
|
44
|
+
}
|
45
|
+
}
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'geocoder/lookups/base'
|
4
|
+
require 'geocoder/results/ipqualityscore'
|
5
|
+
|
6
|
+
module Geocoder::Lookup
|
7
|
+
class Ipqualityscore < Base
|
8
|
+
|
9
|
+
def name
|
10
|
+
"IPQualityScore"
|
11
|
+
end
|
12
|
+
|
13
|
+
def required_api_key_parts
|
14
|
+
['api_key']
|
15
|
+
end
|
16
|
+
|
17
|
+
private # ---------------------------------------------------------------
|
18
|
+
|
19
|
+
def base_query_url(query)
|
20
|
+
"#{protocol}://ipqualityscore.com/api/json/ip/#{configuration.api_key}/#{query.sanitized_text}?"
|
21
|
+
end
|
22
|
+
|
23
|
+
def valid_response?(response)
|
24
|
+
if (json = parse_json(response.body))
|
25
|
+
success = json['success']
|
26
|
+
end
|
27
|
+
super && success == true
|
28
|
+
end
|
29
|
+
|
30
|
+
def results(query, reverse = false)
|
31
|
+
return [] unless doc = fetch_data(query)
|
32
|
+
|
33
|
+
return [doc] if doc['success']
|
34
|
+
|
35
|
+
case doc['message']
|
36
|
+
when /invalid (.*) key/i
|
37
|
+
raise_error Geocoder::InvalidApiKey ||
|
38
|
+
Geocoder.log(:warn, "#{name} API error: invalid api key.")
|
39
|
+
when /insufficient credits/, /exceeded your request quota/
|
40
|
+
raise_error Geocoder::OverQueryLimitError ||
|
41
|
+
Geocoder.log(:warn, "#{name} API error: query limit exceeded.")
|
42
|
+
when /invalid (.*) address/i
|
43
|
+
raise_error Geocoder::InvalidRequest ||
|
44
|
+
Geocoder.log(:warn, "#{name} API error: invalid request.")
|
45
|
+
end
|
46
|
+
|
47
|
+
[doc]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
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)
|
@@ -30,7 +30,13 @@ module Geocoder::Lookup
|
|
30
30
|
def results(query)
|
31
31
|
if configuration[:file]
|
32
32
|
geoip_class = RUBY_PLATFORM == "java" ? JGeoIP : GeoIP
|
33
|
-
|
33
|
+
geoip_instance = geoip_class.new(configuration[:file])
|
34
|
+
result =
|
35
|
+
if configuration[:package] == :country
|
36
|
+
geoip_instance.country(query.to_s)
|
37
|
+
else
|
38
|
+
geoip_instance.city(query.to_s)
|
39
|
+
end
|
34
40
|
result.nil? ? [] : [encode_hash(result.to_hash)]
|
35
41
|
elsif configuration[:package] == :city
|
36
42
|
addr = IPAddr.new(query.text).to_i
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'geocoder/lookups/base'
|
2
|
+
require "geocoder/results/melissa_street"
|
3
|
+
|
4
|
+
module Geocoder::Lookup
|
5
|
+
class MelissaStreet < Base
|
6
|
+
|
7
|
+
def name
|
8
|
+
"MelissaStreet"
|
9
|
+
end
|
10
|
+
|
11
|
+
def results(query)
|
12
|
+
return [] unless doc = fetch_data(query)
|
13
|
+
|
14
|
+
if doc["TransmissionResults"] == "GE05"
|
15
|
+
raise_error(Geocoder::InvalidApiKey) ||
|
16
|
+
Geocoder.log(:warn, "Melissa service error: invalid API key.")
|
17
|
+
end
|
18
|
+
|
19
|
+
return doc["Records"]
|
20
|
+
end
|
21
|
+
|
22
|
+
private # ---------------------------------------------------------------
|
23
|
+
|
24
|
+
def base_query_url(query)
|
25
|
+
"#{protocol}://address.melissadata.net/v3/WEB/GlobalAddress/doGlobalAddress?"
|
26
|
+
end
|
27
|
+
|
28
|
+
def query_url_params(query)
|
29
|
+
params = {
|
30
|
+
id: configuration.api_key,
|
31
|
+
format: "JSON",
|
32
|
+
a1: query.sanitized_text,
|
33
|
+
loc: query.options[:city],
|
34
|
+
admarea: query.options[:state],
|
35
|
+
postal: query.options[:postal],
|
36
|
+
ctry: query.options[:country]
|
37
|
+
}
|
38
|
+
params.merge(super)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'geocoder/lookups/base'
|
2
|
+
require "geocoder/results/pc_miler"
|
3
|
+
require 'cgi' unless defined?(CGI) && defined?(CGI.escape)
|
4
|
+
|
5
|
+
module Geocoder::Lookup
|
6
|
+
class PcMiler < Base
|
7
|
+
|
8
|
+
# https://developer.trimblemaps.com/restful-apis/location/single-search/single-search-api/#test-the-api-now
|
9
|
+
def valid_region_codes
|
10
|
+
# AF: Africa
|
11
|
+
# AS: Asia
|
12
|
+
# EU: Europe
|
13
|
+
# NA: North America
|
14
|
+
# OC: Oceania
|
15
|
+
# SA: South America
|
16
|
+
%w[AF AS EU NA OC SA]
|
17
|
+
end
|
18
|
+
|
19
|
+
def name
|
20
|
+
"PCMiler"
|
21
|
+
end
|
22
|
+
|
23
|
+
private # ---------------------------------------------------------------
|
24
|
+
|
25
|
+
def base_query_url(query)
|
26
|
+
region_code = region(query)
|
27
|
+
if !valid_region_codes.include?(region_code)
|
28
|
+
raise "region_code '#{region_code}' is invalid. use one of #{valid_region_codes}." \
|
29
|
+
"https://developer.trimblemaps.com/restful-apis/location/single-search/single-search-api/#test-the-api-now"
|
30
|
+
end
|
31
|
+
|
32
|
+
"#{protocol}://singlesearch.alk.com/#{region_code}/api/search?"
|
33
|
+
end
|
34
|
+
|
35
|
+
def results(query)
|
36
|
+
return [] unless data = fetch_data(query)
|
37
|
+
if data['Locations']
|
38
|
+
add_metadata_to_locations!(data)
|
39
|
+
data['Locations']
|
40
|
+
else
|
41
|
+
[]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_metadata_to_locations!(data)
|
46
|
+
confidence = data['QueryConfidence']
|
47
|
+
data['Locations'].each do |location|
|
48
|
+
location['QueryConfidence'] = confidence
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def query_url_params(query)
|
53
|
+
if query.reverse_geocode?
|
54
|
+
lat,lon = query.coordinates
|
55
|
+
formatted_query = "#{CGI.escape(lat)},#{CGI.escape(lon)}"
|
56
|
+
else
|
57
|
+
formatted_query = query.text.to_s
|
58
|
+
end
|
59
|
+
|
60
|
+
{
|
61
|
+
authToken: configuration.api_key,
|
62
|
+
query: formatted_query,
|
63
|
+
# to add additional metadata to response such as QueryConfidence
|
64
|
+
include: 'Meta'
|
65
|
+
}.merge(super(query))
|
66
|
+
end
|
67
|
+
|
68
|
+
def region(query)
|
69
|
+
query.options[:region] || query.options['region'] || configuration[:region] || "NA"
|
70
|
+
end
|
71
|
+
|
72
|
+
def check_response_for_errors!(response)
|
73
|
+
if response.code.to_i == 403
|
74
|
+
raise_error(Geocoder::RequestDenied) ||
|
75
|
+
Geocoder.log(:warn, "Geocoding API error: 403 API key does not exist")
|
76
|
+
else
|
77
|
+
super(response)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def supported_protocols
|
82
|
+
[:https]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'geocoder/lookups/base'
|
2
|
+
require 'geocoder/results/photon'
|
3
|
+
|
4
|
+
module Geocoder::Lookup
|
5
|
+
class Photon < Base
|
6
|
+
def name
|
7
|
+
'Photon'
|
8
|
+
end
|
9
|
+
|
10
|
+
private # ---------------------------------------------------------------
|
11
|
+
|
12
|
+
def supported_protocols
|
13
|
+
[:https]
|
14
|
+
end
|
15
|
+
|
16
|
+
def base_query_url(query)
|
17
|
+
host = configuration[:host] || 'photon.komoot.io'
|
18
|
+
method = query.reverse_geocode? ? 'reverse' : 'api'
|
19
|
+
"#{protocol}://#{host}/#{method}?"
|
20
|
+
end
|
21
|
+
|
22
|
+
def results(query)
|
23
|
+
return [] unless (doc = fetch_data(query))
|
24
|
+
return [] unless doc['type'] == 'FeatureCollection'
|
25
|
+
return [] unless doc['features'] || doc['features'].present?
|
26
|
+
|
27
|
+
doc['features']
|
28
|
+
end
|
29
|
+
|
30
|
+
def query_url_params(query)
|
31
|
+
lang = query.language || configuration.language
|
32
|
+
params = { lang: lang, limit: query.options[:limit] }
|
33
|
+
|
34
|
+
if query.reverse_geocode?
|
35
|
+
params.merge!(query_url_params_reverse(query))
|
36
|
+
else
|
37
|
+
params.merge!(query_url_params_coordinates(query))
|
38
|
+
end
|
39
|
+
|
40
|
+
params.merge!(super)
|
41
|
+
end
|
42
|
+
|
43
|
+
def query_url_params_coordinates(query)
|
44
|
+
params = { q: query.sanitized_text }
|
45
|
+
|
46
|
+
if (bias = query.options[:bias])
|
47
|
+
params.merge!(lat: bias[:latitude], lon: bias[:longitude], location_bias_scale: bias[:scale])
|
48
|
+
end
|
49
|
+
|
50
|
+
if (filter = query_url_params_coordinates_filter(query))
|
51
|
+
params.merge!(filter)
|
52
|
+
end
|
53
|
+
|
54
|
+
params
|
55
|
+
end
|
56
|
+
|
57
|
+
def query_url_params_coordinates_filter(query)
|
58
|
+
filter = query.options[:filter]
|
59
|
+
return unless filter
|
60
|
+
|
61
|
+
bbox = filter[:bbox]
|
62
|
+
{
|
63
|
+
bbox: bbox.is_a?(Array) ? bbox.join(',') : bbox,
|
64
|
+
osm_tag: filter[:osm_tag]
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
def query_url_params_reverse(query)
|
69
|
+
params = { lat: query.coordinates[0], lon: query.coordinates[1], radius: query.options[:radius] }
|
70
|
+
|
71
|
+
if (dsort = query.options[:distance_sort])
|
72
|
+
params[:distance_sort] = dsort ? 'true' : 'false'
|
73
|
+
end
|
74
|
+
|
75
|
+
if (filter = query_url_params_reverse_filter(query))
|
76
|
+
params.merge!(filter)
|
77
|
+
end
|
78
|
+
|
79
|
+
params
|
80
|
+
end
|
81
|
+
|
82
|
+
def query_url_params_reverse_filter(query)
|
83
|
+
filter = query.options[:filter]
|
84
|
+
return unless filter
|
85
|
+
|
86
|
+
{ query_string_filter: filter[:string] }
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -18,6 +18,7 @@ module Geocoder
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def self.read_stub(query_text)
|
21
|
+
@default_stub ||= nil
|
21
22
|
stubs.fetch(query_text) {
|
22
23
|
return @default_stub unless @default_stub.nil?
|
23
24
|
raise ArgumentError, "unknown stub request #{query_text}"
|
@@ -28,6 +29,10 @@ module Geocoder
|
|
28
29
|
@stubs ||= {}
|
29
30
|
end
|
30
31
|
|
32
|
+
def self.delete_stub(query_text)
|
33
|
+
stubs.delete(query_text)
|
34
|
+
end
|
35
|
+
|
31
36
|
def self.reset
|
32
37
|
@stubs = {}
|
33
38
|
@default_stub = nil
|
@@ -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
|
@@ -24,11 +24,11 @@ module Geocoder::Lookup
|
|
24
24
|
|
25
25
|
def results(query)
|
26
26
|
return [] unless doc = fetch_data(query)
|
27
|
-
if
|
28
|
-
if
|
27
|
+
if [400, 403].include? doc['statusCode']
|
28
|
+
if doc['statusCode'] == 403 and doc['message'] == 'Invalid key'
|
29
29
|
raise_error(Geocoder::InvalidApiKey) || Geocoder.log(:warn, "Invalid API key.")
|
30
30
|
else
|
31
|
-
Geocoder.log(:warn, "Yandex Geocoding API error: #{
|
31
|
+
Geocoder.log(:warn, "Yandex Geocoding API error: #{doc['statusCode']} (#{doc['message']}).")
|
32
32
|
end
|
33
33
|
return []
|
34
34
|
end
|