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,129 @@
1
+ require 'singleton'
2
+ require 'geocoder/configuration_hash'
3
+
4
+ module Geocoder
5
+
6
+ ##
7
+ # Configuration options should be set by passing a hash:
8
+ #
9
+ # Geocoder.configure(
10
+ # :timeout => 5,
11
+ # :lookup => :yandex,
12
+ # :api_key => "2a9fsa983jaslfj982fjasd",
13
+ # :units => :km
14
+ # )
15
+ #
16
+ def self.configure(options = nil, &block)
17
+ if !options.nil?
18
+ Configuration.instance.configure(options)
19
+ end
20
+ end
21
+
22
+ ##
23
+ # Read-only access to the singleton's config data.
24
+ #
25
+ def self.config
26
+ Configuration.instance.data
27
+ end
28
+
29
+ ##
30
+ # Read-only access to lookup-specific config data.
31
+ #
32
+ def self.config_for_lookup(lookup_name)
33
+ data = config.clone
34
+ data.reject!{ |key,value| !Configuration::OPTIONS.include?(key) }
35
+ if config.has_key?(lookup_name)
36
+ data.merge!(config[lookup_name])
37
+ end
38
+ data
39
+ end
40
+
41
+ class Configuration
42
+ include Singleton
43
+
44
+ OPTIONS = [
45
+ :timeout,
46
+ :lookup,
47
+ :ip_lookup,
48
+ :language,
49
+ :http_headers,
50
+ :use_https,
51
+ :http_proxy,
52
+ :https_proxy,
53
+ :api_key,
54
+ :cache,
55
+ :cache_prefix,
56
+ :always_raise,
57
+ :units,
58
+ :distances,
59
+ :basic_auth,
60
+ :logger,
61
+ :kernel_logger_level
62
+ ]
63
+
64
+ attr_accessor :data
65
+
66
+ def self.set_defaults
67
+ instance.set_defaults
68
+ end
69
+
70
+ OPTIONS.each do |o|
71
+ define_method o do
72
+ @data[o]
73
+ end
74
+ define_method "#{o}=" do |value|
75
+ @data[o] = value
76
+ end
77
+ end
78
+
79
+ def configure(options)
80
+ @data.rmerge!(options)
81
+ end
82
+
83
+ def initialize # :nodoc
84
+ @data = Geocoder::ConfigurationHash.new
85
+ set_defaults
86
+ end
87
+
88
+ def set_defaults
89
+
90
+ # geocoding options
91
+ @data[:timeout] = 3 # geocoding service timeout (secs)
92
+ @data[:lookup] = :google # name of street address geocoding service (symbol)
93
+ @data[:ip_lookup] = :freegeoip # name of IP address geocoding service (symbol)
94
+ @data[:language] = :en # ISO-639 language code
95
+ @data[:http_headers] = {} # HTTP headers for lookup
96
+ @data[:use_https] = false # use HTTPS for lookup requests? (if supported)
97
+ @data[:http_proxy] = nil # HTTP proxy server (user:pass@host:port)
98
+ @data[:https_proxy] = nil # HTTPS proxy server (user:pass@host:port)
99
+ @data[:api_key] = nil # API key for geocoding service
100
+ @data[:cache] = nil # cache object (must respond to #[], #[]=, and #keys)
101
+ @data[:cache_prefix] = "geocoder:" # prefix (string) to use for all cache keys
102
+ @data[:basic_auth] = {} # user and password for basic auth ({:user => "user", :password => "password"})
103
+ @data[:logger] = :kernel # :kernel or Logger instance
104
+ @data[:kernel_logger_level] = ::Logger::WARN # log level, if kernel logger is used
105
+
106
+ # exceptions that should not be rescued by default
107
+ # (if you want to implement custom error handling);
108
+ # supports SocketError and Timeout::Error
109
+ @data[:always_raise] = []
110
+
111
+ # calculation options
112
+ @data[:units] = :mi # :mi or :km
113
+ @data[:distances] = :linear # :linear or :spherical
114
+ end
115
+
116
+ instance_eval(OPTIONS.map do |option|
117
+ o = option.to_s
118
+ <<-EOS
119
+ def #{o}
120
+ instance.data[:#{o}]
121
+ end
122
+
123
+ def #{o}=(value)
124
+ instance.data[:#{o}] = value
125
+ end
126
+ EOS
127
+ end.join("\n\n"))
128
+ end
129
+ end
@@ -0,0 +1,11 @@
1
+ require 'hash_recursive_merge'
2
+
3
+ module Geocoder
4
+ class ConfigurationHash < Hash
5
+ include HashRecursiveMerge
6
+
7
+ def method_missing(meth, *args, &block)
8
+ has_key?(meth) ? self[meth] : super
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,38 @@
1
+ module Geocoder
2
+ class EsriToken
3
+ attr_accessor :value, :expires_at
4
+
5
+ def initialize(value, expires_at)
6
+ @value = value
7
+ @expires_at = expires_at
8
+ end
9
+
10
+ def to_s
11
+ @value
12
+ end
13
+
14
+ def active?
15
+ @expires_at > Time.now
16
+ end
17
+
18
+ def self.generate_token(client_id, client_secret, expires=1440)
19
+ # creates a new token that will expire in 1 day by default
20
+ getToken = Net::HTTP.post_form URI('https://www.arcgis.com/sharing/rest/oauth2/token'),
21
+ f: 'json',
22
+ client_id: client_id,
23
+ client_secret: client_secret,
24
+ grant_type: 'client_credentials',
25
+ expiration: expires # (minutes) max: 20160, default: 1 day
26
+
27
+ response = JSON.parse(getToken.body)
28
+
29
+ if response['error']
30
+ Geocoder.log(:warn, response['error'])
31
+ else
32
+ token_value = response['access_token']
33
+ expires_at = Time.now + (expires * 60)
34
+ new(token_value, expires_at)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,37 @@
1
+ require 'timeout' # required for Ruby 1.9.3
2
+
3
+ module Geocoder
4
+
5
+ class Error < StandardError
6
+ end
7
+
8
+ class ConfigurationError < Error
9
+ end
10
+
11
+ class OverQueryLimitError < Error
12
+ end
13
+
14
+ class ResponseParseError < Error
15
+ attr_reader :response
16
+
17
+ def initialize(response)
18
+ @response = response
19
+ end
20
+ end
21
+
22
+ class RequestDenied < Error
23
+ end
24
+
25
+ class InvalidRequest < Error
26
+ end
27
+
28
+ class InvalidApiKey < Error
29
+ end
30
+
31
+ class ServiceUnavailable < Error
32
+ end
33
+
34
+ class LookupTimeout < ::Timeout::Error
35
+ end
36
+
37
+ end
@@ -0,0 +1,13 @@
1
+ require 'resolv'
2
+ module Geocoder
3
+ class IpAddress < String
4
+
5
+ def loopback?
6
+ valid? and (self == "0.0.0.0" or self.match(/\A127\./) or self == "::1")
7
+ end
8
+
9
+ def valid?
10
+ !!((self =~ Resolv::IPv4::Regex) || (self =~ Resolv::IPv6::Regex))
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,25 @@
1
+ module Geocoder
2
+ class KernelLogger
3
+ include Singleton
4
+
5
+ def add(level, message)
6
+ return unless log_message_at_level?(level)
7
+ case level
8
+ when ::Logger::DEBUG, ::Logger::INFO
9
+ puts message
10
+ when ::Logger::WARN
11
+ warn message
12
+ when ::Logger::ERROR
13
+ raise message
14
+ when ::Logger::FATAL
15
+ fail message
16
+ end
17
+ end
18
+
19
+ private # ----------------------------------------------------------------
20
+
21
+ def log_message_at_level?(level)
22
+ level >= Geocoder.config.kernel_logger_level
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,47 @@
1
+ require 'logger'
2
+
3
+ module Geocoder
4
+
5
+ def self.log(level, message)
6
+ Logger.instance.log(level, message)
7
+ end
8
+
9
+ class Logger
10
+ include Singleton
11
+
12
+ SEVERITY = {
13
+ debug: ::Logger::DEBUG,
14
+ info: ::Logger::INFO,
15
+ warn: ::Logger::WARN,
16
+ error: ::Logger::ERROR,
17
+ fatal: ::Logger::FATAL
18
+ }
19
+
20
+ def log(level, message)
21
+ unless valid_level?(level)
22
+ raise StandardError, "Geocoder tried to log a message with an invalid log level."
23
+ end
24
+ if current_logger.respond_to? :add
25
+ current_logger.add(SEVERITY[level], message)
26
+ else
27
+ raise Geocoder::ConfigurationError, "Please specify valid logger for Geocoder. " +
28
+ "Logger specified must be :kernel or must respond to `add(level, message)`."
29
+ end
30
+ nil
31
+ end
32
+
33
+ private # ----------------------------------------------------------------
34
+
35
+ def current_logger
36
+ logger = Geocoder.config[:logger]
37
+ if logger == :kernel
38
+ logger = Geocoder::KernelLogger.instance
39
+ end
40
+ logger
41
+ end
42
+
43
+ def valid_level?(level)
44
+ SEVERITY.keys.include?(level)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,110 @@
1
+ require "geocoder/lookups/test"
2
+
3
+ module Geocoder
4
+ module Lookup
5
+ extend self
6
+
7
+ ##
8
+ # Array of valid Lookup service names.
9
+ #
10
+ def all_services
11
+ street_services + ip_services
12
+ end
13
+
14
+ ##
15
+ # Array of valid Lookup service names, excluding :test.
16
+ #
17
+ def all_services_except_test
18
+ all_services - [:test]
19
+ end
20
+
21
+ ##
22
+ # All street address lookup services, default first.
23
+ #
24
+ def street_services
25
+ @street_services ||= [
26
+ :dstk,
27
+ :esri,
28
+ :google,
29
+ :google_premier,
30
+ :google_places_details,
31
+ :bing,
32
+ :geocoder_ca,
33
+ :geocoder_us,
34
+ :yandex,
35
+ :nominatim,
36
+ :mapbox,
37
+ :mapquest,
38
+ :mapzen,
39
+ :opencagedata,
40
+ :ovi,
41
+ :pelias,
42
+ :here,
43
+ :baidu,
44
+ :geocodio,
45
+ :smarty_streets,
46
+ :okf,
47
+ :postcode_anywhere_uk,
48
+ :geoportail_lu,
49
+ :test,
50
+ :latlon
51
+ ]
52
+ end
53
+
54
+ ##
55
+ # All IP address lookup services, default first.
56
+ #
57
+ def ip_services
58
+ @ip_services ||= [
59
+ :baidu_ip,
60
+ :freegeoip,
61
+ :geoip2,
62
+ :maxmind,
63
+ :maxmind_local,
64
+ :telize,
65
+ :pointpin,
66
+ :maxmind_geoip2,
67
+ :ipinfo_io,
68
+ :ipapi_com
69
+ ]
70
+ end
71
+
72
+ attr_writer :street_services, :ip_services
73
+
74
+ ##
75
+ # Retrieve a Lookup object from the store.
76
+ # Use this instead of Geocoder::Lookup::X.new to get an
77
+ # already-configured Lookup object.
78
+ #
79
+ def get(name)
80
+ @services = {} unless defined?(@services)
81
+ @services[name] = spawn(name) unless @services.include?(name)
82
+ @services[name]
83
+ end
84
+
85
+
86
+ private # -----------------------------------------------------------------
87
+
88
+ ##
89
+ # Spawn a Lookup of the given name.
90
+ #
91
+ def spawn(name)
92
+ if all_services.include?(name)
93
+ name = name.to_s
94
+ require "geocoder/lookups/#{name}"
95
+ Geocoder::Lookup.const_get(classify_name(name)).new
96
+ else
97
+ valids = all_services.map(&:inspect).join(", ")
98
+ raise ConfigurationError, "Please specify a valid lookup for Geocoder " +
99
+ "(#{name.inspect} is not one of: #{valids})."
100
+ end
101
+ end
102
+
103
+ ##
104
+ # Convert an "underscore" version of a name into a "class" version.
105
+ #
106
+ def classify_name(filename)
107
+ filename.to_s.split("_").map{ |i| i[0...1].upcase + i[1..-1] }.join
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,59 @@
1
+ require 'geocoder/lookups/base'
2
+ require "geocoder/results/baidu"
3
+
4
+ module Geocoder::Lookup
5
+ class Baidu < Base
6
+
7
+ def name
8
+ "Baidu"
9
+ end
10
+
11
+ def required_api_key_parts
12
+ ["key"]
13
+ end
14
+
15
+ def query_url(query)
16
+ "#{protocol}://api.map.baidu.com/geocoder/v2/?" + url_query_string(query)
17
+ end
18
+
19
+ # HTTP only
20
+ def supported_protocols
21
+ [:http]
22
+ end
23
+
24
+ private # ---------------------------------------------------------------
25
+
26
+ def results(query, reverse = false)
27
+ return [] unless doc = fetch_data(query)
28
+ case doc['status']
29
+ when 0
30
+ return [doc['result']] unless doc['result'].blank?
31
+ when 1, 3, 4
32
+ raise_error(Geocoder::Error, "server error.") ||
33
+ Geocoder.log(:warn, "Baidu Geocoding API error: server error.")
34
+ when 2
35
+ raise_error(Geocoder::InvalidRequest, "invalid request.") ||
36
+ Geocoder.log(:warn, "Baidu Geocoding API error: invalid request.")
37
+ when 5
38
+ raise_error(Geocoder::InvalidApiKey, "invalid api key") ||
39
+ Geocoder.log(:warn, "Baidu Geocoding API error: invalid api key.")
40
+ when 101, 102, 200..299
41
+ raise_error(Geocoder::RequestDenied, "request denied") ||
42
+ Geocoder.log(:warn, "Baidu Geocoding API error: request denied.")
43
+ when 300..399
44
+ raise_error(Geocoder::OverQueryLimitError, "over query limit.") ||
45
+ Geocoder.log(:warn, "Baidu Geocoding API error: over query limit.")
46
+ end
47
+ return []
48
+ end
49
+
50
+ def query_url_params(query)
51
+ {
52
+ (query.reverse_geocode? ? :location : :address) => query.sanitized_text,
53
+ :ak => configuration.api_key,
54
+ :output => "json"
55
+ }.merge(super)
56
+ end
57
+
58
+ end
59
+ end