geocoder 1.6.3 → 1.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +61 -0
  3. data/LICENSE +1 -1
  4. data/README.md +329 -233
  5. data/examples/app_defined_lookup_services.rb +22 -0
  6. data/lib/generators/geocoder/config/templates/initializer.rb +6 -1
  7. data/lib/geocoder/cache.rb +16 -33
  8. data/lib/geocoder/cache_stores/base.rb +40 -0
  9. data/lib/geocoder/cache_stores/generic.rb +35 -0
  10. data/lib/geocoder/cache_stores/redis.rb +34 -0
  11. data/lib/geocoder/configuration.rb +19 -5
  12. data/lib/geocoder/configuration_hash.rb +4 -4
  13. data/lib/geocoder/ip_address.rb +6 -0
  14. data/lib/geocoder/lookup.rb +32 -4
  15. data/lib/geocoder/lookups/abstract_api.rb +46 -0
  16. data/lib/geocoder/lookups/amap.rb +2 -2
  17. data/lib/geocoder/lookups/amazon_location_service.rb +54 -0
  18. data/lib/geocoder/lookups/ban_data_gouv_fr.rb +1 -1
  19. data/lib/geocoder/lookups/base.rb +2 -1
  20. data/lib/geocoder/lookups/bing.rb +1 -1
  21. data/lib/geocoder/lookups/esri.rb +4 -0
  22. data/lib/geocoder/lookups/freegeoip.rb +8 -6
  23. data/lib/geocoder/lookups/geoapify.rb +78 -0
  24. data/lib/geocoder/lookups/geocodio.rb +1 -1
  25. data/lib/geocoder/lookups/geoip2.rb +4 -0
  26. data/lib/geocoder/lookups/geoportail_lu.rb +1 -1
  27. data/lib/geocoder/lookups/google.rb +7 -2
  28. data/lib/geocoder/lookups/google_places_details.rb +26 -12
  29. data/lib/geocoder/lookups/google_places_search.rb +45 -2
  30. data/lib/geocoder/lookups/google_premier.rb +4 -0
  31. data/lib/geocoder/lookups/here.rb +25 -20
  32. data/lib/geocoder/lookups/ip2location.rb +10 -6
  33. data/lib/geocoder/lookups/ipbase.rb +49 -0
  34. data/lib/geocoder/lookups/ipdata_co.rb +1 -1
  35. data/lib/geocoder/lookups/ipqualityscore.rb +50 -0
  36. data/lib/geocoder/lookups/location_iq.rb +5 -1
  37. data/lib/geocoder/lookups/maxmind_local.rb +7 -1
  38. data/lib/geocoder/lookups/melissa_street.rb +41 -0
  39. data/lib/geocoder/lookups/photon.rb +89 -0
  40. data/lib/geocoder/lookups/test.rb +5 -0
  41. data/lib/geocoder/lookups/twogis.rb +58 -0
  42. data/lib/geocoder/lookups/uk_ordnance_survey_names.rb +1 -1
  43. data/lib/geocoder/lookups/yandex.rb +3 -3
  44. data/lib/geocoder/results/abstract_api.rb +146 -0
  45. data/lib/geocoder/results/amazon_location_service.rb +57 -0
  46. data/lib/geocoder/results/ban_data_gouv_fr.rb +26 -1
  47. data/lib/geocoder/results/db_ip_com.rb +1 -1
  48. data/lib/geocoder/results/esri.rb +5 -2
  49. data/lib/geocoder/results/geoapify.rb +179 -0
  50. data/lib/geocoder/results/here.rb +20 -25
  51. data/lib/geocoder/results/ipbase.rb +40 -0
  52. data/lib/geocoder/results/ipqualityscore.rb +54 -0
  53. data/lib/geocoder/results/ipregistry.rb +4 -8
  54. data/lib/geocoder/results/mapbox.rb +10 -4
  55. data/lib/geocoder/results/melissa_street.rb +46 -0
  56. data/lib/geocoder/results/nationaal_georegister_nl.rb +1 -1
  57. data/lib/geocoder/results/nominatim.rb +27 -15
  58. data/lib/geocoder/results/photon.rb +119 -0
  59. data/lib/geocoder/results/twogis.rb +76 -0
  60. data/lib/geocoder/util.rb +29 -0
  61. data/lib/geocoder/version.rb +1 -1
  62. metadata +24 -6
  63. data/examples/autoexpire_cache_dalli.rb +0 -62
  64. data/examples/autoexpire_cache_redis.rb +0 -30
  65. data/lib/hash_recursive_merge.rb +0 -73
