geokit 1.7.1 → 1.8.0

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 (78) hide show
  1. checksums.yaml +6 -14
  2. data/.travis.yml +1 -0
  3. data/CHANGELOG.md +11 -0
  4. data/Gemfile +2 -1
  5. data/MIT-LICENSE +20 -0
  6. data/README.markdown +44 -39
  7. data/Rakefile +15 -0
  8. data/fixtures/vcr_cassettes/bing_full.yml +102 -0
  9. data/fixtures/vcr_cassettes/bing_full_au.yml +91 -0
  10. data/fixtures/vcr_cassettes/bing_full_de.yml +91 -0
  11. data/fixtures/vcr_cassettes/fcc_reverse_geocode.yml +37 -0
  12. data/fixtures/vcr_cassettes/free_geo_ip_geocode.yml +36 -0
  13. data/fixtures/vcr_cassettes/geo_plugin_geocode.yml +38 -0
  14. data/fixtures/vcr_cassettes/geonames_geocode.yml +304 -0
  15. data/fixtures/vcr_cassettes/{google3_city.yml → google_city.yml} +0 -0
  16. data/fixtures/vcr_cassettes/{google3_country_code_biased_result.yml → google_country_code_biased_result.yml} +0 -0
  17. data/fixtures/vcr_cassettes/{google3_full.yml → google_full.yml} +0 -0
  18. data/fixtures/vcr_cassettes/{google3_full_short.yml → google_full_short.yml} +0 -0
  19. data/fixtures/vcr_cassettes/{google3_language_response_fr.yml → google_language_response_fr.yml} +0 -0
  20. data/fixtures/vcr_cassettes/{google3_multi.yml → google_multi.yml} +0 -0
  21. data/fixtures/vcr_cassettes/{google3_reverse_madrid.yml → google_reverse_madrid.yml} +0 -0
  22. data/fixtures/vcr_cassettes/ripe_geocode.yml +66 -0
  23. data/fixtures/vcr_cassettes/ripe_geocode_au.yml +66 -0
  24. data/geokit.gemspec +1 -1
  25. data/lib/geokit.rb +5 -0
  26. data/lib/geokit/bounds.rb +96 -0
  27. data/lib/geokit/core_ext.rb +17 -0
  28. data/lib/geokit/geo_loc.rb +134 -0
  29. data/lib/geokit/geocoders.rb +48 -35
  30. data/lib/geokit/geocoders/base_ip.rb +43 -0
  31. data/lib/geokit/geocoders/bing.rb +101 -0
  32. data/lib/geokit/geocoders/ca_geocoder.rb +50 -0
  33. data/lib/geokit/{services → geocoders}/fcc.rb +17 -20
  34. data/lib/geokit/geocoders/free_geo_ip.rb +34 -0
  35. data/lib/geokit/geocoders/geo_plugin.rb +33 -0
  36. data/lib/geokit/geocoders/geonames.rb +53 -0
  37. data/lib/geokit/{services/google3.rb → geocoders/google.rb} +59 -57
  38. data/lib/geokit/geocoders/ip.rb +69 -0
  39. data/lib/geokit/geocoders/mapquest.rb +72 -0
  40. data/lib/geokit/geocoders/maxmind.rb +29 -0
  41. data/lib/geokit/geocoders/openstreetmap.rb +119 -0
  42. data/lib/geokit/geocoders/ripe.rb +41 -0
  43. data/lib/geokit/{services → geocoders}/us_geocoder.rb +15 -20
  44. data/lib/geokit/{services → geocoders}/yahoo.rb +52 -55
  45. data/lib/geokit/geocoders/yandex.rb +61 -0
  46. data/lib/geokit/inflectors.rb +1 -2
  47. data/lib/geokit/lat_lng.rb +129 -0
  48. data/lib/geokit/mappable.rb +41 -424
  49. data/lib/geokit/multi_geocoder.rb +6 -2
  50. data/lib/geokit/polygon.rb +46 -0
  51. data/lib/geokit/version.rb +1 -1
  52. data/test/helper.rb +2 -12
  53. data/test/test_base_geocoder.rb +0 -10
  54. data/test/test_bing_geocoder.rb +60 -0
  55. data/test/test_fcc_geocoder.rb +23 -0
  56. data/test/test_free_geo_ip_geocoder.rb +23 -0
  57. data/test/test_geo_plugin_geocoder.rb +23 -0
  58. data/test/test_geonames_geocoder.rb +23 -0
  59. data/test/test_google_geocoder.rb +208 -235
  60. data/test/test_maxmind_geocoder.rb +35 -4
  61. data/test/test_multi_geocoder.rb +3 -1
  62. data/test/test_ripe_geocoder.rb +35 -0
  63. data/test/test_yahoo_geocoder.rb +0 -12
  64. metadata +78 -52
  65. data/LICENSE +0 -25
  66. data/Manifest.txt +0 -21
  67. data/data/GeoLiteCity.dat +0 -0
  68. data/lib/geokit/services/ca_geocoder.rb +0 -55
  69. data/lib/geokit/services/geo_plugin.rb +0 -31
  70. data/lib/geokit/services/geonames.rb +0 -53
  71. data/lib/geokit/services/google.rb +0 -158
  72. data/lib/geokit/services/ip.rb +0 -103
  73. data/lib/geokit/services/maxmind.rb +0 -39
  74. data/lib/geokit/services/openstreetmap.rb +0 -119
  75. data/lib/geokit/services/ripe.rb +0 -32
  76. data/lib/geokit/services/yandex.rb +0 -51
  77. data/test/test_google_geocoder3.rb +0 -238
  78. data/test/test_google_reverse_geocoder.rb +0 -49
