michaeltaras-twitter 0.6.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. data/History +206 -0
  2. data/License +20 -0
  3. data/Notes +33 -0
  4. data/README.rdoc +19 -0
  5. data/Rakefile +103 -0
  6. data/VERSION.yml +4 -0
  7. data/examples/connect.rb +30 -0
  8. data/examples/friendship_existance.rb +13 -0
  9. data/examples/helpers/config_store.rb +38 -0
  10. data/examples/httpauth.rb +11 -0
  11. data/examples/ids.rb +13 -0
  12. data/examples/search.rb +15 -0
  13. data/examples/timeline.rb +19 -0
  14. data/examples/unauthorized.rb +16 -0
  15. data/examples/update.rb +11 -0
  16. data/examples/user.rb +5 -0
  17. data/lib/twitter.rb +63 -0
  18. data/lib/twitter/base.rb +165 -0
  19. data/lib/twitter/httpauth.rb +27 -0
  20. data/lib/twitter/oauth.rb +41 -0
  21. data/lib/twitter/request.rb +106 -0
  22. data/lib/twitter/search.rb +106 -0
  23. data/lib/twitter/trends.rb +29 -0
  24. data/test/fixtures/enhance_calm.json +1 -0
  25. data/test/fixtures/firehose.json +1 -0
  26. data/test/fixtures/follower_ids.json +1 -0
  27. data/test/fixtures/friend_ids.json +1 -0
  28. data/test/fixtures/friends_timeline.json +1 -0
  29. data/test/fixtures/rate_limit_exceeded.json +1 -0
  30. data/test/fixtures/replies.json +1 -0
  31. data/test/fixtures/search.json +1 -0
  32. data/test/fixtures/search_from_jnunemaker.json +1 -0
  33. data/test/fixtures/status.json +1 -0
  34. data/test/fixtures/status_show.json +1 -0
  35. data/test/fixtures/trends_current.json +1 -0
  36. data/test/fixtures/trends_current_exclude.json +1 -0
  37. data/test/fixtures/trends_daily.json +1 -0
  38. data/test/fixtures/trends_daily_date.json +1 -0
  39. data/test/fixtures/trends_daily_exclude.json +1 -0
  40. data/test/fixtures/trends_weekly.json +1 -0
  41. data/test/fixtures/trends_weekly_date.json +1 -0
  42. data/test/fixtures/trends_weekly_exclude.json +1 -0
  43. data/test/fixtures/user.json +1 -0
  44. data/test/fixtures/user_timeline.json +1 -0
  45. data/test/test_helper.rb +36 -0
  46. data/test/twitter/base_test.rb +95 -0
  47. data/test/twitter/httpauth_test.rb +76 -0
  48. data/test/twitter/oauth_test.rb +81 -0
  49. data/test/twitter/request_test.rb +224 -0
  50. data/test/twitter/search_test.rb +144 -0
  51. data/test/twitter/trends_test.rb +95 -0
  52. data/test/twitter_test.rb +38 -0
  53. metadata +200 -0