@@ -0,0 +1,146 @@
1
+ require 'geocoder/results/base'
2
+
3
+ module Geocoder
4
+ module Result
5
+ class AbstractApi < Base
6
+
7
+ ##
8
+ # Geolocation
9
+
10
+ def state
11
+ @data['region']
12
+ end
13
+
14
+ def state_code
15
+ @data['region_iso_code']
16
+ end
17
+
18
+ def city
19
+ @data["city"]
20
+ end
21
+
22
+ def city_geoname_id
23
+ @data["city_geoname_id"]
24
+ end
25
+
26
+ def region_geoname_id
27
+ @data["region_geoname_id"]
28
+ end
29
+
30
+ def postal_code
31
+ @data["postal_code"]
32
+ end
33
+
34
+ def country
35
+ @data["country"]
36
+ end
37
+
38
+ def country_code
39
+ @data["country_code"]
40
+ end
41
+
42
+ def country_geoname_id
43
+ @data["country_geoname_id"]
44
+ end
45
+
46
+ def country_is_eu
47
+ @data["country_is_eu"]
48
+ end
49
+
50
+ def continent
51
+ @data["continent"]
52
+ end
53
+
54
+ def continent_code
55
+ @data["continent_code"]
56
+ end
57
+
58
+ def continent_geoname_id
59
+ @data["continent_geoname_id"]
60
+ end
61
+
62
+ ##
63
+ # Security
64
+
65
+ def is_vpn?
66
+ @data.dig "security", "is_vpn"
67
+ end
68
+
69
+ ##
70
+ # Timezone
71
+
72
+ def timezone_name
73
+ @data.dig "timezone", "name"
74
+ end
75
+
76
+ def timezone_abbreviation
77
+ @data.dig "timezone", "abbreviation"
78
+ end
79
+
80
+ def timezone_gmt_offset
81
+ @data.dig "timezone", "gmt_offset"
82
+ end
83
+
84
+ def timezone_current_time
85
+ @data.dig "timezone", "current_time"
86
+ end
87
+
88
+ def timezone_is_dst
89
+ @data.dig "timezone", "is_dst"
90
+ end
91
+
92
+ ##
93
+ # Flag
94
+
95
+ def flag_emoji
96
+ @data.dig "flag", "emoji"
97
+ end
98
+
99
+ def flag_unicode
100
+ @data.dig "flag", "unicode"
101
+ end
102
+
103
+ def flag_png
104
+ @data.dig "flag", "png"
105
+ end
106
+
107
+ def flag_svg
108
+ @data.dig "flag", "svg"
109
+ end
110
+
111
+ ##
112
+ # Currency
113
+
114
+ def currency_currency_name
115
+ @data.dig "currency", "currency_name"
116
+ end
117
+
118
+ def currency_currency_code
119
+ @data.dig "currency", "currency_code"
120
+ end
121
+
122
+ ##
123
+ # Connection
124
+
125
+ def connection_autonomous_system_number
126
+ @data.dig "connection", "autonomous_system_number"
127
+ end
128
+
129
+ def connection_autonomous_system_organization
130
+ @data.dig "connection", "autonomous_system_organization"
131
+ end
132
+
133
+ def connection_connection_type
134
+ @data.dig "connection", "connection_type"
135
+ end
136
+
137
+ def connection_isp_name
138
+ @data.dig "connection", "isp_name"
139
+ end
140
+
141
+ def connection_organization_name
142
+ @data.dig "connection", "organization_name"
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,57 @@
1
+ require 'geocoder/results/base'
2
+
3
+ module Geocoder::Result
4
+ class AmazonLocationService < Base
5
+ def initialize(result)
6
+ @place = result
7
+ end
8
+
9
+ def coordinates
10
+ [@place.geometry.point[1], @place.geometry.point[0]]
11
+ end
12
+
13
+ def address
14
+ @place.label
15
+ end
16
+
17
+ def neighborhood
18
+ @place.neighborhood
19
+ end
20
+
21
+ def route
22
+ @place.street
23
+ end
24
+
25
+ def city
26
+ @place.municipality || @place.sub_region
27
+ end
28
+
29
+ def state
30
+ @place.region
31
+ end
32
+
33
+ def state_code
34
+ @place.region
35
+ end
36
+
37
+ def province
38
+ @place.region
39
+ end
40
+
41
+ def province_code
42
+ @place.region
43
+ end
44
+
45
+ def postal_code
46
+ @place.postal_code
47
+ end
48
+
49
+ def country
50
+ @place.country
51
+ end
52
+
53
+ def country_code
54
+ @place.country
55
+ end
56
+ end
57
+ end
@@ -4,6 +4,27 @@ require 'geocoder/results/base'
4
4
  module Geocoder::Result
