geocoder 1.4.9 → 1.6.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +60 -0
  3. data/LICENSE +1 -1
  4. data/README.md +350 -979
  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/generators/geocoder/config/templates/initializer.rb +1 -1
  9. data/lib/geocoder/cache.rb +4 -0
  10. data/lib/geocoder/calculations.rb +1 -1
  11. data/lib/geocoder/cli.rb +2 -2
  12. data/lib/geocoder/configuration.rb +3 -2
  13. data/lib/geocoder/configuration_hash.rb +4 -4
  14. data/lib/geocoder/exceptions.rb +1 -1
  15. data/lib/geocoder/ip_address.rb +16 -2
  16. data/lib/geocoder/lookup.rb +9 -5
  17. data/lib/geocoder/lookups/abstract_api.rb +46 -0
  18. data/lib/geocoder/lookups/amap.rb +7 -3
  19. data/lib/geocoder/lookups/baidu.rb +14 -10
  20. data/lib/geocoder/lookups/baidu_ip.rb +7 -36
  21. data/lib/geocoder/lookups/ban_data_gouv_fr.rb +18 -5
  22. data/lib/geocoder/lookups/base.rb +27 -4
  23. data/lib/geocoder/lookups/bing.rb +10 -13
  24. data/lib/geocoder/lookups/db_ip_com.rb +9 -6
  25. data/lib/geocoder/lookups/dstk.rb +4 -2
  26. data/lib/geocoder/lookups/esri.rb +44 -28
  27. data/lib/geocoder/lookups/freegeoip.rb +11 -7
  28. data/lib/geocoder/lookups/geocoder_ca.rb +4 -4
  29. data/lib/geocoder/lookups/geocodio.rb +5 -5
  30. data/lib/geocoder/lookups/geoportail_lu.rb +7 -7
  31. data/lib/geocoder/lookups/google.rb +15 -10
  32. data/lib/geocoder/lookups/google_places_details.rb +11 -17
  33. data/lib/geocoder/lookups/google_places_search.rb +30 -4
  34. data/lib/geocoder/lookups/google_premier.rb +14 -0
  35. data/lib/geocoder/lookups/here.rb +29 -23
  36. data/lib/geocoder/lookups/ip2location.rb +67 -0
  37. data/lib/geocoder/lookups/ipapi_com.rb +9 -13
  38. data/lib/geocoder/lookups/ipdata_co.rb +9 -4
  39. data/lib/geocoder/lookups/ipgeolocation.rb +51 -0
  40. data/lib/geocoder/lookups/ipinfo_io.rb +11 -29
  41. data/lib/geocoder/lookups/ipregistry.rb +68 -0
  42. data/lib/geocoder/lookups/ipstack.rb +11 -12
  43. data/lib/geocoder/lookups/latlon.rb +5 -6
  44. data/lib/geocoder/lookups/location_iq.rb +10 -4
  45. data/lib/geocoder/lookups/mapbox.rb +7 -6
  46. data/lib/geocoder/lookups/mapquest.rb +4 -5
  47. data/lib/geocoder/lookups/maxmind.rb +6 -6
  48. data/lib/geocoder/lookups/maxmind_geoip2.rb +8 -7
  49. data/lib/geocoder/lookups/maxmind_local.rb +7 -1
  50. data/lib/geocoder/lookups/nationaal_georegister_nl.rb +38 -0
  51. data/lib/geocoder/lookups/nominatim.rb +4 -4
  52. data/lib/geocoder/lookups/opencagedata.rb +6 -5
  53. data/lib/geocoder/lookups/osmnames.rb +57 -0
  54. data/lib/geocoder/lookups/pelias.rb +8 -9
  55. data/lib/geocoder/lookups/pickpoint.rb +9 -3
  56. data/lib/geocoder/lookups/pointpin.rb +10 -9
  57. data/lib/geocoder/lookups/postcode_anywhere_uk.rb +4 -5
  58. data/lib/geocoder/lookups/postcodes_io.rb +6 -3
  59. data/lib/geocoder/lookups/smarty_streets.rb +26 -11
  60. data/lib/geocoder/lookups/telize.rb +24 -4
  61. data/lib/geocoder/lookups/tencent.rb +59 -0
  62. data/lib/geocoder/lookups/test.rb +4 -0
  63. data/lib/geocoder/lookups/uk_ordnance_survey_names.rb +59 -0
  64. data/lib/geocoder/lookups/yandex.rb +7 -8
  65. data/lib/geocoder/query.rb +14 -0
  66. data/lib/geocoder/railtie.rb +1 -1
  67. data/lib/geocoder/results/abstract_api.rb +146 -0
  68. data/lib/geocoder/results/baidu.rb +10 -14
  69. data/lib/geocoder/results/ban_data_gouv_fr.rb +27 -2
  70. data/lib/geocoder/results/base.rb +13 -1
  71. data/lib/geocoder/results/bing.rb +1 -1
  72. data/lib/geocoder/results/db_ip_com.rb +1 -6
  73. data/lib/geocoder/results/freegeoip.rb +0 -5
  74. data/lib/geocoder/results/geocoder_ca.rb +3 -3
  75. data/lib/geocoder/results/geoip2.rb +0 -4
  76. data/lib/geocoder/results/geoportail_lu.rb +5 -3
  77. data/lib/geocoder/results/here.rb +4 -1
  78. data/lib/geocoder/results/ip2location.rb +22 -0
  79. data/lib/geocoder/results/ipdata_co.rb +0 -5
  80. data/lib/geocoder/results/ipgeolocation.rb +59 -0
  81. data/lib/geocoder/results/ipregistry.rb +304 -0
  82. data/lib/geocoder/results/maxmind.rb +0 -5
  83. data/lib/geocoder/results/maxmind_local.rb +0 -5
  84. data/lib/geocoder/results/nationaal_georegister_nl.rb +62 -0
  85. data/lib/geocoder/results/nominatim.rb +4 -0
  86. data/lib/geocoder/results/osmnames.rb +56 -0
  87. data/lib/geocoder/results/smarty_streets.rb +48 -18
  88. data/lib/geocoder/results/telize.rb +0 -5
  89. data/lib/geocoder/results/tencent.rb +72 -0
  90. data/lib/geocoder/results/test.rb +1 -1
  91. data/lib/geocoder/results/uk_ordnance_survey_names.rb +59 -0
  92. data/lib/geocoder/results/yandex.rb +217 -59
  93. data/lib/geocoder/sql.rb +4 -4
  94. data/lib/geocoder/stores/active_record.rb +1 -3
  95. data/lib/geocoder/util.rb +29 -0
  96. data/lib/geocoder/version.rb +1 -1
  97. data/lib/maxmind_database.rb +3 -3
  98. metadata +27 -23
  99. data/lib/geocoder/lookups/geocoder_us.rb +0 -43
  100. data/lib/geocoder/lookups/mapzen.rb +0 -15
  101. data/lib/geocoder/lookups/okf.rb +0 -44
  102. data/lib/geocoder/lookups/ovi.rb +0 -62
  103. data/lib/geocoder/results/geocoder_us.rb +0 -39
  104. data/lib/geocoder/results/mapzen.rb +0 -5
  105. data/lib/geocoder/results/okf.rb +0 -106
  106. data/lib/geocoder/results/ovi.rb +0 -71
  107. data/lib/hash_recursive_merge.rb +0 -74
