twitterdispatch 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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.
@@ -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.
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 0
4
+ :patch: 2
@@ -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,7 @@
1
+ module TwitterDispatch
2
+ module Proxy
3
+ class None < TwitterDispatch::Proxy::Basic
4
+
5
+ end
6
+ end
7
+ end
@@ -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'
@@ -0,0 +1 @@
1
+ --colour
@@ -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
+