Skip to content

Commit

Permalink
Added Dispatcher classes to perform API calls without depending on an…
Browse files Browse the repository at this point in the history
…other Twitter client gem.
  • Loading branch information
Michael Bleigh committed Mar 20, 2009
1 parent 4ff5ea6 commit 8b9bdf1
Show file tree
Hide file tree
Showing 12 changed files with 254 additions and 7 deletions.
2 changes: 1 addition & 1 deletion README.markdown
Expand Up @@ -23,7 +23,7 @@ Usage

To utilize TwitterAuth in your application you will need to run the generator:

script/generate twitter_auth [--oauth(default)|--basic]
script/generate twitter_auth [--oauth (default) | --basic]

This will generate a migration as well as set up the stubs needed to use the Rails Engines controllers and models set up by TwitterAuth. It will also create a User class that inherits from TwitterUser, abstracting away all of the Twitter authentication functionality and leaving you a blank slate to work with for your application.

Expand Down
6 changes: 1 addition & 5 deletions app/models/twitter_auth/basic_user.rb
Expand Up @@ -12,11 +12,7 @@ def self.included(base)

module ClassMethods
def verify_credentials(login, password)
uri = URI.parse(TwitterAuth.base_url)
net = Net::HTTP.new(uri.host, uri.port)
net.use_ssl = uri.scheme == 'https'
net.read_timeout = TwitterAuth.api_timeout
response = net.start { |http|
response = TwitterAuth.net.start { |http|
request = Net::HTTP::Get.new('/account/verify_credentials.json')
request.basic_auth login, password
http.request(request)
Expand Down
8 changes: 8 additions & 0 deletions app/models/twitter_auth/generic_user.rb
Expand Up @@ -58,5 +58,13 @@ def update_twitter_attributes(hash)
else
include TwitterAuth::BasicUser
end

def twitter
if TwitterAuth.oauth?
TwitterAuth::Dispatcher::Oauth.new(self)
else
TwitterAuth::Dispatcher::Basic.new(self)
end
end
end
end
2 changes: 1 addition & 1 deletion app/models/twitter_auth/oauth_user.rb
Expand Up @@ -33,6 +33,6 @@ def create_from_twitter_hash_and_token(user_info, access_token)

def token
OAuth::AccessToken.new(TwitterAuth.consumer, access_token, access_secret)
end
end
end
end
12 changes: 12 additions & 0 deletions lib/twitter_auth.rb
@@ -1,4 +1,6 @@
module TwitterAuth
class Error < StandardError; end

def self.config(environment=RAILS_ENV)
@config ||= {}
@config[environment] ||= YAML.load(File.open(RAILS_ROOT + '/config/twitter_auth.yml').read)[environment]
Expand Down Expand Up @@ -52,6 +54,16 @@ def self.consumer
:site => TwitterAuth.base_url
)
end

def self.net
uri = URI.parse(TwitterAuth.base_url)
net = Net::HTTP.new(uri.host, uri.port)
net.use_ssl = uri.scheme == 'https'
net.read_timeout = TwitterAuth.api_timeout
net
end
end

require 'twitter_auth/controller_extensions'
require 'twitter_auth/cryptify'
require 'twitter_auth/dispatcher/oauth'
44 changes: 44 additions & 0 deletions lib/twitter_auth/dispatcher/basic.rb
@@ -0,0 +1,44 @@
require 'net/http'

module TwitterAuth
module Dispatcher
class Basic
attr_accessor :user

def initialize(user)
raise TwitterAuth::Error, 'Dispatcher must be initialized with a User.' unless user.is_a?(TwitterAuth::BasicUser)
self.user = user
end

def request(http_method, path, *arguments)
path << '.json' unless path.match(/\.(:?xml|json)\z/i)

response = TwitterAuth.net.start{ |http|
req = "Net::HTTP::#{http_method.to_s.capitalize}".constantize.new(path, *arguments)
req.basic_auth user.login, user.password
http.request(req)
}

JSON.parse(response.body)
rescue JSON::ParserError
response.body
end

def get(path, *arguments)
request(:get, path, *arguments)
end

def post(path, *arguments)
request(:post, path, *arguments)
end

def put(path, *arguments)
request(:put, path, *arguments)
end

def delete(path, *arguments)
request(:delete, path, *arguments)
end
end
end
end
23 changes: 23 additions & 0 deletions lib/twitter_auth/dispatcher/oauth.rb
@@ -0,0 +1,23 @@
require 'oauth'

module TwitterAuth
module Dispatcher
class Oauth < OAuth::AccessToken
attr_accessor :user

def initialize(user)
raise TwitterAuth::Error, 'Dispatcher must be initialized with a User.' unless user.is_a?(TwitterAuth::OauthUser)
self.user = user
super(TwitterAuth.consumer, user.access_token, user.access_secret)
end

def request(http_method, path, *arguments)
path << '.json' unless path.match(/\.(:?xml|json)\z/i)
response = super
JSON.parse(response.body)
rescue JSON::ParserError
response.body
end
end
end
end
14 changes: 14 additions & 0 deletions spec/models/twitter_auth/basic_user_spec.rb
Expand Up @@ -105,4 +105,18 @@
user.password.should == 'test'
end
end

describe '#twitter' do
before do
@user = Factory.create(:twitter_basic_user)
end

it 'should be an instance of TwitterAuth::Dispatcher::Basic' do
@user.twitter.class.should == TwitterAuth::Dispatcher::Basic
end

it 'should have the correct user set' do
@user.twitter.user.should == @user
end
end
end
15 changes: 15 additions & 0 deletions spec/models/twitter_auth/oauth_user_spec.rb
Expand Up @@ -67,4 +67,19 @@
@user.token.secret.should == @user.access_secret
end
end

describe '#twitter' do
before do
@user = Factory.create(:twitter_oauth_user, :access_token => 'token', :access_secret => 'secret')
end

it 'should return a TwitterAuth::Dispatcher::Oauth' do
@user.twitter.should be_a(TwitterAuth::Dispatcher::Oauth)
end

it 'should use my token and secret' do
@user.twitter.token.should == @user.access_token
@user.twitter.secret.should == @user.access_secret
end
end
end
59 changes: 59 additions & 0 deletions spec/twitter_auth/dispatcher/basic_spec.rb
@@ -0,0 +1,59 @@
require File.dirname(__FILE__) + '/../../spec_helper'

describe TwitterAuth::Dispatcher::Basic do
before do
stub_basic!
@user = Factory.create(:twitter_basic_user, :login => 'twitterman', :password => 'test')
end

it 'should require a user as the initialization argument' do
lambda{TwitterAuth::Dispatcher::Basic.new(nil)}.should raise_error(TwitterAuth::Error, 'Dispatcher must be initialized with a User.')
end

it 'should store the user in an attr_accessor' do
TwitterAuth::Dispatcher::Basic.new(@user).user.should == @user
end

describe '#request' do
before do
@dispatcher = TwitterAuth::Dispatcher::Basic.new(@user)
FakeWeb.register_uri('https://twitter.com:443/fake.json', :string => {'fake' => true}.to_json)
FakeWeb.register_uri('https://twitter.com:443/fake.xml', :string => '<fake>true</fake>')
end

it 'should automatically parse JSON if valid' do
@dispatcher.request(:get, '/fake.json').should == {'fake' => true}
end

it 'should return XML as a string' do
@dispatcher.request(:get, '/fake.xml').should == "<fake>true</fake>"
end

it 'should append .json to the path if no extension is provided' do
@dispatcher.request(:get, '/fake.json').should == @dispatcher.request(:get, '/fake')
end

%w(get post put delete).each do |method|
it "should build a #{method} class based on a :#{method} http_method" do
@req = "Net::HTTP::#{method.capitalize}".constantize.new('/fake.json')
"Net::HTTP::#{method.capitalize}".constantize.should_receive(:new).and_return(@req)
@dispatcher.request(method.to_sym, '/fake')
end
end

it 'should start the HTTP session' do
@net = TwitterAuth.net
TwitterAuth.stub!(:net).and_return(@net)
@net.should_receive(:start)
lambda{@dispatcher.request(:get, '/fake')}.should raise_error(NoMethodError)
end
end

%w(get post delete put).each do |method|
it "should have a ##{method} method that calls request(:#{method})" do
dispatcher = TwitterAuth::Dispatcher::Basic.new(@user)
dispatcher.should_receive(:request).with(method.to_sym, '/fake.json')
dispatcher.send(method, '/fake.json')
end
end
end
52 changes: 52 additions & 0 deletions spec/twitter_auth/dispatcher/oauth_spec.rb
@@ -0,0 +1,52 @@
require File.dirname(__FILE__) + '/../../spec_helper'

describe TwitterAuth::Dispatcher::Oauth do
before do
stub_oauth!
@user = Factory.create(:twitter_oauth_user, :access_token => 'token', :access_secret => 'secret')
end

it 'should be a child class of OAuth::AccessToken' do
TwitterAuth::Dispatcher::Oauth.new(@user).should be_a(OAuth::AccessToken)
end

it 'should require initialization of an OauthUser' do
lambda{TwitterAuth::Dispatcher::Oauth.new(nil)}.should raise_error(TwitterAuth::Error, 'Dispatcher must be initialized with a User.')
end

it 'should store the user in an attr_accessor' do
TwitterAuth::Dispatcher::Oauth.new(@user).user.should == @user
end

it "should initialize with the user's token and secret" do
d = TwitterAuth::Dispatcher::Oauth.new(@user)
d.token.should == 'token'
d.secret.should == 'secret'
end

describe '#request' do
before do
@dispatcher = TwitterAuth::Dispatcher::Oauth.new(@user)
FakeWeb.register_uri(:get, 'https://twitter.com:443/fake.json', :string => {'fake' => true}.to_json)
FakeWeb.register_uri(:get, 'https://twitter.com:443/fake.xml', :string => "<fake>true</fake>")
end

it 'should automatically parse json' do
result = @dispatcher.request(:get, '/fake.json')
result.should be_a(Hash)
result['fake'].should be_true
end

it 'should return xml as a string' do
@dispatcher.request(:get, '/fake.xml').should == '<fake>true</fake>'
end

it 'should append .json to the path if no extension is provided' do
@dispatcher.request(:get, '/fake').should == @dispatcher.request(:get, '/fake.json')
end

it 'should work with verb methods' do
@dispatcher.get('/fake').should == @dispatcher.request(:get, '/fake')
end
end
end
24 changes: 24 additions & 0 deletions spec/twitter_auth_spec.rb
Expand Up @@ -23,6 +23,30 @@
TwitterAuth.stub!(:config).and_return({'api_timeout' => 15})
TwitterAuth.api_timeout.should == 15
end
end

describe '.net' do
before do
stub_basic!
end

it 'should return a Net::HTTP object' do
TwitterAuth.net.should be_a(Net::HTTP)
end

it 'should be SSL if the base_url is' do
TwitterAuth.stub!(:config).and_return({'base_url' => 'http://twitter.com'})
TwitterAuth.net.use_ssl?.should be_false
TwitterAuth.stub!(:config).and_return({'base_url' => 'https://twitter.com'})
TwitterAuth.net.use_ssl?.should be_true
end

it 'should work from the base_url' do
@net = Net::HTTP.new('example.com',80)
Net::HTTP.should_receive(:new).with('example.com',80).and_return(@net)
TwitterAuth.stub!(:config).and_return({'base_url' => 'http://example.com'})
TwitterAuth.net
end
end

describe '#config' do
Expand Down

0 comments on commit 8b9bdf1

Please sign in to comment.