@@ -11,25 +11,24 @@ module Geocoder::Lookup
11
11
  configuration[:endpoint] || 'localhost'
12
12
  end
13
13
 
14
- def query_url(query)
15
- query_type = query.reverse_geocode? ? 'reverse' : 'search'
16
- "#{protocol}://#{endpoint}/v1/#{query_type}?" + url_query_string(query)
17
- end
18
-
19
14
  def required_api_key_parts
20
15
  ['search-XXXX']
21
16
  end
22
17
 
23
- private
18
+ private # ----------------------------------------------------------------
19
+
20
+ def base_query_url(query)
21
+ query_type = query.reverse_geocode? ? 'reverse' : 'search'
22
+ "#{protocol}://#{endpoint}/v1/#{query_type}?"
23
+ end
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
@@ -15,12 +15,18 @@ module Geocoder::Lookup
15
15
  ["api_key"]
16
16
  end
17
17
 
18
- def query_url(query)
18
+ private # ----------------------------------------------------------------
19
+
20
+ def base_query_url(query)
19
21
  method = query.reverse_geocode? ? "reverse" : "forward"
20
- "#{protocol}://api.pickpoint.io/v1/#{method}?key=#{configuration.api_key}&" + url_query_string(query)
22
+ "#{protocol}://api.pickpoint.io/v1/#{method}?"
21
23
  end
