geokit 1.7.0.rc1 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/CHANGELOG.md +37 -18
- data/Gemfile +2 -1
- data/README.markdown +4 -5
- data/Rakefile +2 -1
- data/data/GeoLiteCity.dat +0 -0
- data/fixtures/vcr_cassettes/google3_city.yml +104 -0
- data/fixtures/vcr_cassettes/google3_country_code_biased_result.yml +399 -0
- data/fixtures/vcr_cassettes/google3_full.yml +120 -0
- data/fixtures/vcr_cassettes/google3_full_short.yml +104 -0
- data/fixtures/vcr_cassettes/google3_language_response_fr.yml +82 -0
- data/fixtures/vcr_cassettes/google3_multi.yml +391 -0
- data/fixtures/vcr_cassettes/google3_reverse_madrid.yml +454 -0
- data/fixtures/vcr_cassettes/yahoo_city.yml +43 -0
- data/fixtures/vcr_cassettes/yahoo_full.yml +44 -0
- data/fixtures/vcr_cassettes/yahoo_no_results.yml +40 -0
- data/geokit.gemspec +4 -3
- data/lib/geokit/geocoders.rb +6 -3
- data/lib/geokit/mappable.rb +0 -5
- data/lib/geokit/services/google3.rb +17 -10
- data/lib/geokit/services/ip.rb +1 -1
- data/lib/geokit/services/maxmind.rb +41 -0
- data/lib/geokit/services/ripe.rb +32 -0
- data/lib/geokit/services/yahoo.rb +125 -5
- data/lib/geokit/services/yandex.rb +51 -0
- data/lib/geokit/version.rb +1 -1
- data/test/helper.rb +47 -1
- data/test/test_google_geocoder3.rb +71 -432
- data/test/test_maxmind_geocoder.rb +17 -0
- data/test/test_yahoo_geocoder.rb +39 -34
- data/test/test_yandex_geocoder.rb +93 -0
- metadata +66 -8
- data/ext/mkrf_conf.rb +0 -15
@@ -0,0 +1,43 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: http://yboss.yahooapis.com/geo/placefinder?flags=J&oauth_consumer_key=dj0yJmk9cXByQVN2WHZmTVhDJmQ9WVdrOVZscG1WVWhOTldrbWNHbzlNakF6TlRJME16UTJNZy0tJnM9Y29uc3VtZXJzZWNyZXQmeD0zNg--&oauth_nonce=731410e6df&oauth_signature=%2Bde/2eYXvMPhoRu5MUdjhPct3xY=&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1384355278&oauth_version=1.0&q=San%20Francisco,%20CA
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept-Encoding:
|
11
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
12
|
+
Accept:
|
13
|
+
- '*/*'
|
14
|
+
User-Agent:
|
15
|
+
- Ruby
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 200
|
19
|
+
message: OK
|
20
|
+
headers:
|
21
|
+
Date:
|
22
|
+
- Wed, 13 Nov 2013 15:08:00 GMT
|
23
|
+
P3p:
|
24
|
+
- policyref="http://info.yahoo.com/w3c/p3p.xml", CP="CAO DSP COR CUR ADM DEV
|
25
|
+
TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY
|
26
|
+
ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV"
|
27
|
+
Vary:
|
28
|
+
- Accept-Encoding
|
29
|
+
Transfer-Encoding:
|
30
|
+
- chunked
|
31
|
+
Content-Type:
|
32
|
+
- application/json
|
33
|
+
Cache-Control:
|
34
|
+
- private
|
35
|
+
body:
|
36
|
+
encoding: UTF-8
|
37
|
+
string: '{"bossresponse":{"responsecode":"200","placefinder":{"start":"0","count":"1","request":"flags=J&q=San%20Francisco%2C%20CA","results":[{"quality":"40","latitude":"37.77713","longitude":"-122.41964","offsetlat":"37.77713","offsetlon":"-122.41964","radius":"8800","name":"","line1":"","line2":"San
|
38
|
+
Francisco, CA","line3":"","line4":"United States","house":"","street":"","xstreet":"","unittype":"","unit":"","postal":"","neighborhood":"","city":"San
|
39
|
+
Francisco","county":"San Francisco County","state":"California","country":"United
|
40
|
+
States","countrycode":"US","statecode":"CA","countycode":"","uzip":"94102","hash":"","woeid":"2487956","woetype":"7"}]}}}'
|
41
|
+
http_version:
|
42
|
+
recorded_at: Wed, 13 Nov 2013 15:07:58 GMT
|
43
|
+
recorded_with: VCR 2.7.0
|
@@ -0,0 +1,44 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: http://yboss.yahooapis.com/geo/placefinder?flags=J&oauth_consumer_key=dj0yJmk9cXByQVN2WHZmTVhDJmQ9WVdrOVZscG1WVWhOTldrbWNHbzlNakF6TlRJME16UTJNZy0tJnM9Y29uc3VtZXJzZWNyZXQmeD0zNg--&oauth_nonce=7a0ce94e38&oauth_signature=aTamhmDusxM4xYZXWocDEb5YmyE=&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1384355278&oauth_version=1.0&q=100%20Spear%20St,%20San%20Francisco,%20CA,%2094105-1522,%20US
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept-Encoding:
|
11
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
12
|
+
Accept:
|
13
|
+
- '*/*'
|
14
|
+
User-Agent:
|
15
|
+
- Ruby
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 200
|
19
|
+
message: OK
|
20
|
+
headers:
|
21
|
+
Date:
|
22
|
+
- Wed, 13 Nov 2013 15:08:01 GMT
|
23
|
+
P3p:
|
24
|
+
- policyref="http://info.yahoo.com/w3c/p3p.xml", CP="CAO DSP COR CUR ADM DEV
|
25
|
+
TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY
|
26
|
+
ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV"
|
27
|
+
Vary:
|
28
|
+
- Accept-Encoding
|
29
|
+
Transfer-Encoding:
|
30
|
+
- chunked
|
31
|
+
Content-Type:
|
32
|
+
- application/json
|
33
|
+
Cache-Control:
|
34
|
+
- private
|
35
|
+
body:
|
36
|
+
encoding: UTF-8
|
37
|
+
string: '{"bossresponse":{"responsecode":"200","placefinder":{"start":"0","count":"1","request":"flags=J&q=100%20Spear%20St%2C%20San%20Francisco%2C%20CA%2C%2094105-1522%2C%20US","results":[{"quality":"87","latitude":"37.792332","longitude":"-122.393791","offsetlat":"37.792198","offsetlon":"-122.393898","radius":"400","name":"","line1":"100
|
38
|
+
Spear St","line2":"San Francisco, CA 94105-1578","line3":"","line4":"United
|
39
|
+
States","house":"100","street":"Spear St","xstreet":"","unittype":"","unit":"","postal":"94105-1578","neighborhood":"","city":"San
|
40
|
+
Francisco","county":"San Francisco County","state":"California","country":"United
|
41
|
+
States","countrycode":"US","statecode":"CA","countycode":"","uzip":"94105","hash":"0FA06819B5F53E75","woeid":"12797156","woetype":"11"}]}}}'
|
42
|
+
http_version:
|
43
|
+
recorded_at: Wed, 13 Nov 2013 15:07:59 GMT
|
44
|
+
recorded_with: VCR 2.7.0
|
@@ -0,0 +1,40 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: http://yboss.yahooapis.com/geo/placefinder?flags=J&oauth_consumer_key=dj0yJmk9cXByQVN2WHZmTVhDJmQ9WVdrOVZscG1WVWhOTldrbWNHbzlNakF6TlRJME16UTJNZy0tJnM9Y29uc3VtZXJzZWNyZXQmeD0zNg--&oauth_nonce=2c5ad2f846&oauth_signature=h2eR3b0GSWsgqU2nJhd1jPP8ihI=&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1384355895&oauth_version=1.0&q=ZZ,%20ZZ,%20ZZ
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept-Encoding:
|
11
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
12
|
+
Accept:
|
13
|
+
- '*/*'
|
14
|
+
User-Agent:
|
15
|
+
- Ruby
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 200
|
19
|
+
message: OK
|
20
|
+
headers:
|
21
|
+
Date:
|
22
|
+
- Wed, 13 Nov 2013 15:18:19 GMT
|
23
|
+
P3p:
|
24
|
+
- policyref="http://info.yahoo.com/w3c/p3p.xml", CP="CAO DSP COR CUR ADM DEV
|
25
|
+
TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY
|
26
|
+
ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV"
|
27
|
+
Vary:
|
28
|
+
- Accept-Encoding
|
29
|
+
Transfer-Encoding:
|
30
|
+
- chunked
|
31
|
+
Content-Type:
|
32
|
+
- application/json
|
33
|
+
Cache-Control:
|
34
|
+
- private
|
35
|
+
body:
|
36
|
+
encoding: UTF-8
|
37
|
+
string: '{"bossresponse":{"responsecode":"200","placefinder":{"start":"0","count":"0","request":"flags=J&q=ZZ%2C%20ZZ%2C%20ZZ"}}}'
|
38
|
+
http_version:
|
39
|
+
recorded_at: Wed, 13 Nov 2013 15:18:16 GMT
|
40
|
+
recorded_with: VCR 2.7.0
|
data/geokit.gemspec
CHANGED
@@ -10,13 +10,12 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.email = ["michael+geokit@noack.com.au"]
|
11
11
|
spec.description = %q{Geokit provides geocoding and distance calculation in an easy-to-use API}
|
12
12
|
spec.summary = %q{Geokit: encoding and distance calculation gem}
|
13
|
-
spec.homepage = "http://geokit
|
13
|
+
spec.homepage = "http://github.com/geokit/geokit"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
16
|
spec.has_rdoc = true
|
17
17
|
spec.rdoc_options = ["--main", "README.markdown"]
|
18
18
|
spec.extra_rdoc_files = ["README.markdown"]
|
19
|
-
spec.extensions = 'ext/mkrf_conf.rb'
|
20
19
|
|
21
20
|
spec.files = `git ls-files`.split($/)
|
22
21
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
@@ -29,5 +28,7 @@ Gem::Specification.new do |spec|
|
|
29
28
|
spec.add_development_dependency "simplecov-rcov"
|
30
29
|
spec.add_development_dependency 'rake'
|
31
30
|
spec.add_development_dependency 'mocha'
|
31
|
+
spec.add_development_dependency 'coveralls'
|
32
|
+
spec.add_development_dependency 'vcr'
|
33
|
+
spec.add_development_dependency 'webmock' # used in vcr
|
32
34
|
end
|
33
|
-
|
data/lib/geokit/geocoders.rb
CHANGED
@@ -38,7 +38,9 @@ module Geokit
|
|
38
38
|
@@proxy_user = nil
|
39
39
|
@@proxy_pass = nil
|
40
40
|
@@request_timeout = nil
|
41
|
-
@@
|
41
|
+
@@yahoo_consumer_key = 'REPLACE_WITH_YOUR_YAHOO_BOSS_OAUTH_CONSUMER_KEY'
|
42
|
+
@@yahoo_consumer_secret = 'REPLACE_WITH_YOUR_YAHOO_BOSS_OAUTH_CONSUMER_SECRET'
|
43
|
+
@@yandex = 'REPLACE_WITH_YOUR_YANDEX_KEY'
|
42
44
|
@@google = 'REPLACE_WITH_YOUR_GOOGLE_KEY'
|
43
45
|
@@google_client_id = nil
|
44
46
|
@@google_cryptographic_key = nil
|
@@ -133,10 +135,11 @@ module Geokit
|
|
133
135
|
uri = URI.parse(url)
|
134
136
|
req = Net::HTTP::Get.new(url)
|
135
137
|
req.basic_auth(uri.user, uri.password) if uri.userinfo
|
136
|
-
res = Net::HTTP::
|
138
|
+
res = Net::HTTP::new(uri.host, uri.port,
|
139
|
+
GeoKit::Geocoders::proxy_addr,
|
137
140
|
GeoKit::Geocoders::proxy_port,
|
138
141
|
GeoKit::Geocoders::proxy_user,
|
139
|
-
GeoKit::Geocoders::proxy_pass).start
|
142
|
+
GeoKit::Geocoders::proxy_pass).start { |http| http.request(req) }
|
140
143
|
return res
|
141
144
|
end
|
142
145
|
|
data/lib/geokit/mappable.rb
CHANGED
@@ -10,7 +10,7 @@ module Geokit
|
|
10
10
|
res = self.call_geocoder_service(submit_url)
|
11
11
|
return GeoLoc.new unless (res.is_a?(Net::HTTPSuccess) || res.is_a?(Net::HTTPOK))
|
12
12
|
json = res.body
|
13
|
-
logger.debug "Google reverse-geocoding. LL: #{latlng}. Result: #{json}"
|
13
|
+
logger.debug "Google reverse-geocoding. LL: #{latlng}. Result: #{CGI.escape(json)}"
|
14
14
|
return self.json2GeoLoc(json)
|
15
15
|
end
|
16
16
|
|
@@ -41,14 +41,15 @@ module Geokit
|
|
41
41
|
# Geokit::Geocoders::GoogleGeocoder.geocode('Winnetka', :bias => bounds).state # => 'CA'
|
42
42
|
def self.do_geocode(address, options = {})
|
43
43
|
bias_str = options[:bias] ? construct_bias_string_from_options(options[:bias]) : ''
|
44
|
+
language_str = options[:language] ? "&language=#{options[:language]}" : ''
|
44
45
|
address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
|
45
|
-
submit_url = submit_url("/maps/api/geocode/json?sensor=false&address=#{Geokit::Inflector::url_escape(address_str)}#{bias_str}")
|
46
|
+
submit_url = submit_url("/maps/api/geocode/json?sensor=false&address=#{Geokit::Inflector::url_escape(address_str)}#{bias_str}#{language_str}")
|
46
47
|
|
47
48
|
res = self.call_geocoder_service(submit_url)
|
48
49
|
return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
|
49
50
|
|
50
51
|
json = res.body
|
51
|
-
logger.debug "Google geocoding. Address: #{address}. Result: #{json}"
|
52
|
+
logger.debug "Google geocoding. Address: #{address}. Result: #{CGI.escape(json)}"
|
52
53
|
|
53
54
|
return self.json2GeoLoc(json, address)
|
54
55
|
end
|
@@ -85,7 +86,8 @@ module Geokit
|
|
85
86
|
"®ion=#{bias.to_s.downcase}"
|
86
87
|
when Bounds
|
87
88
|
# viewport biasing
|
88
|
-
Geokit::Inflector::url_escape("
|
89
|
+
url_escaped_string = Geokit::Inflector::url_escape("#{bias.sw.to_s}|#{bias.ne.to_s}")
|
90
|
+
"&bounds=#{url_escaped_string}"
|
89
91
|
end
|
90
92
|
end
|
91
93
|
|
@@ -180,12 +182,17 @@ module Geokit
|
|
180
182
|
res.accuracy = 7
|
181
183
|
end
|
182
184
|
|
183
|
-
res.
|
184
|
-
|
185
|
-
|
186
|
-
ne.
|
187
|
-
|
188
|
-
|
185
|
+
res.lat=addr['geometry']['location']['lat'].to_f
|
186
|
+
res.lng=addr['geometry']['location']['lng'].to_f
|
187
|
+
|
188
|
+
ne=Geokit::LatLng.new(
|
189
|
+
addr['geometry']['viewport']['northeast']['lat'].to_f,
|
190
|
+
addr['geometry']['viewport']['northeast']['lng'].to_f
|
191
|
+
)
|
192
|
+
sw=Geokit::LatLng.new(
|
193
|
+
addr['geometry']['viewport']['southwest']['lat'].to_f,
|
194
|
+
addr['geometry']['viewport']['southwest']['lng'].to_f
|
195
|
+
)
|
189
196
|
res.suggested_bounds = Geokit::Bounds.new(sw,ne)
|
190
197
|
|
191
198
|
res
|
data/lib/geokit/services/ip.rb
CHANGED
@@ -57,7 +57,7 @@ module Geokit
|
|
57
57
|
res = GeoLoc.new
|
58
58
|
res.provider = 'hostip'
|
59
59
|
res.city, res.state = yaml['City'].split(', ')
|
60
|
-
country, res.country_code = yaml['Country'].split(' (')
|
60
|
+
res.country, res.country_code = yaml['Country'].split(' (')
|
61
61
|
res.lat = yaml['Latitude']
|
62
62
|
res.lng = yaml['Longitude']
|
63
63
|
res.country_code.chop!
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "geoip"
|
2
|
+
|
3
|
+
module Geokit
|
4
|
+
module Geocoders
|
5
|
+
|
6
|
+
@@geoip_data_path = File.expand_path(File.join(File.dirname(__FILE__),'../../..','data','GeoLiteCity.dat'))
|
7
|
+
__define_accessors
|
8
|
+
|
9
|
+
# Provides geocoding based upon an IP address. The underlying web service is MaxMind
|
10
|
+
class MaxmindGeocoder < Geocoder
|
11
|
+
private
|
12
|
+
|
13
|
+
def self.do_geocode(ip, options = {})
|
14
|
+
# return GeoLoc.new unless /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/.match(ip)
|
15
|
+
return maxmind(ip)
|
16
|
+
rescue
|
17
|
+
logger.error "Caught an error during MaxMind geocoding call: " + $!.to_s
|
18
|
+
return GeoLoc.new
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def self.maxmind(ip)
|
23
|
+
res = GeoIP.new(Geokit::Geocoders::geoip_data_path).city(ip)
|
24
|
+
|
25
|
+
loc = GeoLoc.new(
|
26
|
+
:provider => 'maxmind_city',
|
27
|
+
:lat => res.latitude,
|
28
|
+
:lng => res.longitude,
|
29
|
+
:city => res.city_name,
|
30
|
+
:state => res.region_name,
|
31
|
+
:zip => res.postal_code,
|
32
|
+
:country_code => res.country_code3
|
33
|
+
)
|
34
|
+
|
35
|
+
# loc.success = res.city_name && res.city_name != ''
|
36
|
+
loc.success = (res.longitude > 0 && res.latitude > 0)
|
37
|
+
return loc
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Geokit
|
2
|
+
module Geocoders
|
3
|
+
# Provides geocoding based upon an IP address. The underlying web service is geoplugin.net
|
4
|
+
class RipeGeocoder < 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://stat.ripe.net/data/geoloc/data.json?resource=#{ip}")
|
10
|
+
return response.is_a?(Net::HTTPSuccess) ? parse_json(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_json(json)
|
17
|
+
json = MultiJson.load(json)
|
18
|
+
geo = GeoLoc.new
|
19
|
+
data = json['data']['locations'][0]
|
20
|
+
|
21
|
+
geo.provider='RIPE'
|
22
|
+
geo.city = data['city']
|
23
|
+
geo.country_code = data['country']
|
24
|
+
geo.lat = data['latitude']
|
25
|
+
geo.lng = data['longitude']
|
26
|
+
geo.success = (data['status_code'] == 200)
|
27
|
+
return geo
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -5,12 +5,21 @@ module Geokit
|
|
5
5
|
class YahooGeocoder < Geocoder
|
6
6
|
|
7
7
|
private
|
8
|
+
def self.submit_url(query_string)
|
9
|
+
o = OauthUtil.new
|
10
|
+
o.consumer_key = Geocoders::yahoo_consumer_key
|
11
|
+
o.consumer_secret = Geocoders::yahoo_consumer_secret
|
12
|
+
base = "http://yboss.yahooapis.com/geo/placefinder"
|
13
|
+
parsed_url = URI.parse("#{base}#{query_string}")
|
14
|
+
"http://yboss.yahooapis.com/geo/placefinder?#{o.sign(parsed_url).query_string}"
|
15
|
+
end
|
8
16
|
|
9
17
|
# Template method which does the geocode lookup.
|
10
18
|
def self.do_geocode(address, options = {})
|
11
19
|
address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
|
12
|
-
|
13
|
-
|
20
|
+
submit_url = submit_url("?q=#{Geokit::Inflector::url_escape(address_str)}&flags=J")
|
21
|
+
|
22
|
+
res = self.call_geocoder_service(submit_url)
|
14
23
|
return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
|
15
24
|
json = res.body
|
16
25
|
logger.debug "Yahoo geocoding. Address: #{address}. Result: #{json}"
|
@@ -20,9 +29,9 @@ module Geokit
|
|
20
29
|
def self.json2GeoLoc(json, address)
|
21
30
|
results = MultiJson.load(json)
|
22
31
|
|
23
|
-
if results['
|
32
|
+
if results && results['bossresponse'] && results['bossresponse']['placefinder'] && results['bossresponse']['placefinder']['results'] && results['bossresponse']['placefinder']['results'].first != nil
|
24
33
|
geoloc = nil
|
25
|
-
results['
|
34
|
+
results['bossresponse']['placefinder']['results'].each do |result|
|
26
35
|
extracted_geoloc = extract_geoloc(result)
|
27
36
|
if geoloc.nil?
|
28
37
|
geoloc = extracted_geoloc
|
@@ -52,7 +61,7 @@ module Geokit
|
|
52
61
|
geoloc.state = geoloc.is_us? ? result_json['statecode'] : result_json['state']
|
53
62
|
geoloc.zip = result_json['postal']
|
54
63
|
|
55
|
-
geoloc.precision = case result_json['quality']
|
64
|
+
geoloc.precision = case result_json['quality'].to_i
|
56
65
|
when 9,10 then 'country'
|
57
66
|
when 19..30 then 'state'
|
58
67
|
when 39,40 then 'city'
|
@@ -73,3 +82,114 @@ module Geokit
|
|
73
82
|
end
|
74
83
|
end
|
75
84
|
end
|
85
|
+
|
86
|
+
# Oauth Util
|
87
|
+
# from gist: https://gist.github.com/erikeldridge/383159
|
88
|
+
# A utility for signing an url using OAuth in a way that's convenient for debugging
|
89
|
+
# Note: the standard Ruby OAuth lib is here http://github.com/mojodna/oauth
|
90
|
+
# License: http://gist.github.com/375593
|
91
|
+
# Usage: see example.rb below
|
92
|
+
|
93
|
+
require 'uri'
|
94
|
+
require 'cgi'
|
95
|
+
require 'openssl'
|
96
|
+
require 'base64'
|
97
|
+
|
98
|
+
class OauthUtil
|
99
|
+
|
100
|
+
attr_accessor :consumer_key, :consumer_secret, :token, :token_secret, :req_method,
|
101
|
+
:sig_method, :oauth_version, :callback_url, :params, :req_url, :base_str
|
102
|
+
|
103
|
+
def initialize
|
104
|
+
@consumer_key = ''
|
105
|
+
@consumer_secret = ''
|
106
|
+
@token = ''
|
107
|
+
@token_secret = ''
|
108
|
+
@req_method = 'GET'
|
109
|
+
@sig_method = 'HMAC-SHA1'
|
110
|
+
@oauth_version = '1.0'
|
111
|
+
@callback_url = ''
|
112
|
+
end
|
113
|
+
|
114
|
+
# openssl::random_bytes returns non-word chars, which need to be removed. using alt method to get length
|
115
|
+
# ref http://snippets.dzone.com/posts/show/491
|
116
|
+
def nonce
|
117
|
+
Array.new( 5 ) { rand(256) }.pack('C*').unpack('H*').first
|
118
|
+
end
|
119
|
+
|
120
|
+
def percent_encode( string )
|
121
|
+
|
122
|
+
# ref http://snippets.dzone.com/posts/show/1260
|
123
|
+
return URI.escape( string, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]") ).gsub('*', '%2A')
|
124
|
+
end
|
125
|
+
|
126
|
+
# @ref http://oauth.net/core/1.0/#rfc.section.9.2
|
127
|
+
def signature
|
128
|
+
key = percent_encode( @consumer_secret ) + '&' + percent_encode( @token_secret )
|
129
|
+
|
130
|
+
# ref: http://blog.nathanielbibler.com/post/63031273/openssl-hmac-vs-ruby-hmac-benchmarks
|
131
|
+
digest = OpenSSL::Digest::Digest.new( 'sha1' )
|
132
|
+
hmac = OpenSSL::HMAC.digest( digest, key, @base_str )
|
133
|
+
|
134
|
+
# ref http://groups.google.com/group/oauth-ruby/browse_thread/thread/9110ed8c8f3cae81
|
135
|
+
Base64.encode64( hmac ).chomp.gsub( /\n/, '' )
|
136
|
+
end
|
137
|
+
|
138
|
+
# sort (very important as it affects the signature), concat, and percent encode
|
139
|
+
# @ref http://oauth.net/core/1.0/#rfc.section.9.1.1
|
140
|
+
# @ref http://oauth.net/core/1.0/#9.2.1
|
141
|
+
# @ref http://oauth.net/core/1.0/#rfc.section.A.5.1
|
142
|
+
def query_string
|
143
|
+
pairs = []
|
144
|
+
@params.sort.each { | key, val |
|
145
|
+
pairs.push( "#{ percent_encode( key ) }=#{ percent_encode( val.to_s ) }" )
|
146
|
+
}
|
147
|
+
pairs.join '&'
|
148
|
+
end
|
149
|
+
|
150
|
+
def timestamp
|
151
|
+
Time.now.to_i.to_s
|
152
|
+
end
|
153
|
+
|
154
|
+
# organize params & create signature
|
155
|
+
def sign( parsed_url )
|
156
|
+
|
157
|
+
@params = {
|
158
|
+
'oauth_consumer_key' => @consumer_key,
|
159
|
+
'oauth_nonce' => nonce,
|
160
|
+
'oauth_signature_method' => @sig_method,
|
161
|
+
'oauth_timestamp' => timestamp,
|
162
|
+
'oauth_version' => @oauth_version
|
163
|
+
}
|
164
|
+
|
165
|
+
# if url has query, merge key/values into params obj overwriting defaults
|
166
|
+
if parsed_url.query
|
167
|
+
CGI.parse( parsed_url.query ).each do |k,v|
|
168
|
+
if v.is_a?(Array) && v.count == 1
|
169
|
+
@params[k] = v.first
|
170
|
+
else
|
171
|
+
@params[k] = v
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# @ref http://oauth.net/core/1.0/#rfc.section.9.1.2
|
177
|
+
@req_url = parsed_url.scheme + '://' + parsed_url.host + parsed_url.path
|
178
|
+
|
179
|
+
# create base str. make it an object attr for ez debugging
|
180
|
+
# ref http://oauth.net/core/1.0/#anchor14
|
181
|
+
@base_str = [
|
182
|
+
@req_method,
|
183
|
+
percent_encode( req_url ),
|
184
|
+
|
185
|
+
# normalization is just x-www-form-urlencoded
|
186
|
+
percent_encode( query_string )
|
187
|
+
|
188
|
+
].join( '&' )
|
189
|
+
|
190
|
+
# add signature
|
191
|
+
@params[ 'oauth_signature' ] = signature
|
192
|
+
|
193
|
+
return self
|
194
|
+
end
|
195
|
+
end
|