twitterdispatch 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.rdoc +37 -0
- data/VERSION.yml +4 -0
- data/lib/twitter_dispatch/dispatcher.rb +125 -0
- data/lib/twitter_dispatch/proxy/basic.rb +46 -0
- data/lib/twitter_dispatch/proxy/none.rb +7 -0
- data/lib/twitter_dispatch/proxy/oauth.rb +23 -0
- data/lib/twitter_dispatch/proxy/shared.rb +36 -0
- data/lib/twitterdispatch.rb +18 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/twitter_dispatch/proxy/basic_spec.rb +79 -0
- data/spec/twitter_dispatch/proxy/oauth_spec.rb +55 -0
- data/spec/twitter_dispatch/proxy/shared_spec.rb +26 -0
- data/spec/twitter_dispatch_spec.rb +47 -0
- metadata +73 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Michael Bleigh
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
= TwitterDispatch
|
2
|
+
|
3
|
+
TwitterDispatch is an unassuming API wrapper for Twitter based on the dispatcher from TwitterAuth. Rather than create a complex object mapping system around the simple REST API Twitter provides, TwitterDispatch simply gives you the tools to make calls directly to the API URLs and parse the results (or not).
|
4
|
+
|
5
|
+
TwitterDispatch supports both OAuth and HTTP Basic authentication strategies.
|
6
|
+
|
7
|
+
== Usage
|
8
|
+
|
9
|
+
To use TwitterDispatch you will need different things depending on the strategy you are using:
|
10
|
+
|
11
|
+
* <b>OAuth</b> - You will need to have already registered your application with Twitter (have a consumer key and secret) as well as performed the entire OAuth authentication process (have an access key and secret). If you don't know much about OAuth and are building a Rails application, I would suggest using TwitterAuth instead.
|
12
|
+
* <b>HTTP Basic</b> - You will need to have the screen name and password for the authenticating user.
|
13
|
+
|
14
|
+
Usage of TwitterDispatch is straightforward. Here are some basic examples to get you going.
|
15
|
+
|
16
|
+
# OAuth Example
|
17
|
+
dispatcher = TwitterDispatch.new(:oauth, 'myconsumerkey', 'myconsumersecret', 'myaccesskey', 'myaccesssecret')
|
18
|
+
dispatcher.get('/account/verify_credentials') # => {'screen_name' => ...}
|
19
|
+
dispatcher.post('/statuses/update', :status => 'Update my status.') # => {'text' => 'Update my status.' ... }
|
20
|
+
|
21
|
+
# HTTP Basic Example
|
22
|
+
dispatcher = TwitterDispatch.new(:basic, 'screenname', 'password')
|
23
|
+
dispatcher.get('/statuses/friends_timeline') # => [{'text' => ...}]
|
24
|
+
|
25
|
+
# No Auth Example
|
26
|
+
dispatcher = TwitterDispatch.new
|
27
|
+
dispatcher.get('/statuses/public_timeline') # => [{'text' => ...}]
|
28
|
+
|
29
|
+
# Search Example
|
30
|
+
dispatcher = TwitterDispatch.new
|
31
|
+
dispatcher.search('query text') # => [{'text' => ...}]
|
32
|
+
|
33
|
+
TwitterDispatch is not meant to be complex or assuming, it literally just does the bare minimum to provide you with a simple and direct access to the Twitter API in Ruby.
|
34
|
+
|
35
|
+
== Copyright
|
36
|
+
|
37
|
+
Copyright (c) 2009 Michael Bleigh and Intridea, Inc. See LICENSE for details.
|
data/VERSION.yml
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
module TwitterDispatch
|
2
|
+
class Dispatcher
|
3
|
+
# Override this method to provide new defaults.
|
4
|
+
# The defaults are as follows:
|
5
|
+
#
|
6
|
+
# * <tt>:base_url</tt> - http://twitter.com
|
7
|
+
#
|
8
|
+
def self.default_options
|
9
|
+
{
|
10
|
+
:base_url => 'http://twitter.com',
|
11
|
+
:api_timeout => 10
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
# Initialize a dispatcher using the specified strategy.
|
16
|
+
#
|
17
|
+
# *Strategies*
|
18
|
+
#
|
19
|
+
# * <tt>:oauth</tt> - You will need to provide four arguments before any options: the consumer key, the consumer secret, the access key, and the access secret.
|
20
|
+
# * <tt>:basic</tt> - You will need to provide two arguments before any options: the screen name# and the password of the authenticating user.
|
21
|
+
# * <tt>:none</tt> - You will not need to provide any additional arguments but will only be able to access resources that do not require authentication (such as <tt>statuses/public_timeline</tt>).
|
22
|
+
#
|
23
|
+
# *Options*
|
24
|
+
#
|
25
|
+
# * <tt>:base_url</tt> - The base URL used to make calls. This way the dispatcher can be used on Twitter-compatible APIs, not just the Twitter API.
|
26
|
+
#
|
27
|
+
def initialize(strategy = :none, *args)
|
28
|
+
args << {} unless args.last.is_a?(Hash)
|
29
|
+
@strategy = strategy
|
30
|
+
case @strategy
|
31
|
+
when :oauth
|
32
|
+
raise ArgumentError, "The :oauth strategy requires four arguments - consumer_key, consumer_secret, access_key and access_secret." unless args.size == 5
|
33
|
+
@consumer_key, @consumer_secret, @access_key, @access_secret, @options = *args
|
34
|
+
when :basic
|
35
|
+
raise ArgumentError, "The :basic strategy requires two arguments - screen_name and password." unless args.size == 3
|
36
|
+
@screen_name, @password, @options = *args
|
37
|
+
when :none
|
38
|
+
raise ArgumentError, "The :none strategy does not take any mandatory arguments, only options." unless args.size == 1
|
39
|
+
@options = *args
|
40
|
+
else
|
41
|
+
raise ArgumentError, "Valid strategies are :oauth, :basic and :none."
|
42
|
+
end
|
43
|
+
|
44
|
+
@options = TwitterDispatch::Dispatcher.default_options.merge(@options)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Generates an OAuth consumer for this dispatcher given the
|
48
|
+
# base_url and provided access key and token.
|
49
|
+
def consumer
|
50
|
+
OAuth::Consumer.new(@consumer_key, @consumer_secret, :site => @options[:base_url])
|
51
|
+
end
|
52
|
+
|
53
|
+
#:nodoc:
|
54
|
+
def path_prefix
|
55
|
+
URI.parse(base_url).path
|
56
|
+
end
|
57
|
+
|
58
|
+
def net
|
59
|
+
uri = URI.parse(base_url)
|
60
|
+
net = Net::HTTP.new(uri.host, uri.port)
|
61
|
+
net.use_ssl = uri.scheme == 'https'
|
62
|
+
net.read_timeout = @options[:api_timeout]
|
63
|
+
net
|
64
|
+
end
|
65
|
+
|
66
|
+
attr_reader :access_token, :access_secret, :strategy, :screen_name, :password
|
67
|
+
|
68
|
+
def base_url
|
69
|
+
@options[:base_url]
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns true if a strategy is set.
|
73
|
+
def strategy?
|
74
|
+
strategy != :none
|
75
|
+
end
|
76
|
+
|
77
|
+
# True if the current strategy is OAuth.
|
78
|
+
def oauth?
|
79
|
+
strategy == :oauth
|
80
|
+
end
|
81
|
+
|
82
|
+
# True if the current strategy is HTTP Basic.
|
83
|
+
def basic?
|
84
|
+
strategy == :basic
|
85
|
+
end
|
86
|
+
|
87
|
+
def proxy
|
88
|
+
case strategy
|
89
|
+
when :oauth
|
90
|
+
@proxy ||= TwitterDispatch::Proxy::OAuth.new(self)
|
91
|
+
when :basic
|
92
|
+
@proxy ||= TwitterDispatch::Proxy::Basic.new(self)
|
93
|
+
when :none
|
94
|
+
@proxy ||= TwitterDispatch::Proxy::None.new(self)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Make a request through the dispatcher. Method
|
99
|
+
# can be any of the standard HTTP verbs, path
|
100
|
+
# is the API path such as <tt>/account/verify_credentials.json</tt>
|
101
|
+
def request(http_method, path, *args)
|
102
|
+
proxy.request(http_method, path, *args)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Perform a GET request through the dispatcher.
|
106
|
+
def get(*args)
|
107
|
+
proxy.get(*args)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Perform a POST request through the dispatcher.
|
111
|
+
def post(*args)
|
112
|
+
proxy.post(*args)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Perform a PUT request through the dispatcher.
|
116
|
+
def put(*args)
|
117
|
+
proxy.put(*args)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Perform a DELETE request through the dispatcher.
|
121
|
+
def delete(*args)
|
122
|
+
proxy.delete(*args)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module TwitterDispatch
|
4
|
+
module Proxy
|
5
|
+
class Basic
|
6
|
+
include TwitterDispatch::Proxy::Shared
|
7
|
+
|
8
|
+
attr_accessor :dispatcher
|
9
|
+
|
10
|
+
def initialize(dispatcher)
|
11
|
+
self.dispatcher = dispatcher
|
12
|
+
end
|
13
|
+
|
14
|
+
def request(http_method, path, body=nil, *arguments)
|
15
|
+
path = dispatcher.path_prefix + path
|
16
|
+
path = append_extension_to(path)
|
17
|
+
|
18
|
+
response = dispatcher.net.start{ |http|
|
19
|
+
req = eval("Net::HTTP::#{http_method.to_s.capitalize}").new(path, *arguments)
|
20
|
+
req.basic_auth dispatcher.screen_name, dispatcher.password if dispatcher.basic?
|
21
|
+
req.set_form_data(body) unless body.nil?
|
22
|
+
http.request(req)
|
23
|
+
}
|
24
|
+
|
25
|
+
handle_response(response)
|
26
|
+
end
|
27
|
+
|
28
|
+
def get(path, *arguments)
|
29
|
+
request(:get, path, *arguments)
|
30
|
+
end
|
31
|
+
|
32
|
+
def post(path, body='', *arguments)
|
33
|
+
request(:post, path, body, *arguments)
|
34
|
+
end
|
35
|
+
|
36
|
+
def put(path, body='', *arguments)
|
37
|
+
request(:put, path, body, *arguments)
|
38
|
+
end
|
39
|
+
|
40
|
+
def delete(path, *arguments)
|
41
|
+
request(:delete, path, *arguments)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module TwitterDispatch
|
2
|
+
module Proxy
|
3
|
+
class OAuth < OAuth::AccessToken
|
4
|
+
include TwitterDispatch::Proxy::Shared
|
5
|
+
|
6
|
+
attr_accessor :dispatcher
|
7
|
+
|
8
|
+
def initialize(dispatcher)
|
9
|
+
self.dispatcher = dispatcher
|
10
|
+
super(dispatcher.consumer, dispatcher.access_token, dispatcher.access_secret)
|
11
|
+
end
|
12
|
+
|
13
|
+
def request(http_method, path, *arguments)
|
14
|
+
path = dispatcher.path_prefix + path
|
15
|
+
path = append_extension_to(path)
|
16
|
+
|
17
|
+
response = super
|
18
|
+
|
19
|
+
handle_response(response)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module TwitterDispatch
|
2
|
+
module Proxy
|
3
|
+
module Shared
|
4
|
+
def append_extension_to(path)
|
5
|
+
path, query_string = *(path.split("?"))
|
6
|
+
path << '.json' unless path.match(/\.(:?xml|json)\z/i)
|
7
|
+
"#{path}#{"?#{query_string}" if query_string}"
|
8
|
+
end
|
9
|
+
|
10
|
+
def handle_response(response)
|
11
|
+
case response
|
12
|
+
when Net::HTTPOK
|
13
|
+
begin
|
14
|
+
JSON.parse(response.body)
|
15
|
+
rescue JSON::ParserError
|
16
|
+
response.body
|
17
|
+
end
|
18
|
+
when Net::HTTPUnauthorized
|
19
|
+
raise TwitterDispatch::Unauthorized, 'API Authorization failed. Check user credentials and OAuth consumer permission levels.'
|
20
|
+
else
|
21
|
+
message = begin
|
22
|
+
JSON.parse(response.body)['error']
|
23
|
+
rescue JSON::ParserError
|
24
|
+
if match = response.body.match(/<error>(.*)<\/error>/)
|
25
|
+
match[1]
|
26
|
+
else
|
27
|
+
"An unknown #{response.code} error occurred processing your API request."
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
raise TwitterDispatch::HTTPError, message
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'oauth'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module TwitterDispatch
|
6
|
+
def self.new(*args)
|
7
|
+
TwitterDispatch::Dispatcher.new(*args)
|
8
|
+
end
|
9
|
+
|
10
|
+
class HTTPError < StandardError; end
|
11
|
+
class Unauthorized < HTTPError; end
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'twitter_dispatch/dispatcher'
|
15
|
+
require 'twitter_dispatch/proxy/shared'
|
16
|
+
require 'twitter_dispatch/proxy/oauth'
|
17
|
+
require 'twitter_dispatch/proxy/basic'
|
18
|
+
require 'twitter_dispatch/proxy/none'
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
require 'fakeweb'
|
4
|
+
|
5
|
+
FakeWeb.allow_net_connect = false
|
6
|
+
|
7
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
8
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
9
|
+
require 'twitterdispatch'
|
10
|
+
|
11
|
+
Spec::Runner.configure do |config|
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe TwitterDispatch::Proxy::Basic do
|
4
|
+
before do
|
5
|
+
@dispatcher = TwitterDispatch.new(:basic, 'abc', 'def')
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should store the dispatcher in an attr_accessor' do
|
9
|
+
TwitterDispatch::Proxy::Basic.new(@dispatcher).dispatcher.should == @dispatcher
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#request' do
|
13
|
+
before do
|
14
|
+
@proxy = TwitterDispatch::Proxy::Basic.new(@dispatcher)
|
15
|
+
FakeWeb.register_uri('http://twitter.com:80/fake.json', :string => {'fake' => true}.to_json)
|
16
|
+
FakeWeb.register_uri('http://twitter.com:80/fake.xml', :string => '<fake>true</fake>')
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should automatically parse JSON if valid' do
|
20
|
+
@proxy.request(:get, '/fake.json').should == {'fake' => true}
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should return XML as a string' do
|
24
|
+
@proxy.request(:get, '/fake.xml').should == "<fake>true</fake>"
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should append .json to the path if no extension is provided' do
|
28
|
+
@proxy.request(:get, '/fake.json').should == @proxy.request(:get, '/fake')
|
29
|
+
end
|
30
|
+
|
31
|
+
%w(get post put delete).each do |method|
|
32
|
+
it "should build a #{method} class based on a :#{method} http_method" do
|
33
|
+
@req = eval("Net::HTTP::#{method.capitalize}").new('/fake.json')
|
34
|
+
eval("Net::HTTP::#{method.capitalize}").should_receive(:new).and_return(@req)
|
35
|
+
@proxy.request(method.to_sym, '/fake')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should start the HTTP session' do
|
40
|
+
@net = @dispatcher.net
|
41
|
+
@dispatcher.stub!(:net).and_return(@net)
|
42
|
+
@net.should_receive(:start)
|
43
|
+
lambda{@proxy.request(:get, '/fake')}.should raise_error(NoMethodError)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should raise a TwitterDispatch::HTTPError if response code isn't 200" do
|
47
|
+
FakeWeb.register_uri('http://twitter.com:80/bad_response.json', :string => {'error' => 'bad response'}.to_json, :status => ['401', 'Unauthorized'])
|
48
|
+
lambda{@proxy.request(:get, '/bad_response')}.should raise_error(TwitterDispatch::HTTPError)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should set the error message to the JSON message' do
|
52
|
+
FakeWeb.register_uri('http://twitter.com:80/bad_response.json', :string => {'error' => 'bad response'}.to_json, :status => ['403', 'Forbidden'])
|
53
|
+
lambda{@proxy.request(:get, '/bad_response')}.should raise_error(TwitterDispatch::HTTPError, 'bad response')
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should raise a TwitterDispatch::Proxy::Unauthorized on 401' do
|
57
|
+
FakeWeb.register_uri('http://twitter.com:80/unauthenticated_response.xml', :string => "<hash>\n<request>/unauthenticated_response.xml</request>\n<error>bad response</error>\n</hash>", :status => ['401', 'Unauthorized'])
|
58
|
+
lambda{@proxy.request(:get, '/unauthenticated_response.xml')}.should raise_error(TwitterDispatch::Unauthorized)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should set the error message to the XML message' do
|
62
|
+
FakeWeb.register_uri('http://twitter.com:80/bad_response.xml', :string => "<hash>\n<request>/bad_response.xml</request>\n<error>bad response</error>\n</hash>", :status => ['403', 'Forbidden'])
|
63
|
+
lambda{@proxy.request(:get, '/bad_response')}.should raise_error(TwitterDispatch::HTTPError, 'bad response')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
%w(get post delete put).each do |method|
|
68
|
+
it "should have a ##{method} method that calls request(:#{method})" do
|
69
|
+
dispatcher = TwitterDispatch::Proxy::Basic.new(@user)
|
70
|
+
if %w(get delete).include?(method)
|
71
|
+
dispatcher.should_receive(:request).with(method.to_sym, '/fake.json')
|
72
|
+
else
|
73
|
+
dispatcher.should_receive(:request).with(method.to_sym, '/fake.json', '')
|
74
|
+
end
|
75
|
+
dispatcher.send(method, '/fake.json')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe TwitterDispatch::Proxy::OAuth do
|
4
|
+
describe '#request' do
|
5
|
+
before do
|
6
|
+
@dispatcher = TwitterDispatch.new(:oauth, 'abc', 'def', 'hgi', 'jkl')
|
7
|
+
@proxy = TwitterDispatch::Proxy::OAuth.new(@dispatcher)
|
8
|
+
FakeWeb.register_uri(:get, 'http://twitter.com:80/fake.json', :string => {'fake' => true}.to_json)
|
9
|
+
FakeWeb.register_uri(:get, 'http://twitter.com:80/fake.xml', :string => "<fake>true</fake>")
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should automatically parse json' do
|
13
|
+
result = @proxy.request(:get, '/fake.json')
|
14
|
+
result.should be_a(Hash)
|
15
|
+
result['fake'].should be_true
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should return xml as a string' do
|
19
|
+
@proxy.request(:get, '/fake.xml').should == '<fake>true</fake>'
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should append .json to the path if no extension is provided' do
|
23
|
+
@proxy.request(:get, '/fake').should == @proxy.request(:get, '/fake.json')
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should raise a TwitterDispatch::HTTPError if response code isn't 200" do
|
27
|
+
FakeWeb.register_uri('http://twitter.com:80/bad_response.json', :string => {'error' => 'bad response'}.to_json, :status => ['401', 'Unauthorized'])
|
28
|
+
lambda{@proxy.request(:get, '/bad_response')}.should raise_error(TwitterDispatch::HTTPError)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should set the error message to the JSON message' do
|
32
|
+
FakeWeb.register_uri('http://twitter.com:80/bad_response.json', :string => {'error' => 'bad response'}.to_json, :status => ['403', 'Forbidden'])
|
33
|
+
lambda{@proxy.request(:get, '/bad_response')}.should raise_error(TwitterDispatch::HTTPError, 'bad response')
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should set the error message to the XML message' do
|
37
|
+
FakeWeb.register_uri('http://twitter.com:80/bad_response.xml', :string => "<hash>\n<request>/bad_response.xml</request>\n<error>bad response</error>\n</hash>", :status => ['403', 'Forbidden'])
|
38
|
+
lambda{@proxy.request(:get, '/bad_response.xml')}.should raise_error(TwitterDispatch::HTTPError, 'bad response')
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should still error correctly on a totally messed up response' do
|
42
|
+
FakeWeb.register_uri('http://twitter.com:80/bad_response.xml', :string => "aosidnaoisdnasd", :status => ['403', 'Forbidden'])
|
43
|
+
lambda{@proxy.request(:get, '/bad_response.xml')}.should raise_error(TwitterDispatch::HTTPError, 'An unknown 403 error occurred processing your API request.')
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should raise a TwitterAuth::Dispatcher::Unauthorized on 401' do
|
47
|
+
FakeWeb.register_uri('http://twitter.com:80/unauthenticated_response.xml', :string => "<hash>\n<request>/unauthenticated_response.xml</request>\n<error>bad response</error>\n</hash>", :status => ['401', 'Unauthorized'])
|
48
|
+
lambda{@proxy.request(:get, '/unauthenticated_response.xml')}.should raise_error(TwitterDispatch::Unauthorized)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should work with verb methods' do
|
52
|
+
@proxy.get('/fake').should == @proxy.request(:get, '/fake')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe TwitterDispatch::Proxy::Shared do
|
4
|
+
include TwitterDispatch::Proxy::Shared
|
5
|
+
|
6
|
+
describe '#append_extension_to' do
|
7
|
+
it 'should leave extensions alone if they exist' do
|
8
|
+
append_extension_to('/fake.json').should == '/fake.json'
|
9
|
+
append_extension_to('/fake.xml').should == '/fake.xml'
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should append .json if no extension is provided' do
|
13
|
+
append_extension_to('/fake').should == '/fake.json'
|
14
|
+
append_extension_to('/verify/fake').should == '/verify/fake.json'
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should leave extensions alone even with query strings' do
|
18
|
+
append_extension_to('/fake.json?since_id=123').should == '/fake.json?since_id=123'
|
19
|
+
append_extension_to('/fake.xml?since_id=123').should == '/fake.xml?since_id=123'
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should add an extension even with query strings' do
|
23
|
+
append_extension_to('/fake?since_id=123').should == '/fake.json?since_id=123'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe TwitterDispatch do
|
4
|
+
describe '#new' do
|
5
|
+
it 'should raise an ArgumentError for non-existent strategies' do
|
6
|
+
lambda{TwitterDispatch.new(:bollocks)}.should raise_error(ArgumentError)
|
7
|
+
end
|
8
|
+
|
9
|
+
{ :oauth => 4,
|
10
|
+
:basic => 2,
|
11
|
+
:none => 0 }.each_pair do |strategy, count|
|
12
|
+
it "should raise an ArgumentError with the wrong number of args for #{strategy.inspect}" do
|
13
|
+
(0...count).each do |arg_count|
|
14
|
+
myargs = ['abc'] * arg_count
|
15
|
+
lambda{TwitterDispatch.new(strategy, *myargs)}.should raise_error(ArgumentError)
|
16
|
+
myargs << {:base_url => 'http://example.com'}
|
17
|
+
lambda{TwitterDispatch.new(strategy, *myargs)}.should raise_error(ArgumentError)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should not raise an ArgumentError with the correct number of arguments for #{strategy.inspect}" do
|
22
|
+
myargs = ['abc'] * count
|
23
|
+
lambda{TwitterDispatch.new(strategy, *myargs)}.should_not raise_error(ArgumentError)
|
24
|
+
myargs << {:base_url => 'http://example.com'}
|
25
|
+
lambda{TwitterDispatch.new(strategy, *myargs)}.should_not raise_error(ArgumentError)
|
26
|
+
end
|
27
|
+
|
28
|
+
unless strategy == :none
|
29
|
+
it "should set the strategy appropriately" do
|
30
|
+
myargs = ['abc'] * count
|
31
|
+
@dispatch = TwitterDispatch.new(strategy, *myargs)
|
32
|
+
@dispatch.strategy.should == strategy
|
33
|
+
@dispatch.should be_strategy
|
34
|
+
@dispatch.send("#{strategy}?").should be_true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it '#strategy? should be false if the :none strategy is used' do
|
40
|
+
TwitterDispatch.new(:none).should_not be_strategy
|
41
|
+
end
|
42
|
+
|
43
|
+
it '#strategy should default to none' do
|
44
|
+
TwitterDispatch.new.strategy.should == :none
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: twitterdispatch
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Bleigh
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-04-07 00:00:00 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: michael@intridea.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
- LICENSE
|
25
|
+
files:
|
26
|
+
- README.rdoc
|
27
|
+
- VERSION.yml
|
28
|
+
- lib/twitter_dispatch
|
29
|
+
- lib/twitter_dispatch/dispatcher.rb
|
30
|
+
- lib/twitter_dispatch/proxy
|
31
|
+
- lib/twitter_dispatch/proxy/basic.rb
|
32
|
+
- lib/twitter_dispatch/proxy/none.rb
|
33
|
+
- lib/twitter_dispatch/proxy/oauth.rb
|
34
|
+
- lib/twitter_dispatch/proxy/shared.rb
|
35
|
+
- lib/twitterdispatch.rb
|
36
|
+
- spec/spec.opts
|
37
|
+
- spec/spec_helper.rb
|
38
|
+
- spec/twitter_dispatch
|
39
|
+
- spec/twitter_dispatch/proxy
|
40
|
+
- spec/twitter_dispatch/proxy/basic_spec.rb
|
41
|
+
- spec/twitter_dispatch/proxy/oauth_spec.rb
|
42
|
+
- spec/twitter_dispatch/proxy/shared_spec.rb
|
43
|
+
- spec/twitter_dispatch_spec.rb
|
44
|
+
- LICENSE
|
45
|
+
has_rdoc: true
|
46
|
+
homepage: http://github.com/mbleigh/twitterdispatch
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options:
|
49
|
+
- --inline-source
|
50
|
+
- --charset=UTF-8
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project: twitterdispatch
|
68
|
+
rubygems_version: 1.3.1
|
69
|
+
signing_key:
|
70
|
+
specification_version: 2
|
71
|
+
summary: A simple Twitter API wrapper that gets out of your way and lets you access things directly.
|
72
|
+
test_files: []
|
73
|
+
|