22
24
 
23
- private
25
+ def query_url_params(query)
26
+ {
27
+ key: configuration.api_key
28
+ }.merge(super)
29
+ end
24
30
 
25
31
  def results(query)
26
32
  return [] unless doc = fetch_data(query)
@@ -13,14 +13,18 @@ module Geocoder::Lookup
13
13
  end
14
14
 
15
15
  def query_url(query)
16
- "#{ protocol }://geo.pointp.in/#{ api_key }/json/#{ query.sanitized_text }"
16
+ "#{protocol}://geo.pointp.in/#{configuration.api_key}/json/#{query.sanitized_text}"
17
17
  end
18
18
 
19
- private
19
+ private # ----------------------------------------------------------------
20
+
21
+ def cache_key(query)
22
+ "#{protocol}://geo.pointp.in/json/#{query.sanitized_text}"
23
+ end
20
24
 
21
25
  def results(query)
22
- # don't look up a loopback address, just return the stored result
23
- 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?
24
28
  doc = fetch_data(query)
25
29
  if doc and doc.is_a?(Hash)
26
30
  if !data_contains_error?(doc)
@@ -38,7 +42,7 @@ module Geocoder::Lookup
38
42
  raise_error(Geocoder::Error) || Geocoder.log(:warn, "Pointpin server error")
39
43
  end
40
44
  end
41
-
45
+
42
46
  return []
43
47
  end
44
48
 
@@ -46,6 +50,7 @@ module Geocoder::Lookup
46
50
  parsed_data.keys.include?('error')
47
51
  end
48
52
 
53
+ # TODO: replace this hash with what's actually returned by Pointpin
49
54
  def reserved_result(ip)
50
55
  {
51
56
  "ip" => ip,
@@ -60,9 +65,5 @@ module Geocoder::Lookup
60
65
  "country_code" => "RD"
61
66
  }
62
67
  end
63
-
64
- def api_key
65
- configuration.api_key
66
- end
67
68
  end
68
69
  end
@@ -4,7 +4,6 @@ require 'geocoder/results/postcode_anywhere_uk'
4
4
  module Geocoder::Lookup
5
5
  class PostcodeAnywhereUk < Base
6
6
  # API documentation: http://www.postcodeanywhere.co.uk/Support/WebService/Geocoding/UK/Geocode/2/
7
- BASE_URL_GEOCODE_V2_00 = 'services.postcodeanywhere.co.uk/Geocoding/UK/Geocode/v2.00/json.ws'
8
7
  DAILY_LIMIT_EXEEDED_ERROR_CODES = ['8', '17'] # api docs say these two codes are the same error
9
8
  INVALID_API_KEY_ERROR_CODE = '2'
10
9
 
@@ -16,11 +15,11 @@ module Geocoder::Lookup
16
15
  %w(key)
17
16
  end
18
17
 
19
- def query_url(query)
20
- format('%s://%s?%s', protocol, BASE_URL_GEOCODE_V2_00, url_query_string(query))
21
- end
18
+ private # ----------------------------------------------------------------
22
19
 
23
- private
20
+ def base_query_url(query)
21
+ "#{protocol}://services.postcodeanywhere.co.uk/Geocoding/UK/Geocode/v2.00/json.ws?"
22
+ end
24
23
 
25
24
  def results(query)
26
25
  response = fetch_data(query)
@@ -8,15 +8,18 @@ module Geocoder::Lookup
8
8
  end
