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,51 @@
1
+ require 'geocoder/models/base'
2
+
3
+ module Geocoder
4
+ module Model
5
+ module ActiveRecord
6
+ include Base
7
+
8
+ ##
9
+ # Set attribute names and include the Geocoder module.
10
+ #
11
+ def geocoded_by(address_attr, options = {}, &block)
12
+ geocoder_init(
13
+ :geocode => true,
14
+ :user_address => address_attr,
15
+ :latitude => options[:latitude] || :latitude,
16
+ :longitude => options[:longitude] || :longitude,
17
+ :geocode_block => block,
18
+ :units => options[:units],
19
+ :method => options[:method],
20
+ :lookup => options[:lookup],
21
+ :language => options[:language],
22
+ :params => options[:params]
23
+ )
24
+ end
25
+
26
+ ##
27
+ # Set attribute names and include the Geocoder module.
28
+ #
29
+ def reverse_geocoded_by(latitude_attr, longitude_attr, options = {}, &block)
30
+ geocoder_init(
31
+ :reverse_geocode => true,
32
+ :fetched_address => options[:address] || :address,
33
+ :latitude => latitude_attr,
34
+ :longitude => longitude_attr,
35
+ :reverse_block => block,
36
+ :units => options[:units],
37
+ :method => options[:method],
38
+ :lookup => options[:lookup],
39
+ :language => options[:language],
40
+ :params => options[:params]
41
+ )
42
+ end
43
+
44
+
45
+ private # --------------------------------------------------------------
46
+
47
+ def geocoder_file_name; "active_record"; end
48
+ def geocoder_module_name; "ActiveRecord"; end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,39 @@
1
+ module Geocoder
2
+
3
+ ##
4
+ # Methods for invoking Geocoder in a model.
5
+ #
6
+ module Model
7
+ module Base
8
+
9
+ def geocoder_options
10
+ if defined?(@geocoder_options)
11
+ @geocoder_options
12
+ elsif superclass.respond_to?(:geocoder_options)
13
+ superclass.geocoder_options || { }
14
+ else
15
+ { }
16
+ end
17
+ end
18
+
19
+ def geocoded_by
20
+ fail
21
+ end
22
+
23
+ def reverse_geocoded_by
24
+ fail
25
+ end
26
+
27
+ private # ----------------------------------------------------------------
28
+
29
+ def geocoder_init(options)
30
+ unless defined?(@geocoder_options)
31
+ @geocoder_options = {}
32
+ require "geocoder/stores/#{geocoder_file_name}"
33
+ include Geocoder::Store.const_get(geocoder_module_name)
34
+ end
35
+ @geocoder_options.merge! options
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,62 @@
1
+ module Geocoder
2
+
3
+ ##
4
+ # Methods for invoking Geocoder in a model.
5
+ #
6
+ module Model
7
+ module MongoBase
8
+
9
+ ##
10
+ # Set attribute names and include the Geocoder module.
11
+ #
12
+ def geocoded_by(address_attr, options = {}, &block)
13
+ geocoder_init(
14
+ :geocode => true,
15
+ :user_address => address_attr,
16
+ :coordinates => options[:coordinates] || :coordinates,
17
+ :geocode_block => block,
18
+ :units => options[:units],
19
+ :method => options[:method],
20
+ :skip_index => options[:skip_index] || false,
21
+ :lookup => options[:lookup],
22
+ :language => options[:language]
23
+ )
24
+ end
25
+
26
+ ##
27
+ # Set attribute names and include the Geocoder module.
28
+ #
29
+ def reverse_geocoded_by(coordinates_attr, options = {}, &block)
30
+ geocoder_init(
31
+ :reverse_geocode => true,
32
+ :fetched_address => options[:address] || :address,
33
+ :coordinates => coordinates_attr,
34
+ :reverse_block => block,
35
+ :units => options[:units],
36
+ :method => options[:method],
37
+ :skip_index => options[:skip_index] || false,
38
+ :lookup => options[:lookup],
39
+ :language => options[:language]
40
+ )
41
+ end
42
+
43
+ private # ----------------------------------------------------------------
44
+
45
+ def geocoder_init(options)
46
+ unless geocoder_initialized?
47
+ @geocoder_options = { }
48
+ require "geocoder/stores/#{geocoder_file_name}"
49
+ include Geocoder::Store.const_get(geocoder_module_name)
50
+ end
51
+ @geocoder_options.merge! options
52
+ end
53
+
54
+ def geocoder_initialized?
55
+ included_modules.include? Geocoder::Store.const_get(geocoder_module_name)
56
+ rescue NameError
57
+ false
58
+ end
59
+ end
60
+ end
61
+ end
62
+
@@ -0,0 +1,26 @@
1
+ require 'geocoder/models/base'
2
+ require 'geocoder/models/mongo_base'
3
+
4
+ module Geocoder
5
+ module Model
6
+ module MongoMapper
7
+ include Base
8
+ include MongoBase
9
+
10
+ def self.included(base); base.extend(self); end
11
+
12
+ private # --------------------------------------------------------------
13
+
14
+ def geocoder_file_name; "mongo_mapper"; end
15
+ def geocoder_module_name; "MongoMapper"; end
16
+
17
+ def geocoder_init(options)
18
+ super(options)
19
+ if options[:skip_index] == false
20
+ ensure_index [[ geocoder_options[:coordinates], Mongo::GEO2D ]],
21
+ :min => -180, :max => 180 # create 2d index
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,32 @@
1
+ require 'geocoder/models/base'
2
+ require 'geocoder/models/mongo_base'
3
+
4
+ module Geocoder
5
+ module Model
6
+ module Mongoid
7
+ include Base
8
+ include MongoBase
9
+
10
+ def self.included(base); base.extend(self); end
11
+
12
+ private # --------------------------------------------------------------
13
+
14
+ def geocoder_file_name; "mongoid"; end
15
+ def geocoder_module_name; "Mongoid"; end
16
+
17
+ def geocoder_init(options)
18
+ super(options)
19
+ if options[:skip_index] == false
20
+ # create 2d index
21
+ if defined?(::Mongoid::VERSION) && ::Mongoid::VERSION >= "3"
22
+ index({ geocoder_options[:coordinates].to_sym => '2d' },
23
+ {:min => -180, :max => 180})
24
+ else
25
+ index [[ geocoder_options[:coordinates], '2d' ]],
26
+ :min => -180, :max => 180
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,125 @@
1
+ module Geocoder
2
+ class Query
3
+ attr_accessor :text, :options
4
+
5
+ def initialize(text, options = {})
6
+ self.text = text
7
+ self.options = options
8
+ end
9
+
10
+ def execute
11
+ lookup.search(text, options)
12
+ end
13
+
14
+ def to_s
15
+ text
16
+ end
17
+
18
+ def sanitized_text
19
+ if coordinates?
20
+ if text.is_a?(Array)
21
+ text.join(',')
22
+ else
23
+ text.split(/\s*,\s*/).join(',')
24
+ end
25
+ else
26
+ text
27
+ end
28
+ end
29
+
30
+ ##
31
+ # Get a Lookup object (which communicates with the remote geocoding API)
32
+ # appropriate to the Query text.
33
+ #
34
+ def lookup
35
+ if !options[:street_address] and (options[:ip_address] or ip_address?)
36
+ name = options[:ip_lookup] || Configuration.ip_lookup || Geocoder::Lookup.ip_services.first
37
+ else
38
+ name = options[:lookup] || Configuration.lookup || Geocoder::Lookup.street_services.first
39
+ end
40
+ Lookup.get(name)
41
+ end
42
+
43
+ def url
44
+ lookup.query_url(self)
45
+ end
46
+
47
+ ##
48
+ # Is the Query blank? (ie, should we not bother searching?)
49
+ # A query is considered blank if its text is nil or empty string AND
50
+ # no URL parameters are specified.
51
+ #
52
+ def blank?
53
+ !params_given? and (
54
+ (text.is_a?(Array) and text.compact.size < 2) or
55
+ text.to_s.match(/\A\s*\z/)
56
+ )
57
+ end
58
+
59
+ ##
60
+ # Does the Query text look like an IP address?
61
+ #
62
+ # Does not check for actual validity, just the appearance of four
63
+ # dot-delimited numbers.
64
+ #
65
+ def ip_address?
66
+ IpAddress.new(text).valid? rescue false
67
+ end
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
+
76
+ ##
77
+ # Is the Query text a loopback IP address?
78
+ #
79
+ def loopback_ip_address?
80
+ ip_address? && IpAddress.new(text).loopback?
81
+ end
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
+
90
+ ##
91
+ # Does the given string look like latitude/longitude coordinates?
92
+ #
93
+ def coordinates?
94
+ text.is_a?(Array) or (
95
+ text.is_a?(String) and
96
+ !!text.to_s.match(/\A-?[0-9\.]+, *-?[0-9\.]+\z/)
97
+ )
98
+ end
99
+
100
+ ##
101
+ # Return the latitude/longitude coordinates specified in the query,
102
+ # or nil if none.
103
+ #
104
+ def coordinates
105
+ sanitized_text.split(',') if coordinates?
106
+ end
107
+
108
+ ##
109
+ # Should reverse geocoding be performed for this query?
110
+ #
111
+ def reverse_geocode?
112
+ coordinates?
113
+ end
114
+
115
+ def language
116
+ options[:language]
117
+ end
118
+
119
+ private # ----------------------------------------------------------------
120
+
121
+ def params_given?
122
+ !!(options[:params].is_a?(Hash) and options[:params].keys.size > 0)
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,26 @@
1
+ require 'geocoder/models/active_record'
2
+
3
+ module Geocoder
4
+ if defined? Rails::Railtie
5
+ require 'rails'
6
+ class Railtie < Rails::Railtie
7
+ initializer 'geocoder.insert_into_active_record', before: :load_config_initializers do
8
+ ActiveSupport.on_load :active_record do
9
+ Geocoder::Railtie.insert
10
+ end
11
+ end
12
+ rake_tasks do
13
+ load "tasks/geocoder.rake"
14
+ load "tasks/maxmind.rake"
15
+ end
16
+ end
17
+ end
18
+
19
+ class Railtie
20
+ def self.insert
21
+ if defined?(::ActiveRecord)
22
+ ::ActiveRecord::Base.extend(Model::ActiveRecord)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,114 @@
1
+ require 'ipaddr'
2
+
3
+ module Geocoder
4
+ module Request
5
+
6
+ # The location() method is vulnerable to trivial IP spoofing.
7
+ # Don't use it in authorization/authentication code, or any
8
+ # other security-sensitive application. Use safe_location
9
+ # instead.
10
+ def location
11
+ @location ||= Geocoder.search(geocoder_spoofable_ip, ip_address: true).first
12
+ end
13
+
14
+ # This safe_location() protects you from trivial IP spoofing.
15
+ # For requests that go through a proxy that you haven't
16
+ # whitelisted as trusted in your Rack config, you will get the
17
+ # location for the IP of the last untrusted proxy in the chain,
18
+ # not the original client IP. You WILL NOT get the location
19
+ # corresponding to the original client IP for any request sent
20
+ # through a non-whitelisted proxy.
21
+ def safe_location
22
+ @safe_location ||= Geocoder.search(ip, ip_address: true).first
23
+ end
24
+
25
+ # There's a whole zoo of nonstandard headers added by various
26
+ # proxy softwares to indicate original client IP.
27
+ # ANY of these can be trivially spoofed!
28
+ # (except REMOTE_ADDR, which should by set by your server,
29
+ # and is included at the end as a fallback.
30
+ # Order does matter: we're following the convention established in
31
+ # ActionDispatch::RemoteIp::GetIp::calculate_ip()
32
+ # https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/remote_ip.rb
33
+ # where the forwarded_for headers, possibly containing lists,
34
+ # are arbitrarily preferred over headers expected to contain a
35
+ # single address.
36
+ GEOCODER_CANDIDATE_HEADERS = ['HTTP_X_FORWARDED_FOR',
37
+ 'HTTP_X_FORWARDED',
38
+ 'HTTP_FORWARDED_FOR',
39
+ 'HTTP_FORWARDED',
40
+ 'HTTP_X_CLIENT_IP',
41
+ 'HTTP_CLIENT_IP',
42
+ 'HTTP_X_REAL_IP',
43
+ 'HTTP_X_CLUSTER_CLIENT_IP',
44
+ 'REMOTE_ADDR']
45
+
46
+ def geocoder_spoofable_ip
47
+
48
+ # We could use a more sophisticated IP-guessing algorithm here,
49
+ # in which we'd try to resolve the use of different headers by
50
+ # different proxies. The idea is that by comparing IPs repeated
51
+ # in different headers, you can sometimes decide which header
52
+ # was used by a proxy further along in the chain, and thus
53
+ # prefer the headers used earlier. However, the gains might not
54
+ # be worth the performance tradeoff, since this method is likely
55
+ # to be called on every request in a lot of applications.
56
+ GEOCODER_CANDIDATE_HEADERS.each do |header|
57
+ if @env.has_key? header
58
+ addrs = geocoder_split_ip_addresses(@env[header])
59
+ addrs = geocoder_remove_port_from_addresses(addrs)
60
+ addrs = geocoder_reject_non_ipv4_addresses(addrs)
61
+ addrs = geocoder_reject_trusted_ip_addresses(addrs)
62
+ return addrs.first if addrs.any?
63
+ end
64
+ end
65
+
66
+ @env['REMOTE_ADDR']
67
+ end
68
+
69
+ private
70
+
71
+ def geocoder_split_ip_addresses(ip_addresses)
72
+ ip_addresses ? ip_addresses.strip.split(/[,\s]+/) : []
73
+ end
74
+
75
+ # use Rack's trusted_proxy?() method to filter out IPs that have
76
+ # been configured as trusted; includes private ranges by
77
+ # default. (we don't want every lookup to return the location
78
+ # of our own proxy/load balancer)
79
+ def geocoder_reject_trusted_ip_addresses(ip_addresses)
80
+ ip_addresses.reject { |ip| trusted_proxy?(ip) }
81
+ end
82
+
83
+ def geocoder_remove_port_from_addresses(ip_addresses)
84
+ ip_addresses.map do |ip|
85
+ # IPv4
86
+ if ip.count('.') > 0
87
+ ip.split(':').first
88
+ # IPv6 bracket notation
89
+ elsif match = ip.match(/\[(\S+)\]/)
90
+ match.captures.first
91
+ # IPv6 bare notation
92
+ else
93
+ ip
94
+ end
95
+ end
96
+ end
97
+
98
+ def geocoder_reject_non_ipv4_addresses(ip_addresses)
99
+ ips = []
100
+ for ip in ip_addresses
101
+ begin
102
+ valid_ip = IPAddr.new(ip)
103
+ rescue
104
+ valid_ip = false
105
+ end
106
+ ips << valid_ip.to_s if valid_ip
107
+ end
108
+ return ips.any? ? ips : ip_addresses
109
+ end
110
+ end
111
+ end
112
+
113
+ ActionDispatch::Request.__send__(:include, Geocoder::Request) if defined?(ActionDispatch::Request)
114
+ Rack::Request.__send__(:include, Geocoder::Request) if defined?(Rack::Request)