data/Manifest.txt DELETED
@@ -1,21 +0,0 @@
1
- History.txt
2
- Manifest.txt
3
- README.markdown
4
- Rakefile
5
- geokit.gemspec
6
- lib/geokit.rb
7
- lib/geokit/geocoders.rb
8
- lib/geokit/mappable.rb
9
- test/test_base_geocoder.rb
10
- test/test_bounds.rb
11
- test/test_ca_geocoder.rb
12
- test/test_geoloc.rb
13
- test/test_geoplugin_geocoder.rb
14
- test/test_google_geocoder.rb
15
- test/test_google_reverse_geocoder.rb
16
- test/test_inflector.rb
17
- test/test_ipgeocoder.rb
18
- test/test_latlng.rb
19
- test/test_multi_geocoder.rb
20
- test/test_us_geocoder.rb
21
- test/test_yahoo_geocoder.rb
data/data/GeoLiteCity.dat DELETED
Binary file
@@ -1,55 +0,0 @@
1
-
2
- # Geocoder CA geocoder implementation. Requires the Geokit::Geocoders::GEOCODER_CA variable to
3
- # contain true or false based upon whether authentication is to occur. Conforms to the
4
- # interface set by the Geocoder class.
5
- #
6
- # Returns a response like:
7
- # <?xml version="1.0" encoding="UTF-8" ?>
8
- # <geodata>
9
- # <latt>49.243086</latt>
10
- # <longt>-123.153684</longt>
11
- # </geodata>
12
- module Geokit
13
- module Geocoders
14
- class CaGeocoder < Geocoder
15
-
16
- private
17
-
18
- # Template method which does the geocode lookup.
19
- def self.do_geocode(address, options = {})
20
- raise ArgumentError('Geocoder.ca requires a GeoLoc argument') unless address.is_a?(GeoLoc)
21
- url = construct_request(address)
22
- res = self.call_geocoder_service(url)
23
- return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
24
- xml = res.body
25
- logger.debug "Geocoder.ca geocoding. Address: #{address}. Result: #{xml}"
26
- # Parse the document.
27
- doc = REXML::Document.new(xml)
28
- address.lat = doc.elements['//latt'].text
29
- address.lng = doc.elements['//longt'].text
30
- address.success = true
31
- return address
32
- rescue
33
- logger.error "Caught an error during Geocoder.ca geocoding call: "+$!
34
- return GeoLoc.new
35
- end
36
-
37
- # Formats the request in the format acceptable by the CA geocoder.
38
- def self.construct_request(location)
39
- url = ""
40
- url += add_ampersand(url) + "stno=#{location.street_number}" if location.street_address
41
- url += add_ampersand(url) + "addresst=#{Geokit::Inflector::url_escape(location.street_name)}" if location.street_address
42
- url += add_ampersand(url) + "city=#{Geokit::Inflector::url_escape(location.city)}" if location.city
43
- url += add_ampersand(url) + "prov=#{location.state}" if location.state
44
- url += add_ampersand(url) + "postal=#{location.zip}" if location.zip
45
- url += add_ampersand(url) + "auth=#{Geokit::Geocoders::geocoder_ca}" if Geokit::Geocoders::geocoder_ca
46
- url += add_ampersand(url) + "geoit=xml"
47
- 'http://geocoder.ca/?' + url
48
- end
49
-
50
- def self.add_ampersand(url)
51
- url && url.length > 0 ? "&" : ""
52
- end
53
- end
54
- end
55
- end
@@ -1,31 +0,0 @@
1
- module Geokit
2
- module Geocoders
3
- # Provides geocoding based upon an IP address. The underlying web service is geoplugin.net
4
- class GeoPluginGeocoder < Geocoder
5
- private
6
-
7
- def self.do_geocode(ip, options = {})
8
- return GeoLoc.new unless /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/.match(ip)
9
- response = self.call_geocoder_service("http://www.geoplugin.net/xml.gp?ip=#{ip}")
10
- return response.is_a?(Net::HTTPSuccess) ? parse_xml(response.body) : GeoLoc.new
11
- rescue
12
- logger.error "Caught an error during GeoPluginGeocoder geocoding call: "+$!
13
- return GeoLoc.new
14
- end
15
-
16
- def self.parse_xml(xml)
17
- xml = REXML::Document.new(xml)
18
- geo = GeoLoc.new
19
- geo.provider='geoPlugin'
20
- geo.city = xml.elements['//geoplugin_city'].text
21
- geo.state = xml.elements['//geoplugin_region'].text
22
- geo.country_code = xml.elements['//geoplugin_countryCode'].text
23
- geo.lat = xml.elements['//geoplugin_latitude'].text.to_f
24
- geo.lng = xml.elements['//geoplugin_longitude'].text.to_f
25
- geo.success = !!geo.city && !geo.city.empty?
26
- return geo
27
- end
28
- end
29
-
30
- end
31
- end
@@ -1,53 +0,0 @@
1
- module Geokit
2
- module Geocoders
3
- # Another geocoding web service
4
- # http://www.geonames.org
5
- class GeonamesGeocoder < Geocoder
6
-
7
- private
8
-
9
- # Template method which does the geocode lookup.
10
- def self.do_geocode(address, options = {})
11
- address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
12
- # geonames need a space seperated search string
13
- address_str.gsub!(/,/, " ")
14
- params = "/postalCodeSearch?placename=#{Geokit::Inflector::url_escape(address_str)}&maxRows=10"
15
-
16
- if(Geokit::Geocoders::geonames)
17
- url = "http://ws.geonames.net#{params}&username=#{Geokit::Geocoders::geonames}"
18
- else
19
- url = "http://ws.geonames.org#{params}"
20
- end
21
-
22
- res = self.call_geocoder_service(url)
23
-
24
- return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
25
-
26
- xml=res.body
27
- logger.debug "Geonames geocoding. Address: #{address}. Result: #{xml}"
28
- doc=REXML::Document.new(xml)
29
-
30
- if(doc.elements['//geonames/totalResultsCount'].text.to_i > 0)
31
- res=GeoLoc.new
32
-
33
- # only take the first result
34
- res.lat=doc.elements['//code/lat'].text if doc.elements['//code/lat']
35
- res.lng=doc.elements['//code/lng'].text if doc.elements['//code/lng']
36
- res.country_code=doc.elements['//code/countryCode'].text if doc.elements['//code/countryCode']
37
- res.provider='genomes'
38
- res.city=doc.elements['//code/name'].text if doc.elements['//code/name']
39
- res.state=doc.elements['//code/adminName1'].text if doc.elements['//code/adminName1']
40
- res.zip=doc.elements['//code/postalcode'].text if doc.elements['//code/postalcode']
41
- res.success=true
42
- return res
43
- else
44
- logger.info "Geonames was unable to geocode address: "+address
45
- return GeoLoc.new
46
- end
47
-
48
- rescue
49
- logger.error "Caught an error during Geonames geocoding call: "+$!
50
- end
51
- end
52
- end
53
- end
@@ -1,158 +0,0 @@
1
- module Geokit
2
- module Geocoders
3
- # -------------------------------------------------------------------------------------------
4
- # Address geocoders that also provide reverse geocoding
5
- # -------------------------------------------------------------------------------------------
6
-
7
- # Google geocoder implementation. Requires the Geokit::Geocoders::GOOGLE variable to
8
- # contain a Google API key. Conforms to the interface set by the Geocoder class.
9
- class GoogleGeocoder < Geocoder
10
-
11
- private
12
-
13
- # Template method which does the reverse-geocode lookup.
14
- def self.do_reverse_geocode(latlng)
15
- latlng=LatLng.normalize(latlng)
16
- res = self.call_geocoder_service("http://maps.google.com/maps/geo?ll=#{Geokit::Inflector::url_escape(latlng.ll)}&output=xml&key=#{Geokit::Geocoders::google}&oe=utf-8")
17
- # res = Net::HTTP.get_response(URI.parse("http://maps.google.com/maps/geo?ll=#{Geokit::Inflector::url_escape(address_str)}&output=xml&key=#{Geokit::Geocoders::google}&oe=utf-8"))
18
- return GeoLoc.new unless (res.is_a?(Net::HTTPSuccess) || res.is_a?(Net::HTTPOK))
19
- xml = self.transcode_to_utf8(res.body)
20
- logger.debug "Google reverse-geocoding. LL: #{latlng}. Result: #{xml}"
21
- return self.xml2GeoLoc(xml)
22
- end
23
-
24
- # Template method which does the geocode lookup.
25
- #
26
- # Supports viewport/country code biasing
27
- #
28
- # ==== OPTIONS
29
- # * :bias - This option makes the Google Geocoder return results biased to a particular
30
- # country or viewport. Country code biasing is achieved by passing the ccTLD
31
- # ('uk' for .co.uk, for example) as a :bias value. For a list of ccTLD's,
32
- # look here: http://en.wikipedia.org/wiki/CcTLD. By default, the geocoder
33
- # will be biased to results within the US (ccTLD .com).
34
- #
35
- # If you'd like the Google Geocoder to prefer results within a given viewport,
36
- # you can pass a Geokit::Bounds object as the :bias value.
37
- #
38
- # ==== EXAMPLES
39
- # # By default, the geocoder will return Syracuse, NY
40
- # Geokit::Geocoders::GoogleGeocoder.geocode('Syracuse').country_code # => 'US'
41
- # # With country code biasing, it returns Syracuse in Sicily, Italy
42
- # Geokit::Geocoders::GoogleGeocoder.geocode('Syracuse', :bias => :it).country_code # => 'IT'
43
- #
44
- # # By default, the geocoder will return Winnetka, IL
45
- # Geokit::Geocoders::GoogleGeocoder.geocode('Winnetka').state # => 'IL'
46
- # # When biased to an bounding box around California, it will now return the Winnetka neighbourhood, CA
47
- # bounds = Geokit::Bounds.normalize([34.074081, -118.694401], [34.321129, -118.399487])
48
- # Geokit::Geocoders::GoogleGeocoder.geocode('Winnetka', :bias => bounds).state # => 'CA'
49
- def self.do_geocode(address, options = {})
50
- bias_str = options[:bias] ? construct_bias_string_from_options(options[:bias]) : ''
51
- address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
52
- res = self.call_geocoder_service("http://maps.google.com/maps/geo?q=#{Geokit::Inflector::url_escape(address_str)}&output=xml#{bias_str}&key=#{Geokit::Geocoders::google}&oe=utf-8")
53
- return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
54
- xml = self.transcode_to_utf8(res.body)
55
- logger.debug "Google geocoding. Address: #{address}. Result: #{xml}"
56
- return self.xml2GeoLoc(xml, address)
57
- end
58
-
59
- def self.construct_bias_string_from_options(bias)
60
- if bias.is_a?(String) or bias.is_a?(Symbol)
61
- # country code biasing
62
- "&gl=#{bias.to_s.downcase}"
63
- elsif bias.is_a?(Bounds)
64
- # viewport biasing
65
- "&ll=#{precise_ll(bias.center)}&spn=#{precise_ll(bias.to_span)}"
66
- end
67
- end
68
-
69
- # Precision to 6 decimal places as per:
70
- # https://developers.google.com/maps/documentation/staticmaps/?hl=en#Latlons
71
- def self.precise_ll(loc)
72
- "#{"%.6f" % loc.lat},#{"%.6f" % loc.lng}"
73
- end
74
-
75
- def self.xml2GeoLoc(xml, address="")
76
- doc=REXML::Document.new(xml)
77
-
78
- if doc.elements['//kml/Response/Status/code'].text == '200'
79
- geoloc = nil
80
- # Google can return multiple results as //Placemark elements.
81
- # iterate through each and extract each placemark as a geoloc
82
- doc.each_element('//Placemark') do |e|
83
- extracted_geoloc = extract_placemark(e) # g is now an instance of GeoLoc
84
- if geoloc.nil?
85
- # first time through, geoloc is still nil, so we make it the geoloc we just extracted
86
- geoloc = extracted_geoloc
87
- else
88
- # second (and subsequent) iterations, we push additional
89
- # geolocs onto "geoloc.all"
90
- geoloc.all.push(extracted_geoloc)
91
- end
92
- end
93
- return geoloc
94
- elsif doc.elements['//kml/Response/Status/code'].text == '620'
95
- raise Geokit::TooManyQueriesError
96
- else
97
- logger.info "Google was unable to geocode address: "+address
98
- return GeoLoc.new
99
- end
100
-
101
- rescue Geokit::TooManyQueriesError
102
- # re-raise because of other rescue
103
- raise Geokit::TooManyQueriesError, "Google returned a 620 status, too many queries. The given key has gone over the requests limit in the 24 hour period or has submitted too many requests in too short a period of time. If you're sending multiple requests in parallel or in a tight loop, use a timer or pause in your code to make sure you don't send the requests too quickly."
104
- rescue
105
- logger.error "Caught an error during Google geocoding call: "+$!
106
- return GeoLoc.new
107
- end
108
-
109
- # extracts a single geoloc from a //placemark element in the google results xml
110
- def self.extract_placemark(doc)
111
- res = GeoLoc.new
112
- coordinates=doc.elements['.//coordinates'].text.to_s.split(',')
113
-
114
- #basics
115
- res.lat=coordinates[1]
116
- res.lng=coordinates[0]
117
- res.country_code=doc.elements['.//CountryNameCode'].text if doc.elements['.//CountryNameCode']
118
- res.provider='google'
119
-
120
- #extended -- false if not not available
121
- res.city = doc.elements['.//LocalityName'].text if doc.elements['.//LocalityName']
122
- res.state = doc.elements['.//AdministrativeAreaName'].text if doc.elements['.//AdministrativeAreaName']
123
- res.province = doc.elements['.//SubAdministrativeAreaName'].text if doc.elements['.//SubAdministrativeAreaName']
124
- res.full_address = doc.elements['.//address'].text if doc.elements['.//address'] # google provides it
125
- res.zip = doc.elements['.//PostalCodeNumber'].text if doc.elements['.//PostalCodeNumber']
126
- res.street_address = doc.elements['.//ThoroughfareName'].text if doc.elements['.//ThoroughfareName']
127
- res.country = doc.elements['.//CountryName'].text if doc.elements['.//CountryName']
128
- res.district = doc.elements['.//DependentLocalityName'].text if doc.elements['.//DependentLocalityName']
129
- # Translate accuracy into Yahoo-style token address, street, zip, zip+4, city, state, country
130
- # For Google, 1=low accuracy, 8=high accuracy
131
- address_details=doc.elements['.//*[local-name() = "AddressDetails"]']
132
- res.accuracy = address_details ? address_details.attributes['Accuracy'].to_i : 0
133
- res.precision=%w{unknown country state state city zip zip+4 street address building}[res.accuracy]
134
-
135
- # google returns a set of suggested boundaries for the geocoded result
136
- if suggested_bounds = doc.elements['//LatLonBox']
137
- res.suggested_bounds = Bounds.normalize(
138
- [suggested_bounds.attributes['south'], suggested_bounds.attributes['west']],
139
- [suggested_bounds.attributes['north'], suggested_bounds.attributes['east']])
140
- end
141
-
142
- res.success=true
143
-
144
- return res
145
- end
146
-
147
- def self.transcode_to_utf8(body)
148
- require 'iconv' unless String.method_defined?(:encode)
149
- if String.method_defined?(:encode)
150
- body.encode!('UTF-8', 'UTF-8', :invalid => :replace)
151
- else
152
- ic = Iconv.new('UTF-8', 'UTF-8//IGNORE')
153
- body = ic.iconv(body)
154
- end
155
- end
156
- end
157
- end
158
- end
@@ -1,103 +0,0 @@
1
- module Geokit
2
- module Geocoders
3
- # Provides geocoding based upon an IP address. The underlying web service is a hostip.info
4
- # which sources their data through a combination of publicly available information as well
5
- # as community contributions.
6
- class IpGeocoder < Geocoder
7
-
8
- # A number of non-routable IP ranges.
9
- #
10
- # --
11
- # Sources for these:
12
- # RFC 3330: Special-Use IPv4 Addresses
13
- # The bogon list: http://www.cymru.com/Documents/bogon-list.html
14
-
15
- NON_ROUTABLE_IP_RANGES = [
16
- IPAddr.new('0.0.0.0/8'), # "This" Network
17
- IPAddr.new('10.0.0.0/8'), # Private-Use Networks
18
- IPAddr.new('14.0.0.0/8'), # Public-Data Networks
19
- IPAddr.new('127.0.0.0/8'), # Loopback
20
- IPAddr.new('169.254.0.0/16'), # Link local
21
- IPAddr.new('172.16.0.0/12'), # Private-Use Networks
22
- IPAddr.new('192.0.2.0/24'), # Test-Net
23
- IPAddr.new('192.168.0.0/16'), # Private-Use Networks
24
- IPAddr.new('198.18.0.0/15'), # Network Interconnect Device Benchmark Testing
25
- IPAddr.new('224.0.0.0/4'), # Multicast
26
- IPAddr.new('240.0.0.0/4') # Reserved for future use
27
- ].freeze
28
-
29
- private
30
-
31
- # Given an IP address, returns a GeoLoc instance which contains latitude,
32
- # longitude, city, and country code. Sets the success attribute to false if the ip
33
- # parameter does not match an ip address.
34
- def self.do_geocode(ip, options = {})
35
- return GeoLoc.new unless /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/.match(ip)
36
- return GeoLoc.new if self.private_ip_address?(ip)
37
- url = "http://api.hostip.info/get_html.php?ip=#{ip}&position=true"
38
- response = self.call_geocoder_service(url)
39
- ensure_utf8_encoding(response)
40
- response.is_a?(Net::HTTPSuccess) ? parse_body(response.body) : GeoLoc.new
41
- rescue
42
- logger.error "Caught an error during HostIp geocoding call: " + $!.to_s
43
- return GeoLoc.new
44
- end
45
-
46
- # Converts the body to YAML since its in the form of:
47
- #
48
- # Country: UNITED STATES (US)
49
- # City: Sugar Grove, IL
50
- # Latitude: 41.7696
51
- # Longitude: -88.4588
52
- #
53
- # then instantiates a GeoLoc instance to populate with location data.
54
- def self.parse_body(body) # :nodoc:
55
- body = body.encode('UTF-8') if body.respond_to? :encode
56
- yaml = YAML.load(body)
57
- res = GeoLoc.new
58
- res.provider = 'hostip'
59
- res.city, res.state = yaml['City'].split(', ')
60
- res.country, res.country_code = yaml['Country'].split(' (')
61
- res.lat = yaml['Latitude']
62
- res.lng = yaml['Longitude']
63
- res.country_code.chop!
64
- res.success = !(res.city =~ /\(.+\)/)
65
- res
66
- end
67
-
68
- # Forces UTF-8 encoding on the body
69
- # Rails expects string input to be UTF-8
70
- # hostip.info specifies the charset encoding in the headers
71
- # thus extract encoding from headers and tell Rails about it by forcing it
72
- def self.ensure_utf8_encoding(response)
73
- if (enc_string = extract_charset(response))
74
- if defined?(Encoding) && Encoding.aliases.values.include?(enc_string.upcase)
75
- response.body.force_encoding(enc_string.upcase) if response.body.respond_to?(:force_encoding)
76
- response.body.encode("UTF-8")
77
- else
78
- require 'iconv'
79
- response.body.replace Iconv.conv("UTF8", "iso88591", response.body)
80
- end
81
- end
82
- end
83
-
84
- # Extracts charset out of the response headers
85
- def self.extract_charset(response)
86
- if (content_type = response['content-type'])
87
- capture = content_type.match(/charset=(.+)/)
88
- capture && capture[1]
89
- end
90
- end
91
-
92
- # Checks whether the IP address belongs to a private address range.
93
- #
94
- # This function is used to reduce the number of useless queries made to
95
- # the geocoding service. Such queries can occur frequently during
96
- # integration tests.
97
- def self.private_ip_address?(ip)
98
- return NON_ROUTABLE_IP_RANGES.any? { |range| range.include?(ip) }
99
- end
100
- end
101
- end
102
- end
103
-
@@ -1,39 +0,0 @@
1
- module Geokit
2
- module Geocoders
3
-
4
- @@geoip_data_path = File.expand_path(File.join(File.dirname(__FILE__),'../../..','data','GeoLiteCity.dat'))
5
- __define_accessors
6
-
7
- # Provides geocoding based upon an IP address. The underlying web service is MaxMind
8
- class MaxmindGeocoder < Geocoder
9
- private
10
-
11
- def self.do_geocode(ip, options = {})
12
- # return GeoLoc.new unless /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/.match(ip)
13
- return maxmind(ip)
14
- rescue
15
- logger.error "Caught an error during MaxMind geocoding call: " + $!.to_s
16
- return GeoLoc.new
17
- end
18
-
19
-
20
- def self.maxmind(ip)
21
- res = GeoIP.new(Geokit::Geocoders::geoip_data_path).city(ip)
22
-
23
- loc = GeoLoc.new(
24
- :provider => 'maxmind_city',
25
- :lat => res.latitude,
26
- :lng => res.longitude,
27
- :city => res.city_name,
28
- :state => res.region_name,
29
- :zip => res.postal_code,
30
- :country_code => res.country_code3
31
- )
32
-
33
- # loc.success = res.city_name && res.city_name != ''
34
- loc.success = (res.longitude > 0 && res.latitude > 0)
35
- return loc
36
- end
37
- end
38
- end
39
- end