broken-geocoder 1.3.4

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 (119) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +467 -0
  3. data/LICENSE +20 -0
  4. data/README.md +1193 -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 +21 -0
  12. data/lib/generators/geocoder/maxmind/geolite_city_generator.rb +28 -0
  13. data/lib/generators/geocoder/maxmind/geolite_country_generator.rb +28 -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/geocoder.rb +48 -0
  17. data/lib/geocoder/cache.rb +90 -0
  18. data/lib/geocoder/calculations.rb +431 -0
  19. data/lib/geocoder/cli.rb +121 -0
  20. data/lib/geocoder/configuration.rb +129 -0
  21. data/lib/geocoder/configuration_hash.rb +11 -0
  22. data/lib/geocoder/esri_token.rb +38 -0
  23. data/lib/geocoder/exceptions.rb +37 -0
  24. data/lib/geocoder/ip_address.rb +13 -0
  25. data/lib/geocoder/kernel_logger.rb +25 -0
  26. data/lib/geocoder/logger.rb +47 -0
  27. data/lib/geocoder/lookup.rb +110 -0
  28. data/lib/geocoder/lookups/baidu.rb +59 -0
  29. data/lib/geocoder/lookups/baidu_ip.rb +59 -0
  30. data/lib/geocoder/lookups/base.rb +325 -0
  31. data/lib/geocoder/lookups/bing.rb +80 -0
  32. data/lib/geocoder/lookups/dstk.rb +20 -0
  33. data/lib/geocoder/lookups/esri.rb +64 -0
  34. data/lib/geocoder/lookups/freegeoip.rb +51 -0
  35. data/lib/geocoder/lookups/geocoder_ca.rb +53 -0
  36. data/lib/geocoder/lookups/geocoder_us.rb +43 -0
  37. data/lib/geocoder/lookups/geocodio.rb +42 -0
  38. data/lib/geocoder/lookups/geoip2.rb +45 -0
  39. data/lib/geocoder/lookups/geoportail_lu.rb +65 -0
  40. data/lib/geocoder/lookups/google.rb +91 -0
  41. data/lib/geocoder/lookups/google_places_details.rb +50 -0
  42. data/lib/geocoder/lookups/google_premier.rb +47 -0
  43. data/lib/geocoder/lookups/here.rb +62 -0
  44. data/lib/geocoder/lookups/ipapi_com.rb +86 -0
  45. data/lib/geocoder/lookups/ipinfo_io.rb +55 -0
  46. data/lib/geocoder/lookups/latlon.rb +59 -0
  47. data/lib/geocoder/lookups/mapbox.rb +53 -0
  48. data/lib/geocoder/lookups/mapquest.rb +59 -0
  49. data/lib/geocoder/lookups/mapzen.rb +15 -0
  50. data/lib/geocoder/lookups/maxmind.rb +90 -0
  51. data/lib/geocoder/lookups/maxmind_geoip2.rb +69 -0
  52. data/lib/geocoder/lookups/maxmind_local.rb +65 -0
  53. data/lib/geocoder/lookups/nominatim.rb +52 -0
  54. data/lib/geocoder/lookups/okf.rb +44 -0
  55. data/lib/geocoder/lookups/opencagedata.rb +58 -0
  56. data/lib/geocoder/lookups/ovi.rb +62 -0
  57. data/lib/geocoder/lookups/pelias.rb +64 -0
  58. data/lib/geocoder/lookups/pointpin.rb +68 -0
  59. data/lib/geocoder/lookups/postcode_anywhere_uk.rb +51 -0
  60. data/lib/geocoder/lookups/smarty_streets.rb +50 -0
  61. data/lib/geocoder/lookups/telize.rb +55 -0
  62. data/lib/geocoder/lookups/test.rb +44 -0
  63. data/lib/geocoder/lookups/yandex.rb +58 -0
  64. data/lib/geocoder/models/active_record.rb +50 -0
  65. data/lib/geocoder/models/base.rb +39 -0
  66. data/lib/geocoder/models/mongo_base.rb +62 -0
  67. data/lib/geocoder/models/mongo_mapper.rb +26 -0
  68. data/lib/geocoder/models/mongoid.rb +32 -0
  69. data/lib/geocoder/query.rb +111 -0
  70. data/lib/geocoder/railtie.rb +26 -0
  71. data/lib/geocoder/request.rb +83 -0
  72. data/lib/geocoder/results/baidu.rb +79 -0
  73. data/lib/geocoder/results/baidu_ip.rb +62 -0
  74. data/lib/geocoder/results/base.rb +67 -0
  75. data/lib/geocoder/results/bing.rb +52 -0
  76. data/lib/geocoder/results/dstk.rb +6 -0
  77. data/lib/geocoder/results/esri.rb +75 -0
  78. data/lib/geocoder/results/freegeoip.rb +45 -0
  79. data/lib/geocoder/results/geocoder_ca.rb +60 -0
  80. data/lib/geocoder/results/geocoder_us.rb +39 -0
  81. data/lib/geocoder/results/geocodio.rb +70 -0
  82. data/lib/geocoder/results/geoip2.rb +62 -0
  83. data/lib/geocoder/results/geoportail_lu.rb +69 -0
  84. data/lib/geocoder/results/google.rb +139 -0
  85. data/lib/geocoder/results/google_places_details.rb +35 -0
  86. data/lib/geocoder/results/google_premier.rb +6 -0
  87. data/lib/geocoder/results/here.rb +71 -0
  88. data/lib/geocoder/results/ipapi_com.rb +45 -0
  89. data/lib/geocoder/results/ipinfo_io.rb +48 -0
  90. data/lib/geocoder/results/latlon.rb +71 -0
  91. data/lib/geocoder/results/mapbox.rb +47 -0
  92. data/lib/geocoder/results/mapquest.rb +48 -0
  93. data/lib/geocoder/results/mapzen.rb +5 -0
  94. data/lib/geocoder/results/maxmind.rb +135 -0
  95. data/lib/geocoder/results/maxmind_geoip2.rb +9 -0
  96. data/lib/geocoder/results/maxmind_local.rb +49 -0
  97. data/lib/geocoder/results/nominatim.rb +99 -0
  98. data/lib/geocoder/results/okf.rb +106 -0
  99. data/lib/geocoder/results/opencagedata.rb +90 -0
  100. data/lib/geocoder/results/ovi.rb +71 -0
  101. data/lib/geocoder/results/pelias.rb +58 -0
  102. data/lib/geocoder/results/pointpin.rb +40 -0
  103. data/lib/geocoder/results/postcode_anywhere_uk.rb +42 -0
  104. data/lib/geocoder/results/smarty_streets.rb +106 -0
  105. data/lib/geocoder/results/telize.rb +45 -0
  106. data/lib/geocoder/results/test.rb +33 -0
  107. data/lib/geocoder/results/yandex.rb +92 -0
  108. data/lib/geocoder/sql.rb +107 -0
  109. data/lib/geocoder/stores/active_record.rb +305 -0
  110. data/lib/geocoder/stores/base.rb +116 -0
  111. data/lib/geocoder/stores/mongo_base.rb +58 -0
  112. data/lib/geocoder/stores/mongo_mapper.rb +13 -0
  113. data/lib/geocoder/stores/mongoid.rb +13 -0
  114. data/lib/geocoder/version.rb +3 -0
  115. data/lib/hash_recursive_merge.rb +74 -0
  116. data/lib/maxmind_database.rb +109 -0
  117. data/lib/tasks/geocoder.rake +38 -0
  118. data/lib/tasks/maxmind.rake +73 -0
  119. metadata +167 -0
