geocoder 1.5.0 → 1.6.7

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.
Files changed (75) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +53 -2
  3. data/LICENSE +1 -1
  4. data/README.md +23 -46
  5. data/bin/console +13 -0
  6. data/examples/autoexpire_cache_redis.rb +2 -0
  7. data/lib/easting_northing.rb +171 -0
  8. data/lib/geocoder/cache.rb +4 -0
  9. data/lib/geocoder/calculations.rb +1 -1
  10. data/lib/geocoder/configuration.rb +2 -1
  11. data/lib/geocoder/configuration_hash.rb +4 -4
  12. data/lib/geocoder/ip_address.rb +15 -1
  13. data/lib/geocoder/lookup.rb +9 -4
  14. data/lib/geocoder/lookups/abstract_api.rb +46 -0
  15. data/lib/geocoder/lookups/baidu_ip.rb +1 -1
  16. data/lib/geocoder/lookups/ban_data_gouv_fr.rb +14 -1
  17. data/lib/geocoder/lookups/base.rb +7 -2
  18. data/lib/geocoder/lookups/bing.rb +2 -1
  19. data/lib/geocoder/lookups/esri.rb +44 -13
  20. data/lib/geocoder/lookups/freegeoip.rb +7 -7
  21. data/lib/geocoder/lookups/geocodio.rb +1 -1
  22. data/lib/geocoder/lookups/google.rb +7 -2
  23. data/lib/geocoder/lookups/google_places_details.rb +8 -14
  24. data/lib/geocoder/lookups/google_places_search.rb +28 -2
  25. data/lib/geocoder/lookups/google_premier.rb +4 -0
  26. data/lib/geocoder/lookups/here.rb +28 -22
  27. data/lib/geocoder/lookups/ip2location.rb +7 -14
  28. data/lib/geocoder/lookups/ipapi_com.rb +2 -1
  29. data/lib/geocoder/lookups/ipdata_co.rb +5 -4
  30. data/lib/geocoder/lookups/ipgeolocation.rb +51 -0
  31. data/lib/geocoder/lookups/ipinfo_io.rb +2 -11
  32. data/lib/geocoder/lookups/ipregistry.rb +68 -0
  33. data/lib/geocoder/lookups/ipstack.rb +2 -2
  34. data/lib/geocoder/lookups/latlon.rb +1 -2
  35. data/lib/geocoder/lookups/maxmind.rb +2 -2
  36. data/lib/geocoder/lookups/maxmind_geoip2.rb +4 -7
  37. data/lib/geocoder/lookups/maxmind_local.rb +7 -1
  38. data/lib/geocoder/lookups/nationaal_georegister_nl.rb +38 -0
  39. data/lib/geocoder/lookups/osmnames.rb +57 -0
  40. data/lib/geocoder/lookups/pelias.rb +2 -3
  41. data/lib/geocoder/lookups/pickpoint.rb +1 -1
  42. data/lib/geocoder/lookups/pointpin.rb +3 -3
  43. data/lib/geocoder/lookups/smarty_streets.rb +19 -4
  44. data/lib/geocoder/lookups/telize.rb +3 -3
  45. data/lib/geocoder/lookups/tencent.rb +59 -0
  46. data/lib/geocoder/lookups/test.rb +4 -0
  47. data/lib/geocoder/lookups/uk_ordnance_survey_names.rb +59 -0
  48. data/lib/geocoder/lookups/yandex.rb +3 -4
  49. data/lib/geocoder/query.rb +14 -0
  50. data/lib/geocoder/railtie.rb +1 -1
  51. data/lib/geocoder/results/abstract_api.rb +146 -0
  52. data/lib/geocoder/results/baidu.rb +0 -4
  53. data/lib/geocoder/results/ban_data_gouv_fr.rb +27 -2
  54. data/lib/geocoder/results/db_ip_com.rb +1 -1
  55. data/lib/geocoder/results/here.rb +4 -1
  56. data/lib/geocoder/results/ipgeolocation.rb +59 -0
  57. data/lib/geocoder/results/ipregistry.rb +304 -0
  58. data/lib/geocoder/results/nationaal_georegister_nl.rb +62 -0
  59. data/lib/geocoder/results/nominatim.rb +4 -0
  60. data/lib/geocoder/results/osmnames.rb +56 -0
  61. data/lib/geocoder/results/smarty_streets.rb +48 -18
  62. data/lib/geocoder/results/tencent.rb +72 -0
  63. data/lib/geocoder/results/uk_ordnance_survey_names.rb +59 -0
  64. data/lib/geocoder/results/yandex.rb +217 -59
  65. data/lib/geocoder/sql.rb +4 -4
  66. data/lib/geocoder/stores/active_record.rb +1 -1
  67. data/lib/geocoder/util.rb +29 -0
  68. data/lib/geocoder/version.rb +1 -1
  69. data/lib/maxmind_database.rb +3 -3
  70. metadata +24 -18
  71. data/lib/geocoder/lookups/geocoder_us.rb +0 -51
  72. data/lib/geocoder/lookups/mapzen.rb +0 -15
  73. data/lib/geocoder/results/geocoder_us.rb +0 -39
  74. data/lib/geocoder/results/mapzen.rb +0 -5
  75. data/lib/hash_recursive_merge.rb +0 -74