5
5
  class BanDataGouvFr < Base
6
6
 
7
+ STATE_CODE_MAPPINGS = {
8
+ "Guadeloupe" => "01",
9
+ "Martinique" => "02",
10
+ "Guyane" => "03",
11
+ "La Réunion" => "04",
12
+ "Mayotte" => "06",
13
+ "Île-de-France" => "11",
14
+ "Centre-Val de Loire" => "24",
15
+ "Bourgogne-Franche-Comté" => "27",
16
+ "Normandie" => "28",
17
+ "Hauts-de-France" => "32",
18
+ "Grand Est" => "44",
19
+ "Pays de la Loire" => "52",
20
+ "Bretagne" => "53",
21
+ "Nouvelle-Aquitaine" => "75",
22
+ "Occitanie" => "76",
23
+ "Auvergne-Rhône-Alpes" => "84",
24
+ "Provence-Alpes-Côte d'Azur" => "93",
25
+ "Corse" => "94"
26
+ }.freeze
27
+
7
28
  #### BASE METHODS ####
8
29
 
9
30
  def self.response_attributes
@@ -209,6 +230,10 @@ module Geocoder::Result
209
230
  end
210
231
  end
211
232
 
233
+ def region_code
234
+ STATE_CODE_MAPPINGS[region_name]
235
+ end
236
+
212
237
  def country
213
238
  "France"
214
239
  end
@@ -235,7 +260,7 @@ module Geocoder::Result
235
260
  alias_method :street, :street_name
236
261
  alias_method :city, :city_name
237
262
  alias_method :state, :region_name
238
- alias_method :state_code, :state
263
+ alias_method :state_code, :region_code
239
264
 
240
265
  #### CITIES' METHODS ####
241
266
 
@@ -16,7 +16,7 @@ module Geocoder::Result
16
16
  end
17
17
 
18
18
  def state_code
19
- @data['stateProv']
19
+ @data['stateProvCode']
20
20
  end
21
21
  alias_method :state, :state_code
22
22
 
@@ -16,11 +16,14 @@ module Geocoder::Result
16
16
  end
17
17
  end
18
18
 
19
- def state_code
19
+ def state
20
20
  attributes['Region']
21
21
  end
22
22
 
23
- alias_method :state, :state_code
23
+ def state_code
24
+ abbr = attributes['RegionAbbr']
25
+ abbr.to_s == "" ? state : abbr
26
+ end
24
27
 
25
28
  def country
