really-broken-geocoder 1.5.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.
Files changed (136) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +557 -0
  3. data/LICENSE +20 -0
  4. data/README.md +3 -0
  5. data/bin/geocode +5 -0
  6. data/examples/autoexpire_cache_dalli.rb +62 -0
  7. data/examples/autoexpire_cache_redis.rb +28 -0
  8. data/examples/cache_bypass.rb +48 -0
  9. data/examples/reverse_geocode_job.rb +40 -0
  10. data/lib/generators/geocoder/config/config_generator.rb +14 -0
  11. data/lib/generators/geocoder/config/templates/initializer.rb +22 -0
  12. data/lib/generators/geocoder/maxmind/geolite_city_generator.rb +30 -0
  13. data/lib/generators/geocoder/maxmind/geolite_country_generator.rb +30 -0
  14. data/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb +30 -0
  15. data/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb +17 -0
  16. data/lib/generators/geocoder/migration_version.rb +15 -0
  17. data/lib/geocoder.rb +48 -0
  18. data/lib/geocoder/cache.rb +94 -0
  19. data/lib/geocoder/calculations.rb +420 -0
  20. data/lib/geocoder/cli.rb +121 -0
  21. data/lib/geocoder/configuration.rb +137 -0
  22. data/lib/geocoder/configuration_hash.rb +11 -0
  23. data/lib/geocoder/esri_token.rb +38 -0
  24. data/lib/geocoder/exceptions.rb +40 -0
  25. data/lib/geocoder/ip_address.rb +26 -0
  26. data/lib/geocoder/kernel_logger.rb +25 -0
  27. data/lib/geocoder/logger.rb +47 -0
  28. data/lib/geocoder/lookup.rb +118 -0
  29. data/lib/geocoder/lookups/amap.rb +63 -0
  30. data/lib/geocoder/lookups/baidu.rb +63 -0
  31. data/lib/geocoder/lookups/baidu_ip.rb +30 -0
  32. data/lib/geocoder/lookups/ban_data_gouv_fr.rb +130 -0
  33. data/lib/geocoder/lookups/base.rb +348 -0
  34. data/lib/geocoder/lookups/bing.rb +82 -0
  35. data/lib/geocoder/lookups/db_ip_com.rb +52 -0
  36. data/lib/geocoder/lookups/dstk.rb +22 -0
  37. data/lib/geocoder/lookups/esri.rb +95 -0
  38. data/lib/geocoder/lookups/freegeoip.rb +60 -0
  39. data/lib/geocoder/lookups/geocoder_ca.rb +53 -0
  40. data/lib/geocoder/lookups/geocoder_us.rb +51 -0
  41. data/lib/geocoder/lookups/geocodio.rb +42 -0
  42. data/lib/geocoder/lookups/geoip2.rb +45 -0
  43. data/lib/geocoder/lookups/geoportail_lu.rb +65 -0
  44. data/lib/geocoder/lookups/google.rb +95 -0
  45. data/lib/geocoder/lookups/google_places_details.rb +50 -0
  46. data/lib/geocoder/lookups/google_places_search.rb +33 -0
  47. data/lib/geocoder/lookups/google_premier.rb +57 -0
  48. data/lib/geocoder/lookups/here.rb +77 -0
  49. data/lib/geocoder/lookups/ip2location.rb +75 -0
  50. data/lib/geocoder/lookups/ipapi_com.rb +82 -0
  51. data/lib/geocoder/lookups/ipdata_co.rb +62 -0
  52. data/lib/geocoder/lookups/ipinfo_io.rb +44 -0
  53. data/lib/geocoder/lookups/ipstack.rb +63 -0
  54. data/lib/geocoder/lookups/latlon.rb +59 -0
  55. data/lib/geocoder/lookups/location_iq.rb +50 -0
  56. data/lib/geocoder/lookups/mapbox.rb +59 -0
  57. data/lib/geocoder/lookups/mapquest.rb +58 -0
  58. data/lib/geocoder/lookups/maxmind.rb +90 -0
  59. data/lib/geocoder/lookups/maxmind_geoip2.rb +70 -0
  60. data/lib/geocoder/lookups/maxmind_local.rb +65 -0
  61. data/lib/geocoder/lookups/nominatim.rb +64 -0
  62. data/lib/geocoder/lookups/opencagedata.rb +65 -0
  63. data/lib/geocoder/lookups/pelias.rb +63 -0
  64. data/lib/geocoder/lookups/pickpoint.rb +41 -0
  65. data/lib/geocoder/lookups/pointpin.rb +69 -0
  66. data/lib/geocoder/lookups/postcode_anywhere_uk.rb +50 -0
  67. data/lib/geocoder/lookups/postcodes_io.rb +31 -0
  68. data/lib/geocoder/lookups/smarty_streets.rb +63 -0
  69. data/lib/geocoder/lookups/telize.rb +75 -0
  70. data/lib/geocoder/lookups/tencent.rb +59 -0
  71. data/lib/geocoder/lookups/test.rb +44 -0
  72. data/lib/geocoder/lookups/yandex.rb +62 -0
  73. data/lib/geocoder/models/active_record.rb +51 -0
  74. data/lib/geocoder/models/base.rb +39 -0
  75. data/lib/geocoder/models/mongo_base.rb +62 -0
  76. data/lib/geocoder/models/mongo_mapper.rb +26 -0
  77. data/lib/geocoder/models/mongoid.rb +32 -0
  78. data/lib/geocoder/query.rb +125 -0
  79. data/lib/geocoder/railtie.rb +26 -0
  80. data/lib/geocoder/request.rb +114 -0
  81. data/lib/geocoder/results/amap.rb +87 -0
  82. data/lib/geocoder/results/baidu.rb +79 -0
  83. data/lib/geocoder/results/baidu_ip.rb +62 -0
  84. data/lib/geocoder/results/ban_data_gouv_fr.rb +257 -0
  85. data/lib/geocoder/results/base.rb +79 -0
  86. data/lib/geocoder/results/bing.rb +52 -0
  87. data/lib/geocoder/results/db_ip_com.rb +58 -0
  88. data/lib/geocoder/results/dstk.rb +6 -0
  89. data/lib/geocoder/results/esri.rb +75 -0
  90. data/lib/geocoder/results/freegeoip.rb +40 -0
  91. data/lib/geocoder/results/geocoder_ca.rb +60 -0
  92. data/lib/geocoder/results/geocoder_us.rb +39 -0
  93. data/lib/geocoder/results/geocodio.rb +78 -0
  94. data/lib/geocoder/results/geoip2.rb +76 -0
  95. data/lib/geocoder/results/geoportail_lu.rb +71 -0
  96. data/lib/geocoder/results/google.rb +150 -0
  97. data/lib/geocoder/results/google_places_details.rb +39 -0
  98. data/lib/geocoder/results/google_places_search.rb +52 -0
  99. data/lib/geocoder/results/google_premier.rb +6 -0
  100. data/lib/geocoder/results/here.rb +79 -0
  101. data/lib/geocoder/results/ip2location.rb +22 -0
  102. data/lib/geocoder/results/ipapi_com.rb +45 -0
  103. data/lib/geocoder/results/ipdata_co.rb +40 -0
  104. data/lib/geocoder/results/ipinfo_io.rb +48 -0
  105. data/lib/geocoder/results/ipstack.rb +60 -0
  106. data/lib/geocoder/results/latlon.rb +71 -0
  107. data/lib/geocoder/results/location_iq.rb +6 -0
  108. data/lib/geocoder/results/mapbox.rb +57 -0
  109. data/lib/geocoder/results/mapquest.rb +48 -0
  110. data/lib/geocoder/results/maxmind.rb +130 -0
  111. data/lib/geocoder/results/maxmind_geoip2.rb +9 -0
  112. data/lib/geocoder/results/maxmind_local.rb +44 -0
  113. data/lib/geocoder/results/nominatim.rb +109 -0
  114. data/lib/geocoder/results/opencagedata.rb +100 -0
  115. data/lib/geocoder/results/pelias.rb +58 -0
  116. data/lib/geocoder/results/pickpoint.rb +6 -0
  117. data/lib/geocoder/results/pointpin.rb +40 -0
  118. data/lib/geocoder/results/postcode_anywhere_uk.rb +42 -0
  119. data/lib/geocoder/results/postcodes_io.rb +40 -0
  120. data/lib/geocoder/results/smarty_streets.rb +142 -0
  121. data/lib/geocoder/results/telize.rb +40 -0
  122. data/lib/geocoder/results/tencent.rb +72 -0
  123. data/lib/geocoder/results/test.rb +33 -0
  124. data/lib/geocoder/results/yandex.rb +134 -0
  125. data/lib/geocoder/sql.rb +110 -0
  126. data/lib/geocoder/stores/active_record.rb +328 -0
  127. data/lib/geocoder/stores/base.rb +115 -0
  128. data/lib/geocoder/stores/mongo_base.rb +58 -0
  129. data/lib/geocoder/stores/mongo_mapper.rb +13 -0
  130. data/lib/geocoder/stores/mongoid.rb +13 -0
  131. data/lib/geocoder/version.rb +3 -0
  132. data/lib/hash_recursive_merge.rb +74 -0
  133. data/lib/maxmind_database.rb +109 -0
  134. data/lib/tasks/geocoder.rake +54 -0
  135. data/lib/tasks/maxmind.rake +73 -0
  136. metadata +186 -0