@@ -24,12 +24,11 @@ module Geocoder::Lookup
24
24
 
25
25
  def query_url_params(query)
26
26
  params = {
27
- api_key: configuration.api_key,
28
- size: 1
27
+ api_key: configuration.api_key
29
28
  }.merge(super)
30
29
 
31
30
  if query.reverse_geocode?
32
- lat,lon = query.coordinates
31
+ lat, lon = query.coordinates
33
32
  params[:'point.lat'] = lat
34
33
  params[:'point.lon'] = lon
35
34
  else
@@ -23,7 +23,7 @@ module Geocoder::Lookup
23
23
  end
24
24
 
25
25
  def query_url_params(query)
26
- params = {
26
+ {
27
27
  key: configuration.api_key
28
28
  }.merge(super)
29
29
  end
@@ -23,8 +23,8 @@ module Geocoder::Lookup
23
23
  end
24
24
 
25
25
  def results(query)
26
- # don't look up a loopback address, just return the stored result
27
- return [] if query.loopback_ip_address?
26
+ # don't look up a loopback or private address, just return the stored result
27
+ return [] if query.internal_ip_address?
28
28
  doc = fetch_data(query)
29
29
  if doc and doc.is_a?(Hash)
30
30
  if !data_contains_error?(doc)
@@ -42,7 +42,7 @@ module Geocoder::Lookup
42
42
  raise_error(Geocoder::Error) || Geocoder.log(:warn, "Pointpin server error")
43
43
  end
44
44
  end
45
-
45
+
46
46
  return []
47
47
  end
48
48
 
@@ -8,7 +8,7 @@ module Geocoder::Lookup
8
8
  end
9
9
 
10
10
  def required_api_key_parts
11
- %w(auti-id auth-token)
11
+ %w(auth-id auth-token)
12
12
  end
13
13
 
14
14
  # required by API as of 26 March 2015
@@ -19,7 +19,9 @@ module Geocoder::Lookup
19
19
  private # ---------------------------------------------------------------
20
20
 
21
21
  def base_query_url(query)
22
- if zipcode_only?(query)
22
+ if international?(query)
23
+ "#{protocol}://international-street.api.smartystreets.com/verify?"
24
+ elsif zipcode_only?(query)
23
25
  "#{protocol}://us-zipcode.api.smartystreets.com/lookup?"
24
26
  else
25
27
  "#{protocol}://us-street.api.smartystreets.com/street-address?"
@@ -30,9 +32,17 @@ module Geocoder::Lookup
30
32
  !query.text.is_a?(Array) and query.to_s.strip =~ /\A\d{5}(-\d{4})?\Z/
31
33
  end
32
34
 
35
+ def international?(query)
36
+ !query.options[:country].nil?
37
+ end
38
+
33
39
  def query_url_params(query)
34
40
  params = {}
35
- if zipcode_only?(query)
41
+ if international?(query)
42
+ params[:freeform] = query.sanitized_text
43
+ params[:country] = query.options[:country]
44
+ params[:geocode] = true
45
+ elsif zipcode_only?(query)
36
46
  params[:zipcode] = query.sanitized_text
37
47
  else
38
48
  params[:street] = query.sanitized_text
@@ -47,7 +57,12 @@ module Geocoder::Lookup
47
57
  end
48
58
 
49
59
  def results(query)
50
- fetch_data(query) || []
60
+ doc = fetch_data(query) || []
61
+ if doc.is_a?(Hash) and doc.key?('status') # implies there's an error
62
+ return []
63
+ else
64
+ return doc
65
+ end
51
66
  end
52
67
  end
53
68
  end
@@ -16,7 +16,7 @@ module Geocoder::Lookup
16
16
  if configuration[:host]
17
17
  "#{protocol}://#{configuration[:host]}/location/#{query.sanitized_text}"
18
18
  else
19
- "#{protocol}://telize-v1.p.mashape.com/location/#{query.sanitized_text}?mashape-key=#{api_key}"
19
+ "#{protocol}://telize-v1.p.rapidapi.com/location/#{query.sanitized_text}?rapidapi-key=#{api_key}"
20
20
  end
21
21
  end
22
22
 
@@ -34,8 +34,8 @@ module Geocoder::Lookup
34
34
  end
35
35
 
36
36
  def results(query)
37
- # don't look up a loopback address, just return the stored result
38
- return [reserved_result(query.text)] if query.loopback_ip_address?
37
+ # don't look up a loopback or private address, just return the stored result
38
+ return [reserved_result(query.text)] if query.internal_ip_address?
39
39
  if (doc = fetch_data(query)).nil? or doc['code'] == 401 or empty_result?(doc)
40
40
  []
41
41
  else
@@ -0,0 +1,59 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/tencent"
3
+
4
+ module Geocoder::Lookup
5
+ class Tencent < Base
6
+
7
+ def name
8
+ "Tencent"
9
+ end
10
+
11
+ def required_api_key_parts
12
+ ["key"]
13
+ end
14
+
15
+ def supported_protocols
16
+ [:https]
17
+ end
18
+
19
+ private # ---------------------------------------------------------------
20
+
21
+ def base_query_url(query)
22
+ "#{protocol}://apis.map.qq.com/ws/geocoder/v1/?"
23
+ end
24
+
25
+ def content_key
26
+ 'result'
27
+ end
28
+
29
+ def results(query, reverse = false)
30
+ return [] unless doc = fetch_data(query)
31
+ case doc['status']
32
+ when 0
33
+ return [doc[content_key]]
34
+ when 311
35
+ raise_error(Geocoder::InvalidApiKey, "invalid api key") ||
36
+ Geocoder.log(:warn, "#{name} Geocoding API error: invalid api key.")
37
+ when 310
38
+ raise_error(Geocoder::InvalidRequest, "invalid request.") ||
39
+ Geocoder.log(:warn, "#{name} Geocoding API error: invalid request, invalid parameters.")
40
+ when 306
41
+ raise_error(Geocoder::InvalidRequest, "invalid request.") ||
42
+ Geocoder.log(:warn, "#{name} Geocoding API error: invalid request, check response for more info.")
43
+ when 110
44
+ raise_error(Geocoder::RequestDenied, "request denied.") ||
45
+ Geocoder.log(:warn, "#{name} Geocoding API error: request source is not authorized.")
46
+ end
47
+ return []
48
+ end
49
+
50
+ def query_url_params(query)
51
+ {
52
+ (query.reverse_geocode? ? :location : :address) => query.sanitized_text,
53
+ :key => configuration.api_key,
54
+ :output => "json"
55
+ }.merge(super)
56
+ end
57
+
58
+ end
59
+ end
@@ -28,6 +28,10 @@ module Geocoder
28
28
  @stubs ||= {}
29
29
  end
30
30
 
31
+ def self.delete_stub(query_text)
32
+ stubs.delete(query_text)
33
+ end
34
+
31
35
  def self.reset
32
36
  @stubs = {}
33
37
  @default_stub = nil
@@ -0,0 +1,59 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/uk_ordnance_survey_names'
3
+
4
+ module Geocoder::Lookup
5
+ class UkOrdnanceSurveyNames < Base
6
+
7
+ def name
8
+ 'Ordance Survey Names'
9
+ end
10
+
11
+ def supported_protocols
12
+ [:https]
13
+ end
14
+
15
+ def base_query_url(query)
16
+ "#{protocol}://api.os.uk/search/names/v1/find?"
17
+ end
18
+
19
+ def required_api_key_parts
20
+ ["key"]
21
+ end
22
+
23
+ def query_url(query)
24
+ base_query_url(query) + url_query_string(query)
25
+ end
26
+
27
+ private # -------------------------------------------------------------
28
+
29
+ def results(query)
30
+ return [] unless doc = fetch_data(query)
31
+ return [] if doc['header']['totalresults'].zero?
32
+ return doc['results'].map { |r| r['GAZETTEER_ENTRY'] }
33
+ end
34
+
35
+ def query_url_params(query)
36
+ {
37
+ query: query.sanitized_text,
38
+ key: configuration.api_key,
39
+ fq: filter
40
+ }.merge(super)
41
+ end
42
+
43
+ def local_types
44
+ %w[
45
+ City
46
+ Hamlet
47
+ Other_Settlement
48
+ Town
49
+ Village
50
+ Postcode
51
+ ]
52
+ end
53
+
54
+ def filter
55
+ local_types.map { |t| "local_type:#{t}" }.join(' ')
56
+ end
57
+
58
+ end
59
+ end
@@ -33,8 +33,7 @@ module Geocoder::Lookup
33
33
  return []
34
34
  end
35
35
  if doc = doc['response']['GeoObjectCollection']
36
- meta = doc['metaDataProperty']['GeocoderResponseMetaData']
37
- return meta['found'].to_i > 0 ? doc['featureMember'] : []
36
+ return doc['featureMember'].to_a
38
37
  else
39
38
  Geocoder.log(:warn, "Yandex Geocoding API error: unexpected response format.")
40
39
  return []
@@ -50,8 +49,8 @@ module Geocoder::Lookup
50
49
  params = {
51
50
  :geocode => q,
52
51
  :format => "json",
53
- :plng => "#{query.language || configuration.language}", # supports ru, uk, be
54
- :key => configuration.api_key
52
+ :lang => "#{query.language || configuration.language}", # supports ru, uk, be, default -> ru
53
+ :apikey => configuration.api_key
55
54
  }
56
55
  unless (bounds = query.options[:bounds]).nil?
57
56
  params[:bbox] = bounds.map{ |point| "%f,%f" % point }.join('~')
@@ -66,6 +66,13 @@ module Geocoder
66
66
  IpAddress.new(text).valid? rescue false
67
67
  end
68
68
 
69
+ ##
70
+ # Is the Query text a loopback or private IP address?
71
+ #
72
+ def internal_ip_address?
73
+ ip_address? && IpAddress.new(text).internal?
74
+ end
75
+
69
76
  ##
70
77
  # Is the Query text a loopback IP address?
71
78
  #
@@ -73,6 +80,13 @@ module Geocoder
73
80
  ip_address? && IpAddress.new(text).loopback?
74
81
  end
75
82
 
83
+ ##
84
+ # Is the Query text a private IP address?
85
+ #
86
+ def private_ip_address?
87
+ ip_address? && IpAddress.new(text).private?
88
+ end
89
+
76
90
  ##
77
91
  # Does the given string look like latitude/longitude coordinates?
78
92
  #
@@ -4,7 +4,7 @@ module Geocoder
4
4
  if defined? Rails::Railtie
5
5
  require 'rails'
6
6
  class Railtie < Rails::Railtie
7
- initializer 'geocoder.insert_into_active_record' do
7
+ initializer 'geocoder.insert_into_active_record', before: :load_config_initializers do
8
8
  ActiveSupport.on_load :active_record do
9
9
  Geocoder::Railtie.insert
10
10
  end
@@ -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