26
29
  country_key = reverse_geocode? ? "CountryCode" : "Country"
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'geocoder/results/base'
4
+
5
+ module Geocoder
6
+ module Result
7
+ # https://apidocs.geoapify.com/docs/geocoding/api
8
+ class Geoapify < Base
9
+ def address(_format = :full)
10
+ properties['formatted']
11
+ end
12
+
13
+ def address_line1
14
+ properties['address_line1']
15
+ end
16
+
17
+ def address_line2
18
+ properties['address_line2']
19
+ end
20
+
21
+ def house_number
22
+ properties['housenumber']
23
+ end
24
+
25
+ def street
26
+ properties['street']
27
+ end
28
+
29
+ def postal_code
30
+ properties['postcode']
31
+ end
32
+
33
+ def district
34
+ properties['district']
35
+ end
36
+
37
+ def suburb
38
+ properties['suburb']
39
+ end
40
+
41
+ def city
42
+ properties['city']
43
+ end
44
+
45
+ def county
46
+ properties['county']
47
+ end
48
+
49
+ def state
50
+ properties['state']
51
+ end
52
+
53
+ # Not currently available in the API
54
+ def state_code
55
+ ''
56
+ end
57
+
58
+ def country
59
+ properties['country']
60
+ end
61
+
62
+ def country_code
63
+ return unless properties['country_code']
64
+
65
+ properties['country_code'].upcase
66
+ end
67
+
68
+ def coordinates
69
+ return unless properties['lat']
70
+ return unless properties['lon']
71
+
72
+ [properties['lat'], properties['lon']]
73
+ end
74
+
75
+ # See: https://tools.ietf.org/html/rfc7946#section-3.1
76
+ #
77
+ # Each feature has a "Point" type in the Geoapify API.
78
+ def geometry
79
+ return unless data['geometry']
80
+
81
+ symbol_hash data['geometry']
82
+ end
83
+
84
+ # See: https://tools.ietf.org/html/rfc7946#section-5
85
+ def bounds
86
+ data['bbox']
87
+ end
88
+
89
+ # Type of the result, one of:
90
+ #
91
+ # * :unknown
92
+ # * :amenity
93
+ # * :building
94
+ # * :street
95
+ # * :suburb
96
+ # * :district
97
+ # * :postcode
98
+ # * :city
99
+ # * :county
100
+ # * :state
101
+ # * :country
102
+ #
103
+ def type
104
+ return :unknown unless properties['result_type']
105
+
106
+ properties['result_type'].to_sym
107
+ end
108
+
109
+ # Distance in meters to given bias:proximity or to given coordinates for
110
+ # reverse geocoding
111
+ def distance
112
+ properties['distance']
113
+ end
114
+
115
+ # Calculated rank for the result, containing the following keys:
116
+ #
117
+ # * `popularity` - The popularity score of the result
118
+ # * `confidence` - The confidence value of the result (0-1)
119
+ # * `match_type` - The result's match type, one of following:
120
+ # * full_match
121
+ # * inner_part
122
+ # * match_by_building
123
+ # * match_by_street
124
+ # * match_by_postcode
125
+ # * match_by_city_or_disrict
126
+ # * match_by_country_or_state
127
+ #
128
+ # Example:
129
+ # {
130
+ # popularity: 8.615793062435909,
131
+ # confidence: 0.88,
132
+ # match_type: :full_match
133
+ # }
134
+ def rank
135
+ return unless properties['rank']
136
+
137
+ r = symbol_hash(properties['rank'])
138
+ r[:match_type] = r[:match_type].to_sym if r[:match_type]
139
+ r
140
+ end
141
+
142
+ # Examples:
143
+ #
144
+ # Open
145
+ # {
146
+ # sourcename: 'openstreetmap',
147
+ # wheelchair: 'limited',
148
+ # wikidata: 'Q186125',
149
+ # wikipedia: 'en:Madison Square Garden',
150
+ # website: 'http://www.thegarden.com/',
151
+ # phone: '12124656741',
152
+ # osm_type: 'W',
153
+ # osm_id: 138141251,
154
+ # continent: 'North America',
155
+ # }
156
+ def datasource
157
+ return unless properties['datasource']
158
+
159
+ symbol_hash properties['datasource']
160
+ end
161
+
162
+ private
163
+
164
+ def properties
165
+ @properties ||= data['properties'] || {}
166
+ end
167
+
168
+ def symbol_hash(orig_hash)
169
+ {}.tap do |result|
170
+ orig_hash.each_key do |key|
171
+ next unless orig_hash[key]
172
+
173
+ result[key.to_sym] = orig_hash[key]
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end
179
+ 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['Label']
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['Location']['DisplayPosition']
18
- [d['Latitude'].to_f, d['Longitude'].to_f]
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['Street']
22
+ address_data["street"]
23
23
  end
24
24
 
25
25
  def street_number
26
- address_data['HouseNumber']
26
+ address_data["houseNumber"]
27
27
  end
28
28
 
29
29
  def state
30
- fail unless d = address_data['AdditionalData']
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['County']
34
+ address_data["county"]
38
35
  end
39
36
 
40
37
  def postal_code
41
- address_data['PostalCode']
38
+ address_data["postalCode"]
42
39
  end
43
40
 
44
41
  def city
45
- address_data['City']
42
+ address_data["city"]
46
43
  end
47
44
 
48
45
  def state_code
49
- address_data['State']
46
+ address_data["stateCode"]
50
47
  end
51
48
 