@@ -0,0 +1,50 @@
1
+ require "geocoder/lookups/google"
2
+ require "geocoder/results/google_places_details"
3
+
4
+ module Geocoder
5
+ module Lookup
6
+ class GooglePlacesDetails < Google
7
+ def name
8
+ "Google Places Details"
9
+ end
10
+
11
+ def required_api_key_parts
12
+ ["key"]
13
+ end
14
+
15
+ def supported_protocols
16
+ [:https]
17
+ end
18
+
19
+ def query_url(query)
20
+ "#{protocol}://maps.googleapis.com/maps/api/place/details/json?#{url_query_string(query)}"
21
+ end
22
+
23
+ private
24
+
25
+ def results(query)
26
+ return [] unless doc = fetch_data(query)
27
+
28
+ case doc["status"]
29
+ when "OK"
30
+ return [doc["result"]]
31
+ when "OVER_QUERY_LIMIT"
32
+ raise_error(Geocoder::OverQueryLimitError) || Geocoder.log(:warn, "Google Places Details API error: over query limit.")
33
+ when "REQUEST_DENIED"
34
+ raise_error(Geocoder::RequestDenied) || Geocoder.log(:warn, "Google Places Details API error: request denied.")
35
+ when "INVALID_REQUEST"
36
+ raise_error(Geocoder::InvalidRequest) || Geocoder.log(:warn, "Google Places Details API error: invalid request.")
37
+ end
38
+
39
+ []
40
+ end
41
+
42
+ def query_url_google_params(query)
43
+ {
44
+ placeid: query.text,
45
+ language: query.language || configuration.language
46
+ }
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,47 @@
1
+ require 'openssl'
2
+ require 'base64'
3
+ require 'geocoder/lookups/google'
4
+ require 'geocoder/results/google_premier'
5
+
6
+ module Geocoder::Lookup
7
+ class GooglePremier < Google
8
+
9
+ def name
10
+ "Google Premier"
11
+ end
12
+
13
+ def required_api_key_parts
14
+ ["private key", "client", "channel"]
15
+ end
16
+
17
+ def query_url(query)
18
+ path = "/maps/api/geocode/json?" + url_query_string(query)
19
+ "#{protocol}://maps.googleapis.com#{path}&signature=#{sign(path)}"
20
+ end
21
+
22
+ private # ---------------------------------------------------------------
23
+
24
+ def query_url_params(query)
25
+ query_url_google_params(query).merge(super).merge(
26
+ :key => nil, # don't use param inherited from Google lookup
27
+ :client => configuration.api_key[1],
28
+ :channel => configuration.api_key[2]
29
+ )
30
+ end
31
+
32
+ def sign(string)
33
+ raw_private_key = url_safe_base64_decode(configuration.api_key[0])
34
+ digest = OpenSSL::Digest.new('sha1')
35
+ raw_signature = OpenSSL::HMAC.digest(digest, raw_private_key, string)
36
+ url_safe_base64_encode(raw_signature)
37
+ end
38
+
39
+ def url_safe_base64_decode(base64_string)
40
+ Base64.decode64(base64_string.tr('-_', '+/'))
41
+ end
42
+
43
+ def url_safe_base64_encode(raw)
44
+ Base64.encode64(raw).tr('+/', '-_').strip
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,62 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/here'
3
+
4
+ module Geocoder::Lookup
5
+ class Here < Base
6
+
7
+ def name
8
+ "Here"
9
+ end
10
+
11
+ def required_api_key_parts
12
+ ["app_id", "app_code"]
13
+ end
14
+
15
+ def query_url(query)
16
+ "#{protocol}://#{if query.reverse_geocode? then 'reverse.' end}geocoder.api.here.com/6.2/#{if query.reverse_geocode? then 'reverse' end}geocode.json?" + url_query_string(query)
17
+ end
18
+
19
+ private # ---------------------------------------------------------------
20
+
21
+ def results(query)
22
+ return [] unless doc = fetch_data(query)
23
+ return [] unless doc['Response'] && doc['Response']['View']
24
+ if r=doc['Response']['View']
25
+ return [] if r.nil? || !r.is_a?(Array) || r.empty?
26
+ return r.first['Result']
27
+ end
28
+ []
29
+ end
30
+
31
+ def query_url_params(query)
32
+ options = {
33
+ :gen=>4,
34
+ :app_id=>api_key,
35
+ :app_code=>api_code
36
+ }
37
+
38
+ if query.reverse_geocode?
39
+ super.merge(options).merge(
40
+ :prox=>query.sanitized_text,
41
+ :mode=>:retrieveAddresses
42
+ )
43
+ else
44
+ super.merge(options).merge(
45
+ :searchtext=>query.sanitized_text
46
+ )
47
+ end
48
+ end
49
+
50
+ def api_key
51
+ if a=configuration.api_key
52
+ return a.first if a.is_a?(Array)
53
+ end
54
+ end
55
+
56
+ def api_code
57
+ if a=configuration.api_key
58
+ return a.last if a.is_a?(Array)
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,86 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/ipapi_com'
3
+
4
+ module Geocoder::Lookup
5
+ class IpapiCom < Base
6
+
7
+ def name
8
+ "ip-api.com"
9
+ end
10
+
11
+ def query_url(query)
12
+ domain = configuration.api_key ? "pro.ip-api.com" : "ip-api.com"
13
+ url_ = "#{protocol}://#{domain}/json/#{query.sanitized_text}"
14
+
15
+ if (params = url_query_string(query)) && !params.empty?
16
+ url_ + "?" + params
17
+ else
18
+ url_
19
+ end
20
+ end
21
+
22
+ def supported_protocols
23
+ if configuration.api_key
24
+ [:http, :https]
25
+ else
26
+ [:http]
27
+ end
28
+ end
29
+
30
+
31
+ private
32
+
33
+ def parse_raw_data(raw_data)
34
+ if raw_data.chomp == "invalid key"
35
+ invalid_key_result
36
+ else
37
+ super(raw_data)
38
+ end
39
+ end
40
+
41
+ def results(query)
42
+ return [reserved_result(query.text)] if query.loopback_ip_address?
43
+
44
+ return [] unless doc = fetch_data(query)
45
+
46
+ if doc["message"] == "invalid key"
47
+ raise_error(Geocoder::InvalidApiKey) || Geocoder.log(:warn, "Invalid API key.")
48
+ return []
49
+ else
50
+ return [doc]
51
+ end
52
+ end
53
+
54
+ def reserved_result(query)
55
+ {
56
+ "message" => "reserved range",
57
+ "query" => query,
58
+ "status" => "fail",
59
+ "ip" => query,
60
+ "city" => "",
61
+ "region_code" => "",
62
+ "region_name" => "",
63
+ "metrocode" => "",
64
+ "zipcode" => "",
65
+ "latitude" => "0",
66
+ "longitude" => "0",
67
+ "country_name" => "Reserved",
68
+ "country_code" => "RD"
69
+ }
70
+ end
71
+
72
+ def invalid_key_result
73
+ {
74
+ "message" => "invalid key"
75
+ }
76
+ end
77
+
78
+ def query_url_params(query)
79
+ params = {}
80
+ params.merge!(fields: configuration[:fields]) if configuration.has_key?(:fields)
81
+ params.merge!(key: configuration.api_key) if configuration.api_key
82
+ params.merge(super)
83
+ end
84
+
85
+ end
86
+ end
@@ -0,0 +1,55 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/ipinfo_io'
3
+
4
+ module Geocoder::Lookup
5
+ class IpinfoIo < Base
6
+
7
+ def name
8
+ "Ipinfo.io"
9
+ end
10
+
11
+ def query_url(query)
12
+ if configuration.api_key
13
+ "#{protocol}://ipinfo.io/#{query.sanitized_text}/geo?" + url_query_string(query)
14
+ else
15
+ "#{protocol}://ipinfo.io/#{query.sanitized_text}/geo"
16
+ end
17
+ end
18
+
19
+ # HTTPS available only for paid plans
20
+ def supported_protocols
21
+ if configuration.api_key
22
+ [:http, :https]
23
+ else
24
+ [:http]
25
+ end
26
+ end
27
+
28
+ private # ---------------------------------------------------------------
29
+
30
+ def results(query)
31
+ # don't look up a loopback address, just return the stored result
32
+ return [reserved_result(query.text)] if query.loopback_ip_address?
33
+ if (doc = fetch_data(query)).nil? or doc['code'] == 401 or empty_result?(doc)
34
+ []
35
+ else
36
+ [doc]
37
+ end
38
+ end
39
+
40
+ def empty_result?(doc)
41
+ !doc.is_a?(Hash) or doc.keys == ["ip"]
42
+ end
43
+
44
+ def reserved_result(ip)
45
+ {"message" => "Input string is not a valid IP address", "code" => 401}
46
+ end
47
+
48
+ def query_url_params(query)
49
+ {
50
+ token: configuration.api_key
51
+ }.merge(super)
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,59 @@
1
+ require 'geocoder/lookups/base'
2
+ require 'geocoder/results/latlon'
3
+
4
+ module Geocoder::Lookup
5
+ class Latlon < Base
6
+
7
+ def name
8
+ "LatLon.io"
9
+ end
10
+
11
+ def required_api_key_parts
12
+ ["api_key"]
13
+ end
14
+
15
+ def query_url(query)
16
+ "#{protocol}://latlon.io/api/v1/#{'reverse_' if query.reverse_geocode?}geocode?#{url_query_string(query)}"
17
+ end
18
+
19
+ private # ---------------------------------------------------------------
20
+
21
+ def results(query)
22
+ return [] unless doc = fetch_data(query)
23
+ if doc['error'].nil?
24
+ [doc]
25
+ # The API returned a 404 response, which indicates no results found
26
+ elsif doc['error']['type'] == 'api_error'
27
+ []
28
+ elsif
29
+ doc['error']['type'] == 'authentication_error'
30
+ raise_error(Geocoder::InvalidApiKey) ||
31
+ Geocoder.log(:warn, "LatLon.io service error: invalid API key.")
32
+ else
33
+ []
34
+ end
35
+ end
36
+
37
+ def supported_protocols
38
+ [:https]
39
+ end
40
+
41
+ private # ---------------------------------------------------------------
42
+
43
+ def query_url_params(query)
44
+ if query.reverse_geocode?
45
+ {
46
+ :token => configuration.api_key,
47
+ :lat => query.coordinates[0],
48
+ :lon => query.coordinates[1]
49
+ }.merge(super)
50
+ else
51
+ {
52
+ :token => configuration.api_key,
53
+ :address => query.sanitized_text
54
+ }.merge(super)
55
+ end
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,53 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/mapbox"
3
+
4
+ module Geocoder::Lookup
5
+ class Mapbox < Base
6
+
7
+ def name
8
+ "Mapbox"
9
+ end
10
+
11
+ def query_url(query)
12
+ "#{protocol}://api.mapbox.com/geocoding/v5/#{dataset}/#{url_query_string(query)}.json?access_token=#{configuration.api_key}"
13
+ end
14
+
15
+ private # ---------------------------------------------------------------
16
+
17
+ def results(query)
18
+ return [] unless data = fetch_data(query)
19
+ if data['features']
20
+ sort_relevant_feature(data['features'])
21
+ elsif data['message'] =~ /Invalid\sToken/
22
+ raise_error(Geocoder::InvalidApiKey, data['message'])
23
+ else
24
+ []
25
+ end
26
+ end
27
+
28
+ def url_query_string(query)
29
+ require 'cgi' unless defined?(CGI) && defined?(CGI.escape)
30
+ if query.reverse_geocode?
31
+ lat,lon = query.coordinates
32
+ "#{CGI.escape lon},#{CGI.escape lat}"
33
+ else
34
+ CGI.escape query.text.to_s
35
+ end
36
+ end
37
+
38
+ def dataset
39
+ configuration[:dataset] || "mapbox.places"
40
+ end
41
+
42
+ def supported_protocols
43
+ [:https]
44
+ end
45
+
46
+ def sort_relevant_feature(features)
47
+ # Sort by descending relevance; Favor original order for equal relevance (eg occurs for reverse geocoding)
48
+ features.sort_by do |feature|
49
+ [feature["relevance"],-features.index(feature)]
50
+ end.reverse
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,59 @@
1
+ require 'cgi'
2
+ require 'geocoder/lookups/base'
3
+ require "geocoder/results/mapquest"
4
+
5
+ module Geocoder::Lookup
6
+ class Mapquest < Base
7
+
8
+ def name
9
+ "Mapquest"
10
+ end
11
+
12
+ def required_api_key_parts
13
+ ["key"]
14
+ end
15
+
16
+ def query_url(query)
17
+ domain = configuration[:open] ? "open" : "www"
18
+ url = "#{protocol}://#{domain}.mapquestapi.com/geocoding/v1/#{search_type(query)}?"
19
+ url + url_query_string(query)
20
+ end
21
+
22
+ private # ---------------------------------------------------------------
23
+
24
+ def search_type(query)
25
+ query.reverse_geocode? ? "reverse" : "address"
26
+ end
27
+
28
+ def query_url_params(query)
29
+ params = { :location => query.sanitized_text }
30
+ if key = configuration.api_key
31
+ params[:key] = CGI.unescape(key)
32
+ end
33
+ params.merge(super)
34
+ end
35
+
36
+ # http://www.mapquestapi.com/geocoding/status_codes.html
37
+ # http://open.mapquestapi.com/geocoding/status_codes.html
38
+ def results(query)
39
+ return [] unless doc = fetch_data(query)
40
+ return doc["results"][0]['locations'] if doc['info']['statuscode'] == 0 # A successful geocode call
41
+
42
+ messages = doc['info']['messages'].join
43
+
44
+ case doc['info']['statuscode']
45
+ when 400 # Error with input
46
+ raise_error(Geocoder::InvalidRequest, messages) ||
47
+ Geocoder.log(:warn, "Mapquest Geocoding API error: #{messages}")
48
+ when 403 # Key related error
49
+ raise_error(Geocoder::InvalidApiKey, messages) ||
50
+ Geocoder.log(:warn, "Mapquest Geocoding API error: #{messages}")
51
+ when 500 # Unknown error
52
+ raise_error(Geocoder::Error, messages) ||
53
+ Geocoder.log(:warn, "Mapquest Geocoding API error: #{messages}")
54
+ end
55
+ []
56
+ end
57
+
58
+ end
59
+ end