diff --git a/README.markdown b/README.markdown
index 9dca293..50aa12a 100644
--- a/README.markdown
+++ b/README.markdown
@@ -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.
diff --git a/app/models/twitter_auth/basic_user.rb b/app/models/twitter_auth/basic_user.rb
index 829e2b2..f460551 100644
--- a/app/models/twitter_auth/basic_user.rb
+++ b/app/models/twitter_auth/basic_user.rb
@@ -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)
diff --git a/app/models/twitter_auth/generic_user.rb b/app/models/twitter_auth/generic_user.rb
index 2887a49..0cbc266 100644
--- a/app/models/twitter_auth/generic_user.rb
+++ b/app/models/twitter_auth/generic_user.rb
@@ -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
diff --git a/app/models/twitter_auth/oauth_user.rb b/app/models/twitter_auth/oauth_user.rb
index 815e096..5e0367c 100644
--- a/app/models/twitter_auth/oauth_user.rb
+++ b/app/models/twitter_auth/oauth_user.rb
@@ -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
diff --git a/lib/twitter_auth.rb b/lib/twitter_auth.rb
index 1b6671e..1415182 100644
--- a/lib/twitter_auth.rb
+++ b/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]
@@ -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'
diff --git a/lib/twitter_auth/dispatcher/basic.rb b/lib/twitter_auth/dispatcher/basic.rb
new file mode 100644
index 0000000..fc5f627
--- /dev/null
+++ b/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
diff --git a/lib/twitter_auth/dispatcher/oauth.rb b/lib/twitter_auth/dispatcher/oauth.rb
new file mode 100644
index 0000000..ed8d3fe
--- /dev/null
+++ b/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
diff --git a/spec/models/twitter_auth/basic_user_spec.rb b/spec/models/twitter_auth/basic_user_spec.rb
index 8f6591b..365c78a 100644
--- a/spec/models/twitter_auth/basic_user_spec.rb
+++ b/spec/models/twitter_auth/basic_user_spec.rb
@@ -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
diff --git a/spec/models/twitter_auth/oauth_user_spec.rb b/spec/models/twitter_auth/oauth_user_spec.rb
index 0dd3a9e..efe4f3c 100644
--- a/spec/models/twitter_auth/oauth_user_spec.rb
+++ b/spec/models/twitter_auth/oauth_user_spec.rb
@@ -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
diff --git a/spec/twitter_auth/dispatcher/basic_spec.rb b/spec/twitter_auth/dispatcher/basic_spec.rb
new file mode 100644
index 0000000..19b5c84
--- /dev/null
+++ b/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 => 'true')
+ 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 == "true"
+ 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
diff --git a/spec/twitter_auth/dispatcher/oauth_spec.rb b/spec/twitter_auth/dispatcher/oauth_spec.rb
new file mode 100644
index 0000000..f837732
--- /dev/null
+++ b/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 => "true")
+ 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 == 'true'
+ 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
diff --git a/spec/twitter_auth_spec.rb b/spec/twitter_auth_spec.rb
index 4109994..a333710 100644
--- a/spec/twitter_auth_spec.rb
+++ b/spec/twitter_auth_spec.rb
@@ -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