52
49
  def province_code
53
- address_data['State']
50
+ address_data["state"]
54
51
  end
55
52
 
56
53
  def country
57
- fail unless d = address_data['AdditionalData']
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['Country']
58
+ address_data["countryCode"]
65
59
  end
66
60
 
67
61
  def viewport
68
- map_view = data['Location']['MapView'] || fail
69
- south = map_view['BottomRight']['Latitude']
70
- west = map_view['TopLeft']['Longitude']
71
- north = map_view['TopLeft']['Latitude']
72
- east = map_view['BottomRight']['Longitude']
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['Location']['Address'] || fail
74
+ @data["address"] || fail
80
75
  end
81
76
  end
82
77
  end
@@ -0,0 +1,40 @@
1
+ require 'geocoder/results/base'
2
+
3
+ module Geocoder::Result
4
+ class Ipbase < Base
5
+ def ip
6
+ @data["data"]['ip']
7
+ end
8
+
9
+ def country_code
10
+ @data["data"]["location"]["country"]["alpha2"]
11
+ end
12
+
13
+ def country
14
+ @data["data"]["location"]["country"]["name"]
15
+ end
16
+
17
+ def state_code
18
+ @data["data"]["location"]["region"]["alpha2"]
19
+ end
20
+
21
+ def state
22
+ @data["data"]["location"]["region"]["name"]
23
+ end
24
+
25
+ def city
26
+ @data["data"]["location"]["city"]["name"]
27
+ end
28
+
29
+ def postal_code
30
+ @data["data"]["location"]["zip"]
31
+ end
32
+
33
+ def coordinates
34
+ [
35
+ @data["data"]["location"]["latitude"].to_f,
36
+ @data["data"]["location"]["longitude"].to_f
37
+ ]
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,54 @@
1
+ require 'geocoder/results/base'
2
+
3
+ module Geocoder
4
+ module Result
5
+ class Ipqualityscore < Base
6
+
7
+ def self.key_method_mappings
8
+ {
9
+ 'request_id' => :request_id,
10
+ 'success' => :success?,
11
+ 'message' => :message,
12
+ 'city' => :city,
13
+ 'region' => :state,
14
+ 'country_code' => :country_code,
15
+ 'mobile' => :mobile?,
16
+ 'fraud_score' => :fraud_score,
17
+ 'ISP' => :isp,
18
+ 'ASN' => :asn,
19
+ 'organization' => :organization,
20
+ 'is_crawler' => :crawler?,
21
+ 'host' => :host,
22
+ 'proxy' => :proxy?,
23
+ 'vpn' => :vpn?,
24
+ 'tor' => :tor?,
25
+ 'active_vpn' => :active_vpn?,
26
+ 'active_tor' => :active_tor?,
27
+ 'recent_abuse' => :recent_abuse?,
28
+ 'bot_status' => :bot?,
29
+ 'connection_type' => :connection_type,
30
+ 'abuse_velocity' => :abuse_velocity,
31
+ 'timezone' => :timezone,
32
+ }
33
+ end
34
+
35
+ key_method_mappings.each_pair do |key, meth|
36
+ define_method meth do
37
+ @data[key]
38
+ end
39
+ end
40
+
41
+ alias_method :state_code, :state
42
+ alias_method :country, :country_code
43
+
44
+ def postal_code
45
+ '' # No suitable fallback
46
+ end
47
+
48
+ def address
49
+ [city, state, country_code].compact.reject(&:empty?).join(', ')
50
+ end
51
+
52
+ end
53
+ end
54
+ end
@@ -9,6 +9,10 @@ module Geocoder::Result
9
9
  @data = flatten_hash(data)
10
10
  end
11
11
 
12
+ def coordinates
13
+ [@data['location_latitude'], @data['location_longitude']]
14
+ end
15
+
12
16
  def flatten_hash(hash)
13
17
  hash.each_with_object({}) do |(k, v), h|
14
18
  if v.is_a? Hash
@@ -35,14 +39,6 @@ module Geocoder::Result
35
39
  @data['location_country_code']
36
40
  end
37
41
 
38
- def latitude
39
- @data['location_latitude']
40
- end
41
-
42
- def longitude
43
- @data['location_longitude']
44
- end
45
-
46
42
  def postal_code
47
43
  @data['location_postal']
48
44
  end