ultra-fast-mod 0.0.1
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 +7 -0
- data/geocoder-1.8.6/CHANGELOG.md +669 -0
- data/geocoder-1.8.6/LICENSE +20 -0
- data/geocoder-1.8.6/README.md +827 -0
- data/geocoder-1.8.6/bin/console +13 -0
- data/geocoder-1.8.6/bin/geocode +5 -0
- data/geocoder-1.8.6/examples/app_defined_lookup_services.rb +22 -0
- data/geocoder-1.8.6/examples/cache_bypass.rb +48 -0
- data/geocoder-1.8.6/examples/reverse_geocode_job.rb +40 -0
- data/geocoder-1.8.6/lib/easting_northing.rb +171 -0
- data/geocoder-1.8.6/lib/generators/geocoder/config/config_generator.rb +14 -0
- data/geocoder-1.8.6/lib/generators/geocoder/config/templates/initializer.rb +27 -0
- data/geocoder-1.8.6/lib/generators/geocoder/maxmind/geolite_city_generator.rb +30 -0
- data/geocoder-1.8.6/lib/generators/geocoder/maxmind/geolite_country_generator.rb +30 -0
- data/geocoder-1.8.6/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb +30 -0
- data/geocoder-1.8.6/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb +17 -0
- data/geocoder-1.8.6/lib/generators/geocoder/migration_version.rb +15 -0
- data/geocoder-1.8.6/lib/geocoder/cache.rb +77 -0
- data/geocoder-1.8.6/lib/geocoder/cache_stores/base.rb +40 -0
- data/geocoder-1.8.6/lib/geocoder/cache_stores/generic.rb +35 -0
- data/geocoder-1.8.6/lib/geocoder/cache_stores/redis.rb +34 -0
- data/geocoder-1.8.6/lib/geocoder/calculations.rb +420 -0
- data/geocoder-1.8.6/lib/geocoder/cli.rb +121 -0
- data/geocoder-1.8.6/lib/geocoder/configuration.rb +151 -0
- data/geocoder-1.8.6/lib/geocoder/configuration_hash.rb +11 -0
- data/geocoder-1.8.6/lib/geocoder/esri_token.rb +38 -0
- data/geocoder-1.8.6/lib/geocoder/exceptions.rb +40 -0
- data/geocoder-1.8.6/lib/geocoder/ip_address.rb +36 -0
- data/geocoder-1.8.6/lib/geocoder/kernel_logger.rb +25 -0
- data/geocoder-1.8.6/lib/geocoder/logger.rb +47 -0
- data/geocoder-1.8.6/lib/geocoder/lookup.rb +155 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/abstract_api.rb +46 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/amap.rb +63 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/amazon_location_service.rb +58 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/azure.rb +56 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/baidu.rb +63 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/baidu_ip.rb +30 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/ban_data_gouv_fr.rb +143 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/base.rb +351 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/bing.rb +82 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/db_ip_com.rb +52 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/esri.rb +114 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/freegeoip.rb +62 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/geoapify.rb +78 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/geocoder_ca.rb +53 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/geocodio.rb +42 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/geoip2.rb +49 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/geoportail_lu.rb +65 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/google.rb +100 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/google_places_details.rb +64 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/google_places_search.rb +75 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/google_premier.rb +61 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/here.rb +73 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/ip2location.rb +71 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/ip2location_io.rb +62 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/ip2location_lite.rb +40 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/ipapi_com.rb +82 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/ipbase.rb +49 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/ipdata_co.rb +62 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/ipgeolocation.rb +51 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/ipinfo_io.rb +44 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/ipinfo_io_lite.rb +42 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/ipqualityscore.rb +50 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/ipregistry.rb +68 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/ipstack.rb +63 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/latlon.rb +58 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/location_iq.rb +54 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/mapbox.rb +60 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/mapquest.rb +58 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/maxmind.rb +90 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/maxmind_geoip2.rb +70 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/maxmind_local.rb +71 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/melissa_street.rb +41 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/nationaal_georegister_nl.rb +38 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/nominatim.rb +64 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/opencagedata.rb +65 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/osmnames.rb +57 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/pc_miler.rb +87 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/pdok_nl.rb +43 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/pelias.rb +63 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/photon.rb +89 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/pickpoint.rb +41 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/pointpin.rb +69 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/postcode_anywhere_uk.rb +50 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/postcodes_io.rb +31 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/smarty_streets.rb +68 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/telize.rb +75 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/tencent.rb +59 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/test.rb +49 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/twogis.rb +58 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/uk_ordnance_survey_names.rb +59 -0
- data/geocoder-1.8.6/lib/geocoder/lookups/yandex.rb +61 -0
- data/geocoder-1.8.6/lib/geocoder/models/active_record.rb +51 -0
- data/geocoder-1.8.6/lib/geocoder/models/base.rb +39 -0
- data/geocoder-1.8.6/lib/geocoder/models/mongo_base.rb +62 -0
- data/geocoder-1.8.6/lib/geocoder/models/mongo_mapper.rb +26 -0
- data/geocoder-1.8.6/lib/geocoder/models/mongoid.rb +32 -0
- data/geocoder-1.8.6/lib/geocoder/query.rb +125 -0
- data/geocoder-1.8.6/lib/geocoder/railtie.rb +26 -0
- data/geocoder-1.8.6/lib/geocoder/request.rb +114 -0
- data/geocoder-1.8.6/lib/geocoder/results/abstract_api.rb +146 -0
- data/geocoder-1.8.6/lib/geocoder/results/amap.rb +87 -0
- data/geocoder-1.8.6/lib/geocoder/results/amazon_location_service.rb +62 -0
- data/geocoder-1.8.6/lib/geocoder/results/azure.rb +65 -0
- data/geocoder-1.8.6/lib/geocoder/results/baidu.rb +75 -0
- data/geocoder-1.8.6/lib/geocoder/results/baidu_ip.rb +62 -0
- data/geocoder-1.8.6/lib/geocoder/results/ban_data_gouv_fr.rb +282 -0
- data/geocoder-1.8.6/lib/geocoder/results/base.rb +79 -0
- data/geocoder-1.8.6/lib/geocoder/results/bing.rb +52 -0
- data/geocoder-1.8.6/lib/geocoder/results/db_ip_com.rb +58 -0
- data/geocoder-1.8.6/lib/geocoder/results/esri.rb +78 -0
- data/geocoder-1.8.6/lib/geocoder/results/freegeoip.rb +40 -0
- data/geocoder-1.8.6/lib/geocoder/results/geoapify.rb +179 -0
- data/geocoder-1.8.6/lib/geocoder/results/geocoder_ca.rb +60 -0
- data/geocoder-1.8.6/lib/geocoder/results/geocodio.rb +78 -0
- data/geocoder-1.8.6/lib/geocoder/results/geoip2.rb +76 -0
- data/geocoder-1.8.6/lib/geocoder/results/geoportail_lu.rb +71 -0
- data/geocoder-1.8.6/lib/geocoder/results/google.rb +150 -0
- data/geocoder-1.8.6/lib/geocoder/results/google_places_details.rb +39 -0
- data/geocoder-1.8.6/lib/geocoder/results/google_places_search.rb +52 -0
- data/geocoder-1.8.6/lib/geocoder/results/google_premier.rb +6 -0
- data/geocoder-1.8.6/lib/geocoder/results/here.rb +77 -0
- data/geocoder-1.8.6/lib/geocoder/results/ip2location.rb +22 -0
- data/geocoder-1.8.6/lib/geocoder/results/ip2location_io.rb +21 -0
- data/geocoder-1.8.6/lib/geocoder/results/ip2location_lite.rb +47 -0
- data/geocoder-1.8.6/lib/geocoder/results/ipapi_com.rb +45 -0
- data/geocoder-1.8.6/lib/geocoder/results/ipbase.rb +40 -0
- data/geocoder-1.8.6/lib/geocoder/results/ipdata_co.rb +40 -0
- data/geocoder-1.8.6/lib/geocoder/results/ipgeolocation.rb +59 -0
- data/geocoder-1.8.6/lib/geocoder/results/ipinfo_io.rb +48 -0
- data/geocoder-1.8.6/lib/geocoder/results/ipinfo_io_lite.rb +16 -0
- data/geocoder-1.8.6/lib/geocoder/results/ipqualityscore.rb +54 -0
- data/geocoder-1.8.6/lib/geocoder/results/ipregistry.rb +304 -0
- data/geocoder-1.8.6/lib/geocoder/results/ipstack.rb +60 -0
- data/geocoder-1.8.6/lib/geocoder/results/latlon.rb +71 -0
- data/geocoder-1.8.6/lib/geocoder/results/location_iq.rb +6 -0
- data/geocoder-1.8.6/lib/geocoder/results/mapbox.rb +80 -0
- data/geocoder-1.8.6/lib/geocoder/results/mapquest.rb +48 -0
- data/geocoder-1.8.6/lib/geocoder/results/maxmind.rb +130 -0
- data/geocoder-1.8.6/lib/geocoder/results/maxmind_geoip2.rb +9 -0
- data/geocoder-1.8.6/lib/geocoder/results/maxmind_local.rb +44 -0
- data/geocoder-1.8.6/lib/geocoder/results/melissa_street.rb +46 -0
- data/geocoder-1.8.6/lib/geocoder/results/nationaal_georegister_nl.rb +62 -0
- data/geocoder-1.8.6/lib/geocoder/results/nominatim.rb +121 -0
- data/geocoder-1.8.6/lib/geocoder/results/opencagedata.rb +100 -0
- data/geocoder-1.8.6/lib/geocoder/results/osmnames.rb +56 -0
- data/geocoder-1.8.6/lib/geocoder/results/pc_miler.rb +98 -0
- data/geocoder-1.8.6/lib/geocoder/results/pdok_nl.rb +62 -0
- data/geocoder-1.8.6/lib/geocoder/results/pelias.rb +58 -0
- data/geocoder-1.8.6/lib/geocoder/results/photon.rb +119 -0
- data/geocoder-1.8.6/lib/geocoder/results/pickpoint.rb +6 -0
- data/geocoder-1.8.6/lib/geocoder/results/pointpin.rb +40 -0
- data/geocoder-1.8.6/lib/geocoder/results/postcode_anywhere_uk.rb +42 -0
- data/geocoder-1.8.6/lib/geocoder/results/postcodes_io.rb +40 -0
- data/geocoder-1.8.6/lib/geocoder/results/smarty_streets.rb +142 -0
- data/geocoder-1.8.6/lib/geocoder/results/telize.rb +40 -0
- data/geocoder-1.8.6/lib/geocoder/results/tencent.rb +72 -0
- data/geocoder-1.8.6/lib/geocoder/results/test.rb +33 -0
- data/geocoder-1.8.6/lib/geocoder/results/twogis.rb +76 -0
- data/geocoder-1.8.6/lib/geocoder/results/uk_ordnance_survey_names.rb +59 -0
- data/geocoder-1.8.6/lib/geocoder/results/yandex.rb +292 -0
- data/geocoder-1.8.6/lib/geocoder/sql.rb +110 -0
- data/geocoder-1.8.6/lib/geocoder/stores/active_record.rb +329 -0
- data/geocoder-1.8.6/lib/geocoder/stores/base.rb +115 -0
- data/geocoder-1.8.6/lib/geocoder/stores/mongo_base.rb +58 -0
- data/geocoder-1.8.6/lib/geocoder/stores/mongo_mapper.rb +13 -0
- data/geocoder-1.8.6/lib/geocoder/stores/mongoid.rb +13 -0
- data/geocoder-1.8.6/lib/geocoder/util.rb +29 -0
- data/geocoder-1.8.6/lib/geocoder/version.rb +3 -0
- data/geocoder-1.8.6/lib/geocoder.rb +48 -0
- data/geocoder-1.8.6/lib/maxmind_database.rb +109 -0
- data/geocoder-1.8.6/lib/tasks/geocoder.rake +54 -0
- data/geocoder-1.8.6/lib/tasks/maxmind.rake +73 -0
- data/ultra-fast-mod.gemspec +12 -0
- metadata +214 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'geocoder/lookups/base'
|
|
4
|
+
require 'geocoder/results/ban_data_gouv_fr'
|
|
5
|
+
|
|
6
|
+
module Geocoder::Lookup
|
|
7
|
+
class BanDataGouvFr < Base
|
|
8
|
+
|
|
9
|
+
def name
|
|
10
|
+
"Base Adresse Nationale Française"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def map_link_url(coordinates)
|
|
14
|
+
"https://www.openstreetmap.org/#map=19/#{coordinates.join('/')}"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private # ---------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
def base_query_url(query)
|
|
20
|
+
method = query.reverse_geocode? ? "reverse" : "search"
|
|
21
|
+
"#{protocol}://data.geopf.fr/geocodage/#{method}/?"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def any_result?(doc)
|
|
25
|
+
doc['features'] and doc['features'].any?
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def results(query)
|
|
29
|
+
if doc = fetch_data(query) and any_result?(doc)
|
|
30
|
+
[doc]
|
|
31
|
+
else
|
|
32
|
+
[]
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
#### PARAMS ####
|
|
37
|
+
|
|
38
|
+
def query_url_params(query)
|
|
39
|
+
query_ban_datagouv_fr_params(query).merge(super)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def query_ban_datagouv_fr_params(query)
|
|
43
|
+
query.reverse_geocode? ? reverse_geocode_ban_fr_params(query) : search_geocode_ban_fr_params(query)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
#### SEARCH GEOCODING PARAMS ####
|
|
47
|
+
#
|
|
48
|
+
# :q => required, full text search param)
|
|
49
|
+
|
|
50
|
+
# :limit => force limit number of results returned by raw API
|
|
51
|
+
# (default = 5) note : only first result is taken
|
|
52
|
+
# in account in geocoder
|
|
53
|
+
#
|
|
54
|
+
# :autocomplete => pass 0 to disable autocomplete treatment of :q
|
|
55
|
+
# (default = 1)
|
|
56
|
+
#
|
|
57
|
+
# :lat => force filter results around specific lat/lon
|
|
58
|
+
#
|
|
59
|
+
# :lon => force filter results around specific lat/lon
|
|
60
|
+
#
|
|
61
|
+
# :type => force filter the returned result type
|
|
62
|
+
# (check results for a list of accepted types)
|
|
63
|
+
#
|
|
64
|
+
# :postcode => force filter results on a specific city post code
|
|
65
|
+
#
|
|
66
|
+
# :citycode => force filter results on a specific city UUID INSEE code
|
|
67
|
+
#
|
|
68
|
+
# For up to date doc (in french only) : https://adresse.data.gouv.fr/api/
|
|
69
|
+
#
|
|
70
|
+
def search_geocode_ban_fr_params(query)
|
|
71
|
+
params = {
|
|
72
|
+
q: query.sanitized_text
|
|
73
|
+
}
|
|
74
|
+
unless (limit = query.options[:limit]).nil? || !limit_param_is_valid?(limit)
|
|
75
|
+
params[:limit] = limit.to_i
|
|
76
|
+
end
|
|
77
|
+
unless (autocomplete = query.options[:autocomplete]).nil? || !autocomplete_param_is_valid?(autocomplete)
|
|
78
|
+
params[:autocomplete] = autocomplete.to_s
|
|
79
|
+
end
|
|
80
|
+
unless (type = query.options[:type]).nil? || !type_param_is_valid?(type)
|
|
81
|
+
params[:type] = type.downcase
|
|
82
|
+
end
|
|
83
|
+
unless (postcode = query.options[:postcode]).nil? || !code_param_is_valid?(postcode)
|
|
84
|
+
params[:postcode] = postcode.to_s
|
|
85
|
+
end
|
|
86
|
+
unless (citycode = query.options[:citycode]).nil? || !code_param_is_valid?(citycode)
|
|
87
|
+
params[:citycode] = citycode.to_s
|
|
88
|
+
end
|
|
89
|
+
unless (lat = query.options[:lat]).nil? || !latitude_is_valid?(lat)
|
|
90
|
+
params[:lat] = lat
|
|
91
|
+
end
|
|
92
|
+
unless (lon = query.options[:lon]).nil? || !longitude_is_valid?(lon)
|
|
93
|
+
params[:lon] = lon
|
|
94
|
+
end
|
|
95
|
+
params
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
#### REVERSE GEOCODING PARAMS ####
|
|
99
|
+
#
|
|
100
|
+
# :lat => required
|
|
101
|
+
#
|
|
102
|
+
# :lon => required
|
|
103
|
+
#
|
|
104
|
+
# :type => force returned results type
|
|
105
|
+
# (check results for a list of accepted types)
|
|
106
|
+
#
|
|
107
|
+
def reverse_geocode_ban_fr_params(query)
|
|
108
|
+
lat_lon = query.coordinates
|
|
109
|
+
params = {
|
|
110
|
+
lat: lat_lon.first,
|
|
111
|
+
lon: lat_lon.last
|
|
112
|
+
}
|
|
113
|
+
unless (type = query.options[:type]).nil? || !type_param_is_valid?(type)
|
|
114
|
+
params[:type] = type.downcase
|
|
115
|
+
end
|
|
116
|
+
params
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def limit_param_is_valid?(param)
|
|
120
|
+
param.to_i.positive?
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def autocomplete_param_is_valid?(param)
|
|
124
|
+
[0,1].include?(param.to_i)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def type_param_is_valid?(param)
|
|
128
|
+
%w(housenumber street locality municipality).include?(param.downcase)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def code_param_is_valid?(param)
|
|
132
|
+
(1..99999).include?(param.to_i)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def latitude_is_valid?(param)
|
|
136
|
+
param.to_f <= 90 && param.to_f >= -90
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def longitude_is_valid?(param)
|
|
140
|
+
param.to_f <= 180 && param.to_f >= -180
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
require 'net/http'
|
|
2
|
+
require 'net/https'
|
|
3
|
+
require 'uri'
|
|
4
|
+
|
|
5
|
+
unless defined?(ActiveSupport::JSON)
|
|
6
|
+
begin
|
|
7
|
+
require 'json'
|
|
8
|
+
rescue LoadError
|
|
9
|
+
raise LoadError, "Please install the 'json' or 'json_pure' gem to parse geocoder results."
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module Geocoder
|
|
14
|
+
module Lookup
|
|
15
|
+
|
|
16
|
+
class Base
|
|
17
|
+
def initialize
|
|
18
|
+
@cache = nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
##
|
|
22
|
+
# Human-readable name of the geocoding API.
|
|
23
|
+
#
|
|
24
|
+
def name
|
|
25
|
+
fail
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
##
|
|
29
|
+
# Symbol which is used in configuration to refer to this Lookup.
|
|
30
|
+
#
|
|
31
|
+
def handle
|
|
32
|
+
str = self.class.to_s
|
|
33
|
+
str[str.rindex(':')+1..-1].gsub(/([a-z\d]+)([A-Z])/,'\1_\2').downcase.to_sym
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
##
|
|
37
|
+
# Query the geocoding API and return a Geocoder::Result object.
|
|
38
|
+
# Returns +nil+ on timeout or error.
|
|
39
|
+
#
|
|
40
|
+
# Takes a search string (eg: "Mississippi Coast Coliseumf, Biloxi, MS",
|
|
41
|
+
# "205.128.54.202") for geocoding, or coordinates (latitude, longitude)
|
|
42
|
+
# for reverse geocoding. Returns an array of <tt>Geocoder::Result</tt>s.
|
|
43
|
+
#
|
|
44
|
+
def search(query, options = {})
|
|
45
|
+
query = Geocoder::Query.new(query, options) unless query.is_a?(Geocoder::Query)
|
|
46
|
+
results(query).map{ |r|
|
|
47
|
+
result = result_class.new(r)
|
|
48
|
+
result.cache_hit = @cache_hit if cache
|
|
49
|
+
result
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
##
|
|
54
|
+
# Return the URL for a map of the given coordinates.
|
|
55
|
+
#
|
|
56
|
+
# Not necessarily implemented by all subclasses as only some lookups
|
|
57
|
+
# also provide maps.
|
|
58
|
+
#
|
|
59
|
+
def map_link_url(coordinates)
|
|
60
|
+
nil
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
##
|
|
64
|
+
# Array containing string descriptions of keys required by the API.
|
|
65
|
+
# Empty array if keys are optional or not required.
|
|
66
|
+
#
|
|
67
|
+
def required_api_key_parts
|
|
68
|
+
[]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
##
|
|
72
|
+
# URL to use for querying the geocoding engine.
|
|
73
|
+
#
|
|
74
|
+
# Subclasses should not modify this method. Instead they should define
|
|
75
|
+
# base_query_url and url_query_string. If absolutely necessary to
|
|
76
|
+
# subclss this method, they must also subclass #cache_key.
|
|
77
|
+
#
|
|
78
|
+
def query_url(query)
|
|
79
|
+
base_query_url(query) + url_query_string(query)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
##
|
|
83
|
+
# The working Cache object.
|
|
84
|
+
#
|
|
85
|
+
def cache
|
|
86
|
+
if @cache.nil? and store = configuration.cache
|
|
87
|
+
cache_options = configuration.cache_options
|
|
88
|
+
@cache = Cache.new(store, cache_options)
|
|
89
|
+
end
|
|
90
|
+
@cache
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
##
|
|
94
|
+
# Array containing the protocols supported by the api.
|
|
95
|
+
# Should be set to [:http] if only HTTP is supported
|
|
96
|
+
# or [:https] if only HTTPS is supported.
|
|
97
|
+
#
|
|
98
|
+
def supported_protocols
|
|
99
|
+
[:http, :https]
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
private # -------------------------------------------------------------
|
|
103
|
+
|
|
104
|
+
##
|
|
105
|
+
# String which, when concatenated with url_query_string(query)
|
|
106
|
+
# produces the full query URL. Should include the "?" a the end.
|
|
107
|
+
#
|
|
108
|
+
def base_query_url(query)
|
|
109
|
+
fail
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
##
|
|
113
|
+
# An object with configuration data for this particular lookup.
|
|
114
|
+
#
|
|
115
|
+
def configuration
|
|
116
|
+
Geocoder.config_for_lookup(handle)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
##
|
|
120
|
+
# Object used to make HTTP requests.
|
|
121
|
+
#
|
|
122
|
+
def http_client
|
|
123
|
+
proxy_name = "#{protocol}_proxy"
|
|
124
|
+
if proxy = configuration.send(proxy_name)
|
|
125
|
+
proxy_url = !!(proxy =~ /^#{protocol}/) ? proxy : protocol + '://' + proxy
|
|
126
|
+
begin
|
|
127
|
+
uri = URI.parse(proxy_url)
|
|
128
|
+
rescue URI::InvalidURIError
|
|
129
|
+
raise ConfigurationError,
|
|
130
|
+
"Error parsing #{protocol.upcase} proxy URL: '#{proxy_url}'"
|
|
131
|
+
end
|
|
132
|
+
Net::HTTP::Proxy(uri.host, uri.port, uri.user, uri.password)
|
|
133
|
+
else
|
|
134
|
+
Net::HTTP
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
##
|
|
139
|
+
# Geocoder::Result object or nil on timeout or other error.
|
|
140
|
+
#
|
|
141
|
+
def results(query)
|
|
142
|
+
fail
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def query_url_params(query)
|
|
146
|
+
query.options[:params] || {}
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def url_query_string(query)
|
|
150
|
+
hash_to_query(
|
|
151
|
+
query_url_params(query).reject{ |key,value| value.nil? }
|
|
152
|
+
)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
##
|
|
156
|
+
# Key to use for caching a geocoding result. Usually this will be the
|
|
157
|
+
# request URL, but in cases where OAuth is used and the nonce,
|
|
158
|
+
# timestamp, etc varies from one request to another, we need to use
|
|
159
|
+
# something else (like the URL before OAuth encoding).
|
|
160
|
+
#
|
|
161
|
+
def cache_key(query)
|
|
162
|
+
base_query_url(query) + hash_to_query(cache_key_params(query))
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def cache_key_params(query)
|
|
166
|
+
# omit api_key and token because they may vary among requests
|
|
167
|
+
query_url_params(query).reject do |key,value|
|
|
168
|
+
key.to_s.match(/(key|token)/)
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
##
|
|
173
|
+
# Class of the result objects
|
|
174
|
+
#
|
|
175
|
+
def result_class
|
|
176
|
+
Geocoder::Result.const_get(self.class.to_s.split(":").last)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
##
|
|
180
|
+
# Raise exception if configuration specifies it should be raised.
|
|
181
|
+
# Return false if exception not raised.
|
|
182
|
+
#
|
|
183
|
+
def raise_error(error, message = nil)
|
|
184
|
+
exceptions = configuration.always_raise
|
|
185
|
+
if exceptions == :all or exceptions.include?( error.is_a?(Class) ? error : error.class )
|
|
186
|
+
raise error, message
|
|
187
|
+
else
|
|
188
|
+
false
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
##
|
|
193
|
+
# Returns a parsed search result (Ruby hash).
|
|
194
|
+
#
|
|
195
|
+
def fetch_data(query)
|
|
196
|
+
parse_raw_data fetch_raw_data(query)
|
|
197
|
+
rescue SocketError => err
|
|
198
|
+
raise_error(err) or Geocoder.log(:warn, "Geocoding API connection cannot be established.")
|
|
199
|
+
rescue Errno::ECONNREFUSED => err
|
|
200
|
+
raise_error(err) or Geocoder.log(:warn, "Geocoding API connection refused.")
|
|
201
|
+
rescue Geocoder::NetworkError => err
|
|
202
|
+
raise_error(err) or Geocoder.log(:warn, "Geocoding API connection is either unreacheable or reset by the peer")
|
|
203
|
+
rescue Timeout::Error => err
|
|
204
|
+
raise_error(err) or Geocoder.log(:warn, "Geocoding API not responding fast enough " +
|
|
205
|
+
"(use Geocoder.configure(:timeout => ...) to set limit).")
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def parse_json(data)
|
|
209
|
+
if defined?(ActiveSupport::JSON)
|
|
210
|
+
ActiveSupport::JSON.decode(data)
|
|
211
|
+
else
|
|
212
|
+
JSON.parse(data)
|
|
213
|
+
end
|
|
214
|
+
rescue
|
|
215
|
+
unless raise_error(ResponseParseError.new(data))
|
|
216
|
+
Geocoder.log(:warn, "Geocoding API's response was not valid JSON")
|
|
217
|
+
Geocoder.log(:debug, "Raw response: #{data}")
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
##
|
|
222
|
+
# Parses a raw search result (returns hash or array).
|
|
223
|
+
#
|
|
224
|
+
def parse_raw_data(raw_data)
|
|
225
|
+
parse_json(raw_data)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
##
|
|
229
|
+
# Protocol to use for communication with geocoding services.
|
|
230
|
+
# Set in configuration but not available for every service.
|
|
231
|
+
#
|
|
232
|
+
def protocol
|
|
233
|
+
"http" + (use_ssl? ? "s" : "")
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def valid_response?(response)
|
|
237
|
+
(200..399).include?(response.code.to_i)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
##
|
|
241
|
+
# Fetch a raw geocoding result (JSON string).
|
|
242
|
+
# The result might or might not be cached.
|
|
243
|
+
#
|
|
244
|
+
def fetch_raw_data(query)
|
|
245
|
+
key = cache_key(query)
|
|
246
|
+
if cache and body = cache[key]
|
|
247
|
+
@cache_hit = true
|
|
248
|
+
else
|
|
249
|
+
check_api_key_configuration!(query)
|
|
250
|
+
response = make_api_request(query)
|
|
251
|
+
check_response_for_errors!(response)
|
|
252
|
+
body = response.body
|
|
253
|
+
|
|
254
|
+
# apply the charset from the Content-Type header, if possible
|
|
255
|
+
ct = response['content-type']
|
|
256
|
+
|
|
257
|
+
if ct && ct['charset']
|
|
258
|
+
charset = ct.split(';').select do |s|
|
|
259
|
+
s['charset']
|
|
260
|
+
end.first.to_s.split('=')
|
|
261
|
+
if charset.length == 2
|
|
262
|
+
body.force_encoding(charset.last) rescue ArgumentError
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
if cache and valid_response?(response)
|
|
267
|
+
cache[key] = body
|
|
268
|
+
end
|
|
269
|
+
@cache_hit = false
|
|
270
|
+
end
|
|
271
|
+
body
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def check_response_for_errors!(response)
|
|
275
|
+
if response.code.to_i == 400
|
|
276
|
+
raise_error(Geocoder::InvalidRequest) ||
|
|
277
|
+
Geocoder.log(:warn, "Geocoding API error: 400 Bad Request")
|
|
278
|
+
elsif response.code.to_i == 401
|
|
279
|
+
raise_error(Geocoder::RequestDenied) ||
|
|
280
|
+
Geocoder.log(:warn, "Geocoding API error: 401 Unauthorized")
|
|
281
|
+
elsif response.code.to_i == 402
|
|
282
|
+
raise_error(Geocoder::OverQueryLimitError) ||
|
|
283
|
+
Geocoder.log(:warn, "Geocoding API error: 402 Payment Required")
|
|
284
|
+
elsif response.code.to_i == 429
|
|
285
|
+
raise_error(Geocoder::OverQueryLimitError) ||
|
|
286
|
+
Geocoder.log(:warn, "Geocoding API error: 429 Too Many Requests")
|
|
287
|
+
elsif response.code.to_i == 503
|
|
288
|
+
raise_error(Geocoder::ServiceUnavailable) ||
|
|
289
|
+
Geocoder.log(:warn, "Geocoding API error: 503 Service Unavailable")
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
##
|
|
294
|
+
# Make an HTTP(S) request to a geocoding API and
|
|
295
|
+
# return the response object.
|
|
296
|
+
#
|
|
297
|
+
def make_api_request(query)
|
|
298
|
+
uri = URI.parse(query_url(query))
|
|
299
|
+
Geocoder.log(:debug, "Geocoder: HTTP request being made for #{uri.to_s}")
|
|
300
|
+
http_client.start(uri.host, uri.port, use_ssl: use_ssl?, open_timeout: configuration.timeout, read_timeout: configuration.timeout) do |client|
|
|
301
|
+
configure_ssl!(client) if use_ssl?
|
|
302
|
+
req = Net::HTTP::Get.new(uri.request_uri, configuration.http_headers)
|
|
303
|
+
if configuration.basic_auth[:user] and configuration.basic_auth[:password]
|
|
304
|
+
req.basic_auth(
|
|
305
|
+
configuration.basic_auth[:user],
|
|
306
|
+
configuration.basic_auth[:password]
|
|
307
|
+
)
|
|
308
|
+
end
|
|
309
|
+
client.request(req)
|
|
310
|
+
end
|
|
311
|
+
rescue Timeout::Error
|
|
312
|
+
raise Geocoder::LookupTimeout
|
|
313
|
+
rescue Errno::EHOSTUNREACH, Errno::ETIMEDOUT, Errno::ENETUNREACH, Errno::ECONNRESET
|
|
314
|
+
raise Geocoder::NetworkError
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
def use_ssl?
|
|
318
|
+
if supported_protocols == [:https]
|
|
319
|
+
true
|
|
320
|
+
elsif supported_protocols == [:http]
|
|
321
|
+
false
|
|
322
|
+
else
|
|
323
|
+
configuration.use_https
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def configure_ssl!(client); end
|
|
328
|
+
|
|
329
|
+
def check_api_key_configuration!(query)
|
|
330
|
+
key_parts = query.lookup.required_api_key_parts
|
|
331
|
+
if key_parts.size > Array(configuration.api_key).size
|
|
332
|
+
parts_string = key_parts.size == 1 ? key_parts.first : key_parts
|
|
333
|
+
raise Geocoder::ConfigurationError,
|
|
334
|
+
"The #{query.lookup.name} API requires a key to be configured: " +
|
|
335
|
+
parts_string.inspect
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
##
|
|
340
|
+
# Simulate ActiveSupport's Object#to_query.
|
|
341
|
+
# Removes any keys with nil value.
|
|
342
|
+
#
|
|
343
|
+
def hash_to_query(hash)
|
|
344
|
+
require 'cgi' unless defined?(CGI) && defined?(CGI.escape)
|
|
345
|
+
hash.collect{ |p|
|
|
346
|
+
p[1].nil? ? nil : p.map{ |i| CGI.escape i.to_s } * '='
|
|
347
|
+
}.compact.sort * '&'
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
require 'geocoder/lookups/base'
|
|
2
|
+
require "geocoder/results/bing"
|
|
3
|
+
|
|
4
|
+
module Geocoder::Lookup
|
|
5
|
+
class Bing < Base
|
|
6
|
+
|
|
7
|
+
def name
|
|
8
|
+
"Bing"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def map_link_url(coordinates)
|
|
12
|
+
"http://www.bing.com/maps/default.aspx?cp=#{coordinates.join('~')}"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def required_api_key_parts
|
|
16
|
+
["key"]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private # ---------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
def base_query_url(query)
|
|
22
|
+
text = ERB::Util.url_encode(query.sanitized_text.strip)
|
|
23
|
+
url = "#{protocol}://dev.virtualearth.net/REST/v1/Locations/"
|
|
24
|
+
if query.reverse_geocode?
|
|
25
|
+
url + "#{text}?"
|
|
26
|
+
else
|
|
27
|
+
if r = query.options[:region]
|
|
28
|
+
url << "#{r}/"
|
|
29
|
+
end
|
|
30
|
+
# use the more forgiving 'unstructured' query format to allow special
|
|
31
|
+
# chars, newlines, brackets, typos.
|
|
32
|
+
url + "?q=#{text}&"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def results(query)
|
|
37
|
+
return [] unless doc = fetch_data(query)
|
|
38
|
+
|
|
39
|
+
if doc['statusCode'] == 200
|
|
40
|
+
return doc['resourceSets'].first['estimatedTotal'] > 0 ? doc['resourceSets'].first['resources'] : []
|
|
41
|
+
elsif doc['statusCode'] == 401 and doc["authenticationResultCode"] == "InvalidCredentials"
|
|
42
|
+
raise_error(Geocoder::InvalidApiKey) || Geocoder.log(:warn, "Invalid Bing API key.")
|
|
43
|
+
elsif doc['statusCode'] == 403
|
|
44
|
+
raise_error(Geocoder::RequestDenied) || Geocoder.log(:warn, "Bing Geocoding API error: Forbidden Request")
|
|
45
|
+
elsif [500, 503].include?(doc['statusCode'])
|
|
46
|
+
raise_error(Geocoder::ServiceUnavailable) ||
|
|
47
|
+
Geocoder.log(:warn, "Bing Geocoding API error: Service Unavailable")
|
|
48
|
+
else
|
|
49
|
+
Geocoder.log(:warn, "Bing Geocoding API error: #{doc['statusCode']} (#{doc['statusDescription']}).")
|
|
50
|
+
end
|
|
51
|
+
return []
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def query_url_params(query)
|
|
55
|
+
{
|
|
56
|
+
key: configuration.api_key,
|
|
57
|
+
culture: (query.language || configuration.language)
|
|
58
|
+
}.merge(super)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def check_response_for_errors!(response)
|
|
62
|
+
super
|
|
63
|
+
if server_overloaded?(response)
|
|
64
|
+
raise_error(Geocoder::ServiceUnavailable) ||
|
|
65
|
+
Geocoder.log(:warn, "Bing Geocoding API error: Service Unavailable")
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def valid_response?(response)
|
|
70
|
+
super(response) and not server_overloaded?(response)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def server_overloaded?(response)
|
|
74
|
+
# Occasionally, the servers processing service requests can be overloaded,
|
|
75
|
+
# and you may receive some responses that contain no results for queries that
|
|
76
|
+
# you would normally receive a result. To identify this situation,
|
|
77
|
+
# check the HTTP headers of the response. If the HTTP header X-MS-BM-WS-INFO is set to 1,
|
|
78
|
+
# it is best to wait a few seconds and try again.
|
|
79
|
+
response['x-ms-bm-ws-info'].to_i == 1
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'geocoder/lookups/base'
|
|
2
|
+
require 'geocoder/results/db_ip_com'
|
|
3
|
+
|
|
4
|
+
module Geocoder::Lookup
|
|
5
|
+
class DbIpCom < Base
|
|
6
|
+
|
|
7
|
+
def name
|
|
8
|
+
'DB-IP.com'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def supported_protocols
|
|
12
|
+
[:https, :http]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def required_api_key_parts
|
|
16
|
+
['api_key']
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private # ----------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
def base_query_url(query)
|
|
22
|
+
"#{protocol}://api.db-ip.com/v2/#{configuration.api_key}/#{query.sanitized_text}?"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
##
|
|
26
|
+
# Same as query_url but without the api key.
|
|
27
|
+
#
|
|
28
|
+
def cache_key(query)
|
|
29
|
+
"#{protocol}://api.db-ip.com/v2/#{query.sanitized_text}?" + hash_to_query(cache_key_params(query))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def results(query)
|
|
33
|
+
return [] unless (doc = fetch_data(query))
|
|
34
|
+
|
|
35
|
+
case doc['error']
|
|
36
|
+
when 'maximum number of queries per day exceeded'
|
|
37
|
+
raise_error Geocoder::OverQueryLimitError ||
|
|
38
|
+
Geocoder.log(:warn, 'DB-API query limit exceeded.')
|
|
39
|
+
|
|
40
|
+
when 'invalid API key'
|
|
41
|
+
raise_error Geocoder::InvalidApiKey ||
|
|
42
|
+
Geocoder.log(:warn, 'Invalid DB-IP API key.')
|
|
43
|
+
when nil
|
|
44
|
+
[doc]
|
|
45
|
+
|
|
46
|
+
else
|
|
47
|
+
raise_error Geocoder::Error ||
|
|
48
|
+
Geocoder.log(:warn, "Request failed: #{doc['error']}")
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|