@@ -0,0 +1,69 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/pointpin'
3
+
4
+ module Geocoder::Lookup
5
+ class Pointpin < Base
6
+
7
+ def name
8
+ "Pointpin"
9
+ end
10
+
11
+ def required_api_key_parts
12
+ ["key"]
13
+ end
14
+
15
+ def query_url(query)
16
+ "#{protocol}://geo.pointp.in/#{configuration.api_key}/json/#{query.sanitized_text}"
17
+ end
18
+
19
+ private # ----------------------------------------------------------------
20
+
21
+ def cache_key(query)
22
+ "#{protocol}://geo.pointp.in/json/#{query.sanitized_text}"
23
+ end
24
+
25
+ def results(query)
26
+ # don't look up a loopback or private address, just return the stored result
27
+ return [] if query.internal_ip_address?
28
+ doc = fetch_data(query)
29
+ if doc and doc.is_a?(Hash)
30
+ if !data_contains_error?(doc)
31
+ return [doc]
32
+ elsif doc['error']
33
+ case doc['error']
34
+ when "Invalid IP address"
35
+ raise_error(Geocoder::InvalidRequest) || Geocoder.log(:warn, "Invalid Pointpin request.")
36
+ when "Invalid API key"
37
+ raise_error(Geocoder::InvalidApiKey) || Geocoder.log(:warn, "Invalid Pointpin API key.")
38
+ when "Address not found"
39
+ Geocoder.log(:warn, "Address not found.")
40
+ end
41
+ else
42
+ raise_error(Geocoder::Error) || Geocoder.log(:warn, "Pointpin server error")
43
+ end
44
+ end
45
+
46
+ return []
47
+ end
48
+
49
+ def data_contains_error?(parsed_data)
50
+ parsed_data.keys.include?('error')
51
+ end
52
+
53
+ # TODO: replace this hash with what's actually returned by Pointpin
54
+ def reserved_result(ip)
55
+ {
56
+ "ip" => ip,
57
+ "city" => "",
58
+ "region_code" => "",
59
+ "region_name" => "",
60
+ "metrocode" => "",
61
+ "zipcode" => "",
62
+ "latitude" => "0",
63
+ "longitude" => "0",
64
+ "country_name" => "Reserved",
65
+ "country_code" => "RD"
66
+ }
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,50 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/postcode_anywhere_uk'
3
+
4
+ module Geocoder::Lookup
5
+ class PostcodeAnywhereUk < Base
6
+ # API documentation: http://www.postcodeanywhere.co.uk/Support/WebService/Geocoding/UK/Geocode/2/
7
+ DAILY_LIMIT_EXEEDED_ERROR_CODES = ['8', '17'] # api docs say these two codes are the same error
8
+ INVALID_API_KEY_ERROR_CODE = '2'
9
+
10
+ def name
11
+ 'PostcodeAnywhereUk'
12
+ end
13
+
14
+ def required_api_key_parts
15
+ %w(key)
16
+ end
17
+
18
+ private # ----------------------------------------------------------------
19
+
20
+ def base_query_url(query)
21
+ "#{protocol}://services.postcodeanywhere.co.uk/Geocoding/UK/Geocode/v2.00/json.ws?"
22
+ end
23
+
24
+ def results(query)
25
+ response = fetch_data(query)
26
+ return [] if response.nil? || !response.is_a?(Array) || response.empty?
27
+
28
+ raise_exception_for_response(response[0]) if response[0]['Error']
29
+ response
30
+ end
31
+
32
+ def raise_exception_for_response(response)
33
+ case response['Error']
34
+ when *DAILY_LIMIT_EXEEDED_ERROR_CODES
35
+ raise_error(Geocoder::OverQueryLimitError, response['Cause']) || Geocoder.log(:warn, response['Cause'])
36
+ when INVALID_API_KEY_ERROR_CODE
37
+ raise_error(Geocoder::InvalidApiKey, response['Cause']) || Geocoder.log(:warn, response['Cause'])
38
+ else # anything else just raise general error with the api cause
39
+ raise_error(Geocoder::Error, response['Cause']) || Geocoder.log(:warn, response['Cause'])
40
+ end
41
+ end
42
+
43
+ def query_url_params(query)
44
+ {
45
+ :location => query.sanitized_text,
46
+ :key => configuration.api_key
47
+ }.merge(super)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,31 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/postcodes_io'
3
+
4
+ module Geocoder::Lookup
5
+ class PostcodesIo < Base
6
+ def name
7
+ 'Postcodes.io'
8
+ end
9
+
10
+ def query_url(query)
11
+ "#{protocol}://api.postcodes.io/postcodes/#{query.sanitized_text.gsub(/\s/, '')}"
12
+ end
13
+
14
+ def supported_protocols
15
+ [:https]
16
+ end
17
+
18
+ private # ----------------------------------------------------------------
19
+
20
+ def cache_key(query)
21
+ query_url(query)
22
+ end
23
+
24
+ def results(query)
25
+ response = fetch_data(query)
26
+ return [] if response.nil? || response['status'] != 200 || response.empty?
27
+
28
+ [response['result']]
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,63 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/smarty_streets'
3
+
4
+ module Geocoder::Lookup
5
+ class SmartyStreets < Base
6
+ def name
7
+ "SmartyStreets"
8
+ end
9
+
10
+ def required_api_key_parts
11
+ %w(auth-id auth-token)
12
+ end
13
+
14
+ # required by API as of 26 March 2015
15
+ def supported_protocols
16
+ [:https]
17
+ end
18
+
19
+ private # ---------------------------------------------------------------
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
+
31
+ def zipcode_only?(query)
32
+ !query.text.is_a?(Array) and query.to_s.strip =~ /\A\d{5}(-\d{4})?\Z/
33
+ end
34
+
35
+ def international?(query)
36
+ !query.options[:country].nil?
37
+ end
38
+
39
+ def query_url_params(query)
40
+ params = {}
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)
46
+ params[:zipcode] = query.sanitized_text
47
+ else
48
+ params[:street] = query.sanitized_text
49
+ end
50
+ if configuration.api_key.is_a?(Array)
51
+ params[:"auth-id"] = configuration.api_key[0]
52
+ params[:"auth-token"] = configuration.api_key[1]
53
+ else
54
+ params[:"auth-token"] = configuration.api_key
55
+ end
56
+ params.merge(super)
57
+ end
58
+
59
+ def results(query)
60
+ fetch_data(query) || []
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,75 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/telize'
3
+
4
+ module Geocoder::Lookup
5
+ class Telize < Base
6
+
7
+ def name
8
+ "Telize"
9
+ end
10
+
11
+ def required_api_key_parts
12
+ configuration[:host] ? [] : ["key"]
13
+ end
14
+
15
+ def query_url(query)
16
+ if configuration[:host]
17
+ "#{protocol}://#{configuration[:host]}/location/#{query.sanitized_text}"
18
+ else
19
+ "#{protocol}://telize-v1.p.mashape.com/location/#{query.sanitized_text}?mashape-key=#{api_key}"
20
+ end
21
+ end
22
+
23
+ def supported_protocols
24
+ [].tap do |array|
25
+ array << :https
26
+ array << :http if configuration[:host]
27
+ end
28
+ end
29
+
30
+ private # ---------------------------------------------------------------
31
+
32
+ def cache_key(query)
33
+ query_url(query)[/(.*)\?.*/, 1]
34
+ end
35
+
36
+ def results(query)
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
+ if (doc = fetch_data(query)).nil? or doc['code'] == 401 or empty_result?(doc)
40
+ []
41
+ else
42
+ [doc]
43
+ end
44
+ end
45
+
46
+ def empty_result?(doc)
47
+ !doc.is_a?(Hash) or doc.keys == ["ip"]
48
+ end
49
+
50
+ def reserved_result(ip)
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
+ }
68
+ end
69
+
70
+ def api_key
71
+ configuration.api_key
72
+ end
73
+
74
+ end
75
+ end
@@ -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 199
35
+ raise error(Geocoder::InvalidApiKey, "invalid api key") ||
36
+ Geocoder.log(:warn, "#{name} Geocoding API error: key is not enabled for web service usage.")
37
+ when 311
38
+ raise_error(Geocoder::RequestDenied, "request denied") ||
39
+ Geocoder.log(:warn, "#{name} Geocoding API error: request denied.")
40
+ when 310, 306
41
+ raise_error(Geocoder::InvalidRequest, "invalid request.") ||
42
+ Geocoder.log(:warn, "#{name} Geocoding API error: invalid request.")
43
+ when 311
44
+ raise_error(Geocoder::InvalidApiKey, "invalid api key") ||
45
+ Geocoder.log(:warn, "#{name} Geocoding API error: invalid api key.")
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
@@ -0,0 +1,44 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/test'
3
+
4
+ module Geocoder
5
+ module Lookup
6
+ class Test < Base
7
+
8
+ def name
9
+ "Test"
10
+ end
11
+
12
+ def self.add_stub(query_text, results)
13
+ stubs[query_text] = results
14
+ end
15
+
16
+ def self.set_default_stub(results)
17
+ @default_stub = results
18
+ end
19
+
20
+ def self.read_stub(query_text)
21
+ stubs.fetch(query_text) {
22
+ return @default_stub unless @default_stub.nil?
23
+ raise ArgumentError, "unknown stub request #{query_text}"
24
+ }
25
+ end
26
+
27
+ def self.stubs
28
+ @stubs ||= {}
29
+ end
30
+
31
+ def self.reset
32
+ @stubs = {}
33
+ @default_stub = nil
34
+ end
35
+
36
+ private
37
+
38
+ def results(query)
39
+ Geocoder::Lookup::Test.read_stub(query.text)
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,62 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/yandex"
3
+
4
+ module Geocoder::Lookup
5
+ class Yandex < Base
6
+
7
+ def name
8
+ "Yandex"
9
+ end
10
+
11
+ def map_link_url(coordinates)
12
+ "http://maps.yandex.ru/?ll=#{coordinates.reverse.join(',')}"
13
+ end
14
+
15
+ def supported_protocols
16
+ [:https]
17
+ end
18
+
19
+ private # ---------------------------------------------------------------
20
+
21
+ def base_query_url(query)
22
+ "#{protocol}://geocode-maps.yandex.ru/1.x/?"
23
+ end
24
+
25
+ def results(query)
26
+ return [] unless doc = fetch_data(query)
27
+ if err = doc['error']
28
+ if err["status"] == 401 and err["message"] == "invalid key"
29
+ raise_error(Geocoder::InvalidApiKey) || Geocoder.log(:warn, "Invalid API key.")
30
+ else
31
+ Geocoder.log(:warn, "Yandex Geocoding API error: #{err['status']} (#{err['message']}).")
32
+ end
33
+ return []
34
+ end
35
+ if doc = doc['response']['GeoObjectCollection']
36
+ meta = doc['metaDataProperty']['GeocoderResponseMetaData']
37
+ return meta['found'].to_i > 0 ? doc['featureMember'] : []
38
+ else
39
+ Geocoder.log(:warn, "Yandex Geocoding API error: unexpected response format.")
40
+ return []
41
+ end
42
+ end
43
+
44
+ def query_url_params(query)
45
+ if query.reverse_geocode?
46
+ q = query.coordinates.reverse.join(",")
47
+ else
48
+ q = query.sanitized_text
49
+ end
50
+ params = {
51
+ :geocode => q,
52
+ :format => "json",
53
+ :plng => "#{query.language || configuration.language}", # supports ru, uk, be
54
+ :key => configuration.api_key
55
+ }
56
+ unless (bounds = query.options[:bounds]).nil?
57
+ params[:bbox] = bounds.map{ |point| "%f,%f" % point }.join('~')
58
+ end
59
+ params.merge(super)
60
+ end
61
+ end
62
+ end