@@ -0,0 +1,224 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class RequestTest < Test::Unit::TestCase
4
+ context "new get request" do
5
+ setup do
6
+ @client = mock('twitter client')
7
+ @request = Twitter::Request.new(@client, :get, '/statuses/user_timeline.json', {:query => {:since_id => 1234}})
8
+ end
9
+
10
+ should "have client" do
11
+ @request.client.should == @client
12
+ end
13
+
14
+ should "have method" do
15
+ @request.method.should == :get
16
+ end
17
+
18
+ should "have path" do
19
+ @request.path.should == '/statuses/user_timeline.json'
20
+ end
21
+
22
+ should "have options" do
23
+ @request.options[:query].should == {:since_id => 1234}
24
+ end
25
+
26
+ should "have uri" do
27
+ @request.uri.should == '/statuses/user_timeline.json?since_id=1234'
28
+ end
29
+
30
+ context "performing request for collection" do
31
+ setup do
32
+ response = mock('response') do
33
+ stubs(:body).returns(fixture_file('user_timeline.json'))
34
+ stubs(:code).returns('200')
35
+ end
36
+
37
+ @client.expects(:get).returns(response)
38
+ @object = @request.perform
39
+ end
40
+
41
+ should "return array of mashes" do
42
+ @object.size.should == 20
43
+ @object.each { |obj| obj.class.should be(Mash) }
44
+ @object.first.text.should == 'Colder out today than expected. Headed to the Beanery for some morning wakeup drink. Latte or coffee...hmmm...'
45
+ end
46
+ end
47
+
48
+ context "performing a request for a single object" do
49
+ setup do
50
+ response = mock('response') do
51
+ stubs(:body).returns(fixture_file('status.json'))
52
+ stubs(:code).returns('200')
53
+ end
54
+
55
+ @client.expects(:get).returns(response)
56
+ @object = @request.perform
57
+ end
58
+
59
+ should "return a single mash" do
60
+ @object.class.should be(Mash)
61
+ @object.text.should == 'Rob Dyrdek is the funniest man alive. That is all.'
62
+ end
63
+ end
64
+
65
+ context "with no query string" do
66
+ should "not have any query string" do
67
+ request = Twitter::Request.new(@client, :get, '/statuses/user_timeline.json')
68
+ request.uri.should == '/statuses/user_timeline.json'
69
+ end
70
+ end
71
+
72
+ context "with blank query string" do
73
+ should "not have any query string" do
74
+ request = Twitter::Request.new(@client, :get, '/statuses/user_timeline.json', :query => {})
75
+ request.uri.should == '/statuses/user_timeline.json'
76
+ end
77
+ end
78
+
79
+ should "have get shortcut to initialize and perform all in one" do
80
+ Twitter::Request.any_instance.expects(:perform).returns(nil)
81
+ Twitter::Request.get(@client, '/foo')
82
+ end
83
+
84
+ should "allow setting query string and headers" do
85
+ response = mock('response') do
86
+ stubs(:body).returns('')
87
+ stubs(:code).returns('200')
88
+ end
89
+
90
+ @client.expects(:get).with('/statuses/friends_timeline.json?since_id=1234', {'Foo' => 'Bar'}).returns(response)
91
+ Twitter::Request.get(@client, '/statuses/friends_timeline.json?since_id=1234', :headers => {'Foo' => 'Bar'})
92
+ end
93
+ end
94
+
95
+ context "new post request" do
96
+ setup do
97
+ @client = mock('twitter client')
98
+ @request = Twitter::Request.new(@client, :post, '/statuses/update.json', {:body => {:status => 'Woohoo!'}})
99
+ end
100
+
101
+ should "allow setting body and headers" do
102
+ response = mock('response') do
103
+ stubs(:body).returns('')
104
+ stubs(:code).returns('200')
105
+ end
106
+
107
+ @client.expects(:post).with('/statuses/update.json', {:status => 'Woohoo!'}, {'Foo' => 'Bar'}).returns(response)
108
+ Twitter::Request.post(@client, '/statuses/update.json', :body => {:status => 'Woohoo!'}, :headers => {'Foo' => 'Bar'})
109
+ end
110
+
111
+ context "performing request" do
112
+ setup do
113
+ response = mock('response') do
114
+ stubs(:body).returns(fixture_file('status.json'))
115
+ stubs(:code).returns('200')
116
+ end
117
+
118
+ @client.expects(:post).returns(response)
119
+ @object = @request.perform
120
+ end
121
+
122
+ should "return a mash of the object" do
123
+ @object.text.should == 'Rob Dyrdek is the funniest man alive. That is all.'
124
+ end
125
+ end
126
+
127
+ should "have post shortcut to initialize and perform all in one" do
128
+ Twitter::Request.any_instance.expects(:perform).returns(nil)
129
+ Twitter::Request.post(@client, '/foo')
130
+ end
131
+ end
132
+
133
+ context "error raising" do
134
+ setup do
135
+ oauth = Twitter::OAuth.new('token', 'secret')
136
+ oauth.authorize_from_access('atoken', 'asecret')
137
+ @client = Twitter::Base.new(oauth)
138
+ end
139
+
140
+ should "not raise error for 200" do
141
+ stub_get('http://twitter.com:80/foo', '', ['200'])
142
+ lambda {
143
+ Twitter::Request.get(@client, '/foo')
144
+ }.should_not raise_error
145
+ end
146
+
147
+ should "not raise error for 304" do
148
+ stub_get('http://twitter.com:80/foo', '', ['304'])
149
+ lambda {
150
+ Twitter::Request.get(@client, '/foo')
151
+ }.should_not raise_error
152
+ end
153
+
154
+ should "raise RateLimitExceeded for 400" do
155
+ stub_get('http://twitter.com:80/foo', 'rate_limit_exceeded.json', ['400'])
156
+ lambda {
157
+ Twitter::Request.get(@client, '/foo')
158
+ }.should raise_error(Twitter::RateLimitExceeded)
159
+ end
160
+
161
+ should "raise RateLimitExceeded for 'Enhance your calm' responses" do
162
+ stub_get('http://twitter.com:80/foo', 'enhance_calm.json', ['200'])
163
+ lambda {
164
+ Twitter::Request.get(@client, '/foo')
165
+ }.should raise_error(Twitter::RateLimitExceeded)
166
+ end
167
+
168
+ should "raise Unauthorized for 401" do
169
+ stub_get('http://twitter.com:80/foo', '', ['401'])
170
+ lambda {
171
+ Twitter::Request.get(@client, '/foo')
172
+ }.should raise_error(Twitter::Unauthorized)
173
+ end
174
+
175
+ should "raise General for 403" do
176
+ stub_get('http://twitter.com:80/foo', '', ['403'])
177
+ lambda {
178
+ Twitter::Request.get(@client, '/foo')
179
+ }.should raise_error(Twitter::General)
180
+ end
181
+
182
+ should "raise NotFound for 404" do
183
+ stub_get('http://twitter.com:80/foo', '', ['404'])
184
+ lambda {
185
+ Twitter::Request.get(@client, '/foo')
186
+ }.should raise_error(Twitter::NotFound)
187
+ end
188
+
189
+ should "raise InformTwitter for 500" do
190
+ stub_get('http://twitter.com:80/foo', '', ['500'])
191
+ lambda {
192
+ Twitter::Request.get(@client, '/foo')
193
+ }.should raise_error(Twitter::InformTwitter)
194
+ end
195
+
196
+ should "raise Unavailable for 502" do
197
+ stub_get('http://twitter.com:80/foo', '', ['502'])
198
+ lambda {
199
+ Twitter::Request.get(@client, '/foo')
200
+ }.should raise_error(Twitter::Unavailable)
201
+ end
202
+
203
+ should "raise Unavailable for 503" do
204
+ stub_get('http://twitter.com:80/foo', '', ['503'])
205
+ lambda {
206
+ Twitter::Request.get(@client, '/foo')
207
+ }.should raise_error(Twitter::Unavailable)
208
+ end
209
+ end
210
+
211
+ context "Making request with mash option set to false" do
212
+ setup do
213
+ oauth = Twitter::OAuth.new('token', 'secret')
214
+ oauth.authorize_from_access('atoken', 'asecret')
215
+ @client = Twitter::Base.new(oauth)
216
+ end
217
+
218
+ should "not attempt to create mash of return object" do
219
+ stub_get('http://twitter.com:80/foo', 'friend_ids.json')
220
+ object = Twitter::Request.get(@client, '/foo', :mash => false)
221
+ object.class.should_not be(Mash)
222
+ end
223
+ end
224
+ end
@@ -0,0 +1,144 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class SearchTest < Test::Unit::TestCase
4
+ context "searching" do
5
+ setup do
6
+ @search = Twitter::Search.new
7
+ end
8
+
9
+ should "should be able to initialize with a search term" do
10
+ Twitter::Search.new('httparty').query[:q].should include('httparty')
11
+ end
12
+
13
+ should "should be able to specify from" do
14
+ @search.from('jnunemaker').query[:q].should include('from:jnunemaker')
15
+ end
16
+
17
+ should "should be able to specify to" do
18
+ @search.to('jnunemaker').query[:q].should include('to:jnunemaker')
19
+ end
20
+
21
+ should "should be able to specify referencing" do
22
+ @search.referencing('jnunemaker').query[:q].should include('@jnunemaker')
23
+ end
24
+
25
+ should "should alias references to referencing" do
26
+ @search.references('jnunemaker').query[:q].should include('@jnunemaker')
27
+ end
28
+
29
+ should "should alias ref to referencing" do
30
+ @search.ref('jnunemaker').query[:q].should include('@jnunemaker')
31
+ end
32
+
33
+ should "should be able to specify containing" do
34
+ @search.containing('milk').query[:q].should include('milk')
35
+ end
36
+
37
+ should "should alias contains to containing" do
38
+ @search.contains('milk').query[:q].should include('milk')
39
+ end
40
+
41
+ should "should be able to specify hashed" do
42
+ @search.hashed('twitter').query[:q].should include('#twitter')
43
+ end
44
+
45
+ should "should be able to specify the language" do
46
+ @search.lang('en')
47
+ @search.class.expects(:get).with('http://search.twitter.com/search.json', :query => {:lang => 'en', :q => ''}, :format => :json).returns({'foo' => 'bar'})
48
+ @search.fetch()
49
+ end
50
+
51
+ should "should be able to specify the number of results per page" do
52
+ @search.per_page(25)
53
+ @search.class.expects(:get).with('http://search.twitter.com/search.json', :query => {:rpp => 25, :q => ''}, :format => :json).returns({'foo' => 'bar'})
54
+ @search.fetch()
55
+ end
56
+
57
+ should "should be able to specify the page number" do
58
+ @search.page(20)
59
+ @search.class.expects(:get).with('http://search.twitter.com/search.json', :query => {:page => 20, :q => ''}, :format => :json).returns({'foo' => 'bar'})
60
+ @search.fetch()
61
+ end
62
+
63
+ should "should be able to specify only returning results greater than an id" do
64
+ @search.since(1234)
65
+ @search.class.expects(:get).with('http://search.twitter.com/search.json', :query => {:since_id => 1234, :q => ''}, :format => :json).returns({'foo' => 'bar'})
66
+ @search.fetch()
67
+ end
68
+
69
+ should "should be able to specify geo coordinates" do
70
+ @search.geocode('40.757929', '-73.985506', '25mi')
71
+ @search.class.expects(:get).with('http://search.twitter.com/search.json', :query => {:geocode => '40.757929,-73.985506,25mi', :q => ''}, :format => :json).returns({'foo' => 'bar'})
72
+ @search.fetch()
73
+ end
74
+
75
+ should "should be able to specify max id" do
76
+ @search.max(1234)
77
+ @search.class.expects(:get).with('http://search.twitter.com/search.json', :query => {:max_id => 1234, :q => ''}, :format => :json).returns({'foo' => 'bar'})
78
+ @search.fetch()
79
+ end
80
+
81
+ should "should be able to clear the filters set" do
82
+ @search.from('jnunemaker').to('oaknd1')
83
+ @search.clear.query.should == {:q => []}
84
+ end
85
+
86
+ should "should be able to chain methods together" do
87
+ @search.from('jnunemaker').to('oaknd1').referencing('orderedlist').containing('milk').hashed('twitter').lang('en').per_page(20).since(1234).geocode('40.757929', '-73.985506', '25mi')
88
+ @search.query[:q].should == ['from:jnunemaker', 'to:oaknd1', '@orderedlist', 'milk', '#twitter']
89
+ @search.query[:lang].should == 'en'
90
+ @search.query[:rpp].should == 20
91
+ @search.query[:since_id].should == 1234
92
+ @search.query[:geocode].should == '40.757929,-73.985506,25mi'
93
+ end
94
+
95
+ context "fetching" do
96
+ setup do
97
+ stub_get('http://search.twitter.com:80/search.json?q=%40jnunemaker', 'search.json')
98
+ @search = Twitter::Search.new('@jnunemaker')
99
+ @response = @search.fetch
100
+ end
101
+
102
+ should "should return results" do
103
+ @response.results.size.should == 15
104
+ end
105
+
106
+ should "should support dot notation" do
107
+ first = @response.results.first
108
+ first.text.should == %q(Someone asked about a tweet reader. Easy to do in ruby with @jnunemaker's twitter gem and the win32-sapi gem, if you are on windows.)
109
+ first.from_user.should == 'PatParslow'
110
+ end
111
+
112
+ should "cache fetched results so multiple fetches don't keep hitting api" do
113
+ Twitter::Search.expects(:get).never
114
+ @search.fetch
115
+ end
116
+
117
+ should "rehit api if fetch is called with true" do
118
+ Twitter::Search.expects(:get).once
119
+ @search.fetch(true)
120
+ end
121
+ end
122
+
123
+ context "iterating over results" do
124
+ setup do
125
+ stub_get('http://search.twitter.com:80/search.json?q=from%3Ajnunemaker', 'search_from_jnunemaker.json')
126
+ @search.from('jnunemaker')
127
+ end
128
+
129
+ should "work" do
130
+ @search.each { |result| result.should_not be(nil) }
131
+ end
132
+
133
+ should "work multiple times in a row" do
134
+ @search.each { |result| result.should_not be(nil) }
135
+ @search.each { |result| result.should_not be(nil) }
136
+ end
137
+ end
138
+
139
+ should "should be able to iterate over results" do
140
+ @search.respond_to?(:each).should be(true)
141
+ end
142
+ end
143
+
144
+ end
@@ -0,0 +1,95 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class TrendsTest < Test::Unit::TestCase
4
+ include Twitter
5
+
6
+ context "Getting current trends" do
7
+ should "work" do
8
+ stub_get 'http://search.twitter.com:80/trends/current.json', 'trends_current.json'
9
+ trends = Trends.current
10
+ trends.size.should == 10
11
+ trends[0].name.should == '#musicmonday'
12
+ trends[0].query.should == '#musicmonday'
13
+ trends[1].name.should == '#newdivide'
14
+ trends[1].query.should == '#newdivide'
15
+ end
16
+
17
+ should "be able to exclude hashtags" do
18
+ stub_get 'http://search.twitter.com:80/trends/current.json?exclude=hashtags', 'trends_current_exclude.json'
19
+ trends = Trends.current(:exclude => 'hashtags')
20
+ trends.size.should == 10
21
+ trends[0].name.should == 'New Divide'
22
+ trends[0].query.should == %Q(\"New Divide\")
23
+ trends[1].name.should == 'Star Trek'
24
+ trends[1].query.should == %Q(\"Star Trek\")
25
+ end
26
+ end
27
+
28
+ context "Getting daily trends" do
29
+ should "work" do
30
+ stub_get 'http://search.twitter.com:80/trends/daily.json?', 'trends_daily.json'
31
+ trends = Trends.daily
32
+ trends.size.should == 480
33
+ trends[0].name.should == '#3turnoffwords'
34
+ trends[0].query.should == '#3turnoffwords'
35
+ end
36
+
37
+ should "be able to exclude hastags" do
38
+ stub_get 'http://search.twitter.com:80/trends/daily.json?exclude=hashtags', 'trends_daily_exclude.json'
39
+ trends = Trends.daily(:exclude => 'hashtags')
40
+ trends.size.should == 480
41
+ trends[0].name.should == 'Star Trek'
42
+ trends[0].query.should == %Q(\"Star Trek\")
43
+ end
44
+
45
+ should "be able to get for specific date (with date string)" do
46
+ stub_get 'http://search.twitter.com:80/trends/daily.json?date=2009-05-01', 'trends_daily_date.json'
47
+ trends = Trends.daily(:date => '2009-05-01')
48
+ trends.size.should == 440
49
+ trends[0].name.should == 'Swine Flu'
50
+ trends[0].query.should == %Q(\"Swine Flu\")
51
+ end
52
+
53
+ should "be able to get for specific date (with date object)" do
54
+ stub_get 'http://search.twitter.com:80/trends/daily.json?date=2009-05-01', 'trends_daily_date.json'
55
+ trends = Trends.daily(:date => Date.new(2009, 5, 1))
56
+ trends.size.should == 440
57
+ trends[0].name.should == 'Swine Flu'
58
+ trends[0].query.should == %Q(\"Swine Flu\")
59
+ end
60
+ end
61
+
62
+ context "Getting weekly trends" do
63
+ should "work" do
64
+ stub_get 'http://search.twitter.com:80/trends/weekly.json?', 'trends_weekly.json'
65
+ trends = Trends.weekly
66
+ trends.size.should == 210
67
+ trends[0].name.should == 'Happy Mothers Day'
68
+ trends[0].query.should == %Q(\"Happy Mothers Day\" OR \"Mothers Day\")
69
+ end
70
+
71
+ should "be able to exclude hastags" do
72
+ stub_get 'http://search.twitter.com:80/trends/weekly.json?exclude=hashtags', 'trends_weekly_exclude.json'
73
+ trends = Trends.weekly(:exclude => 'hashtags')
74
+ trends.size.should == 210
75
+ trends[0].name.should == 'Happy Mothers Day'
76
+ trends[0].query.should == %Q(\"Happy Mothers Day\" OR \"Mothers Day\")
77
+ end
78
+
79
+ should "be able to get for specific date (with date string)" do
80
+ stub_get 'http://search.twitter.com:80/trends/weekly.json?date=2009-05-01', 'trends_weekly_date.json'
81
+ trends = Trends.weekly(:date => '2009-05-01')
82
+ trends.size.should == 210
83
+ trends[0].name.should == 'TGIF'
84
+ trends[0].query.should == 'TGIF'
85
+ end
86
+
87
+ should "be able to get for specific date (with date object)" do
88
+ stub_get 'http://search.twitter.com:80/trends/weekly.json?date=2009-05-01', 'trends_weekly_date.json'
89
+ trends = Trends.weekly(:date => Date.new(2009, 5, 1))
90
+ trends.size.should == 210
91
+ trends[0].name.should == 'TGIF'
92
+ trends[0].query.should == 'TGIF'
93
+ end
94
+ end
95
+ end