9
9
 
10
10
  def query_url(query)
11
- str = query.sanitized_text.gsub(/\s/, '')
12
- format('%s://%s/%s', protocol, 'api.postcodes.io/postcodes', str)
11
+ "#{protocol}://api.postcodes.io/postcodes/#{query.sanitized_text.gsub(/\s/, '')}"
13
12
  end
14
13
 
15
14
  def supported_protocols
16
15
  [:https]
17
16
  end
18
17
 
19
- private
18
+ private # ----------------------------------------------------------------
19
+
20
+ def cache_key(query)
21
+ query_url(query)
22
+ end
20
23
 
21
24
  def results(query)
22
25
  response = fetch_data(query)
@@ -8,15 +8,7 @@ module Geocoder::Lookup
8
8
  end
9
9
 
10
10
  def required_api_key_parts
11
- %w(auti-id auth-token)
12
- end
13
-
14
- def query_url(query)
15
- if zipcode_only?(query)
16
- "#{protocol}://us-zipcode.api.smartystreets.com/lookup?#{url_query_string(query)}"
17
- else
18
- "#{protocol}://us-street.api.smartystreets.com/street-address?#{url_query_string(query)}"
19
- end
11
+ %w(auth-id auth-token)
20
12
  end
21
13
 
22
14
  # required by API as of 26 March 2015
@@ -26,13 +18,31 @@ module Geocoder::Lookup
26
18
 
27
19
  private # ---------------------------------------------------------------
28
20
 
21
+ def base_query_url(query)
22
+ if international?(query)
23
+ "#{protocol}://international-street.api.smartystreets.com/verify?"
24
+ elsif zipcode_only?(query)
25
+ "#{protocol}://us-zipcode.api.smartystreets.com/lookup?"
26
+ else
27
+ "#{protocol}://us-street.api.smartystreets.com/street-address?"
28
+ end
29
+ end
30
+
29
31
  def zipcode_only?(query)
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
 
@@ -29,9 +29,13 @@ module Geocoder::Lookup
29
29
 
30
30
  private # ---------------------------------------------------------------
31
31
 
32
+ def cache_key(query)
33
+ query_url(query)[/(.*)\?.*/, 1]
34
+ end
35
+
32
36
  def results(query)
33
- # don't look up a loopback address, just return the stored result
34
- 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?
35
39
  if (doc = fetch_data(query)).nil? or doc['code'] == 401 or empty_result?(doc)
36
40
  []
37
41
  else
@@ -44,7 +48,23 @@ module Geocoder::Lookup
44
48
  end
45
49
 
46
50
  def reserved_result(ip)
47
- {"message" => "Input string is not a valid IP address", "code" => 401}
51
+ {
52
+ "ip" => ip,
53
+ "latitude" => 0,
54
+ "longitude" => 0,
55
+ "city" => "",
56
+ "timezone" => "",
57
+ "asn" => 0,
58
+ "region" => "",
59
+ "offset" => 0,
60
+ "organization" => "",
61
+ "country_code" => "",
62
+ "country_code3" => "",
63
+ "postal_code" => "",
64
+ "continent_code" => "",
65
+ "country" => "",
66
+ "region_code" => ""
67
+ }
48
68
  end
49
69
 
50
70
  def api_key
@@ -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
@@ -12,16 +12,16 @@ module Geocoder::Lookup
12
12
  "http://maps.yandex.ru/?ll=#{coordinates.reverse.join(',')}"
13
13
  end
14
14
 
15
- def query_url(query)
16
- "#{protocol}://geocode-maps.yandex.ru/1.x/?" + url_query_string(query)
17
- end
18
-
19
15
  def supported_protocols
20
16
  [:https]
21
17
  end
22
18
 
23
19
  private # ---------------------------------------------------------------
24
20
 
21
+ def base_query_url(query)
22
+ "#{protocol}://geocode-maps.yandex.ru/1.x/?"
23
+ end
24
+
25
25
  def results(query)
26
26
  return [] unless doc = fetch_data(query)
27
27
  if err = doc['error']
@@ -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
  #