Created
November 7, 2010 23:08
-
-
Save chebyte/667102 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
####lib#### | |
require 'net/http' | |
require 'hpricot' | |
require 'cgi' | |
require 'uri' | |
require 'cgi' | |
require 'openssl' | |
require 'base64' | |
module Chebyte | |
module Yahoo | |
class OauthUtil | |
attr_accessor :consumer_key, :consumer_secret, :token, :token_secret, :req_method, | |
:sig_method, :oauth_version, :callback_url, :params, :req_url, :base_str | |
def initialize | |
@consumer_key = '' | |
@consumer_secret = '' | |
@token = '' | |
@token_secret = '' | |
@req_method = 'GET' | |
@sig_method = 'HMAC-SHA1' | |
@oauth_version = '1.0' | |
@callback_url = '' | |
end | |
# openssl::random_bytes returns non-word chars, which need to be removed. using alt method to get length | |
# ref http://snippets.dzone.com/posts/show/491 | |
def nonce | |
Array.new( 5 ) { rand(256) }.pack('C*').unpack('H*').first | |
end | |
def percent_encode( string ) | |
# ref http://snippets.dzone.com/posts/show/1260 | |
return URI.escape( string, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]") ).gsub('*', '%2A') | |
end | |
# @ref http://oauth.net/core/1.0/#rfc.section.9.2 | |
def signature | |
key = percent_encode( @consumer_secret ) + '&' + percent_encode( @token_secret ) | |
# ref: http://blog.nathanielbibler.com/post/63031273/openssl-hmac-vs-ruby-hmac-benchmarks | |
digest = OpenSSL::Digest::Digest.new( 'sha1' ) | |
hmac = OpenSSL::HMAC.digest( digest, key, @base_str ) | |
# ref http://groups.google.com/group/oauth-ruby/browse_thread/thread/9110ed8c8f3cae81 | |
Base64.encode64( hmac ).chomp.gsub( /\n/, '' ) | |
end | |
# sort (very important as it affects the signature), concat, and percent encode | |
# @ref http://oauth.net/core/1.0/#rfc.section.9.1.1 | |
# @ref http://oauth.net/core/1.0/#9.2.1 | |
# @ref http://oauth.net/core/1.0/#rfc.section.A.5.1 | |
def query_string | |
pairs = [] | |
@params.sort.each { | key, val | | |
pairs.push( "#{ percent_encode( key ) }=#{ percent_encode( val.to_s ) }" ) | |
} | |
pairs.join '&' | |
end | |
# organize params & create signature | |
def sign( parsed_url ) | |
@params = { | |
'oauth_consumer_key' => @consumer_key, | |
'oauth_nonce' => nonce, | |
'oauth_signature_method' => @sig_method, | |
'oauth_timestamp' => Time.now.to_i.to_s, | |
'oauth_version' => @oauth_version | |
} | |
# if url has query, merge key/values into params obj overwriting defaults | |
if parsed_url.query | |
@params.merge! CGI.parse( parsed_url.query ) | |
end | |
# @ref http://oauth.net/core/1.0/#rfc.section.9.1.2 | |
@req_url = parsed_url.scheme + '://' + parsed_url.host + parsed_url.path | |
# create base str. make it an object attr for ez debugging | |
# ref http://oauth.net/core/1.0/#anchor14 | |
@base_str = [ | |
@req_method, | |
percent_encode( req_url ), | |
# normalization is just x-www-form-urlencoded | |
percent_encode( query_string ) | |
].join( '&' ) | |
# add signature | |
@params[ 'oauth_signature' ] = signature | |
return self | |
end | |
end | |
class GeoLoc | |
def initialize(api_key, share_key) | |
@o = OauthUtil.new | |
@o.consumer_key = api_key | |
@o.consumer_secret = share_key | |
@response = nil | |
end | |
def escape(string) | |
CGI::escape(string) | |
end | |
def find_by_address(string) | |
url = "http://query.yahooapis.com/v1/public/yql?q=SELECT%20centroid%20from%20geo.places%20WHERE%20text%3D'#{escape(string)}'&diagnostics=false" | |
parsed_url = URI.parse( url ) | |
Net::HTTP.start( parsed_url.host ) do | http | | |
req = Net::HTTP::Get.new "#{ parsed_url.path }?#{ @o.sign(parsed_url).query_string }" | |
@response = Location.new(Hpricot.XML(http.request(req).read_body)) | |
end | |
end | |
def find(sql) | |
url = "http://query.yahooapis.com/v1/public/yql?q=#{escape(sql)}" | |
parsed_url = URI.parse( sql ) | |
Net::HTTP.start( parsed_url.host ) do | http | | |
req = Net::HTTP::Get.new "#{ parsed_url.path }?#{ @o.sign(parsed_url).query_string }" | |
@response = Location.new(Hpricot.XML(http.request(req).read_body)) | |
end | |
end | |
end | |
class Location | |
def initialize(response) | |
@response = response | |
end | |
def latitude | |
(@response/"centroid").each{|location| return (location/"latitude").text} | |
end | |
def longitude | |
(@response/"centroid").each{|location| return (location/"longitude").text} | |
end | |
def coords | |
"#{latitude}, #{longitude}" | |
end | |
end | |
end | |
end | |
###USAGE#### | |
Chebyte::Yahoo::GeoLoc.new(api_key, shared_key).find_by_address("100 Spear st, San Francisco, CA").coords #"37.779598, -122.420143" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment