t 0.0.2 → 0.1.0

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.
@@ -0,0 +1,7 @@
1
+ class String
2
+
3
+ def strip_at
4
+ self.tr('@', '')
5
+ end
6
+
7
+ end
data/lib/t/delete.rb ADDED
@@ -0,0 +1,101 @@
1
+ require 't/rcfile'
2
+ require 'thor'
3
+ require 'twitter'
4
+
5
+ module T
6
+ class Delete < Thor
7
+ DEFAULT_HOST = 'api.twitter.com'
8
+ DEFAULT_PROTOCOL = 'https'
9
+
10
+ check_unknown_options!
11
+
12
+ def initialize(*)
13
+ super
14
+ @rcfile = RCFile.instance
15
+ end
16
+
17
+ desc "block USERNAME", "Unblock a user."
18
+ def block(username)
19
+ username = username.strip_at
20
+ user = client.unblock(username)
21
+ say "@#{@rcfile.default_profile[0]} unblocked @#{user.screen_name}"
22
+ say
23
+ say "Run `#{$0} block #{user.screen_name}` to block."
24
+ end
25
+
26
+ desc "dm", "Delete the last Direct Message sent."
27
+ def dm
28
+ direct_message = client.direct_messages_sent(:count => 1).first
29
+ if direct_message
30
+ unless parent_options['force']
31
+ exit unless yes?("Are you sure you want to permanently delete the direct message to @#{direct_message.recipient.screen_name}: #{direct_message.text}?")
32
+ end
33
+ direct_message = client.direct_message_destroy(direct_message.id)
34
+ say "@#{direct_message.sender.screen_name} deleted the direct message sent to @#{direct_message.recipient.screen_name}: #{direct_message.text}"
35
+ else
36
+ raise Thor::Error, "Direct Message not found"
37
+ end
38
+ end
39
+ map %w(m) => :dm
40
+
41
+ desc "favorite", "Deletes the last favorite."
42
+ def favorite
43
+ status = client.favorites(:count => 1).first
44
+ if status
45
+ unless parent_options['force']
46
+ exit unless yes?("Are you sure you want to delete the favorite of @#{status.user.screen_name}: #{status.text}?")
47
+ end
48
+ client.unfavorite(status.id)
49
+ say "@#{@rcfile.default_profile[0]} unfavorited @#{status.user.screen_name}'s latest status: #{status.text}"
50
+ say
51
+ say "Run `#{$0} favorite #{status.user.screen_name}` to favorite."
52
+ else
53
+ raise Thor::Error, "Tweet not found"
54
+ end
55
+ end
56
+ map %w(fave) => :favorite
57
+
58
+ desc "status", "Delete a Tweet."
59
+ def status
60
+ user = client.user
61
+ if user.status
62
+ unless parent_options['force']
63
+ exit unless yes?("Are you sure you want to permanently delete the status: #{user.status.text}?")
64
+ end
65
+ status = client.status_destroy(user.status.id)
66
+ say "@#{@rcfile.default_profile[0]} deleted the status: #{status.text}"
67
+ else
68
+ raise Thor::Error, "Tweet not found"
69
+ end
70
+ end
71
+ map %w(post tweet update) => :status
72
+
73
+ no_tasks do
74
+
75
+ def base_url
76
+ "#{protocol}://#{host}"
77
+ end
78
+
79
+ def client
80
+ return @client if @client
81
+ @rcfile.path = parent_options['profile'] if parent_options['profile']
82
+ @client = Twitter::Client.new(
83
+ :endpoint => base_url,
84
+ :consumer_key => @rcfile.default_consumer_key,
85
+ :consumer_secret => @rcfile.default_consumer_secret,
86
+ :oauth_token => @rcfile.default_token,
87
+ :oauth_token_secret => @rcfile.default_secret
88
+ )
89
+ end
90
+
91
+ def host
92
+ parent_options['host'] || DEFAULT_HOST
93
+ end
94
+
95
+ def protocol
96
+ parent_options['no_ssl'] ? 'http' : DEFAULT_PROTOCOL
97
+ end
98
+
99
+ end
100
+ end
101
+ end
data/lib/t/set.rb CHANGED
@@ -7,42 +7,49 @@ module T
7
7
  DEFAULT_HOST = 'api.twitter.com'
8
8
  DEFAULT_PROTOCOL = 'https'
9
9
 
10
+ check_unknown_options!
11
+
12
+ def initialize(*)
13
+ super
14
+ @rcfile = RCFile.instance
15
+ end
16
+
10
17
  desc "bio DESCRIPTION", "Edits your Bio information on your Twitter profile."
11
18
  def bio(description)
12
19
  client.update_profile(:description => description)
13
- say "Bio has been changed."
20
+ say "@#{@rcfile.default_profile[0]}'s bio has been updated."
14
21
  end
15
22
 
16
- desc "default USERNAME, CONSUMER_KEY", "Set your default account."
23
+ desc "default USERNAME [CONSUMER_KEY]", "Set your default account."
17
24
  def default(username, consumer_key=nil)
18
- rcfile = RCFile.instance
25
+ @rcfile.path = parent_options['profile'] if parent_options['profile']
19
26
  consumer_key = rcfile[username].keys.last if consumer_key.nil?
20
- rcfile.default_profile = {'username' => username, 'consumer_key' => consumer_key}
21
- say "Default account has been changed."
27
+ @rcfile.default_profile = {'username' => username, 'consumer_key' => consumer_key}
28
+ say "Default account has been updated."
22
29
  end
23
30
 
24
31
  desc "language LANGUAGE_NAME", "Selects the language you'd like to receive notifications in."
25
32
  def language(language_name)
26
- client.settings(:language => language_name)
27
- say "Language has been changed."
33
+ client.settings(:lang => language_name)
34
+ say "@#{@rcfile.default_profile[0]}'s language has been updated."
28
35
  end
29
36
 
30
37
  desc "location PLACE_NAME", "Updates the location field in your profile."
31
38
  def location(place_name)
32
39
  client.update_profile(:location => place_name)
33
- say "Location has been changed."
40
+ say "@#{@rcfile.default_profile[0]}'s location has been updated."
34
41
  end
35
42
 
36
43
  desc "name NAME", "Sets the name field on your Twitter profile."
37
44
  def name(name)
38
45
  client.update_profile(:name => name)
39
- say "Name has been changed."
46
+ say "@#{@rcfile.default_profile[0]}'s name has been updated."
40
47
  end
41
48
 
42
49
  desc "url URL", "Sets the URL field on your profile."
43
50
  def url(url)
44
51
  client.update_profile(:url => url)
45
- say "URL has been changed."
52
+ say "@#{@rcfile.default_profile[0]}'s URL has been updated."
46
53
  end
47
54
 
48
55
  no_tasks do
@@ -52,13 +59,14 @@ module T
52
59
  end
53
60
 
54
61
  def client
55
- rcfile = RCFile.instance
56
- Twitter::Client.new(
62
+ return @client if @client
63
+ @rcfile.path = parent_options['profile'] if parent_options['profile']
64
+ @client = Twitter::Client.new(
57
65
  :endpoint => base_url,
58
- :consumer_key => rcfile.default_consumer_key,
59
- :consumer_secret => rcfile.default_consumer_secret,
60
- :oauth_token => rcfile.default_token,
61
- :oauth_token_secret => rcfile.default_secret
66
+ :consumer_key => @rcfile.default_consumer_key,
67
+ :consumer_secret => @rcfile.default_consumer_secret,
68
+ :oauth_token => @rcfile.default_token,
69
+ :oauth_token_secret => @rcfile.default_secret
62
70
  )
63
71
  end
64
72
 
@@ -67,7 +75,7 @@ module T
67
75
  end
68
76
 
69
77
  def protocol
70
- parent_options['no-ssl'] ? 'http' : DEFAULT_PROTOCOL
78
+ parent_options['no_ssl'] ? 'http' : DEFAULT_PROTOCOL
71
79
  end
72
80
 
73
81
  end
data/lib/t/version.rb CHANGED
@@ -8,12 +8,12 @@ module T
8
8
 
9
9
  # @return [Integer]
10
10
  def self.minor
11
- 0
11
+ 1
12
12
  end
13
13
 
14
14
  # @return [Integer]
15
15
  def self.patch
16
- 2
16
+ 0
17
17
  end
18
18
 
19
19
  # @return [String, NilClass]
data/spec/cli_spec.rb ADDED
@@ -0,0 +1,587 @@
1
+ # encoding: utf-8
2
+ require 'helper'
3
+
4
+ describe T::CLI do
5
+
6
+ before do
7
+ @t = T::CLI.new
8
+ Timecop.freeze(Time.local(2011, 11, 24, 16, 20, 0))
9
+ @old_stderr = $stderr
10
+ $stderr = StringIO.new
11
+ @old_stdout = $stdout
12
+ $stdout = StringIO.new
13
+ end
14
+
15
+ after do
16
+ $stderr = @old_stderr
17
+ $stdout = @old_stdout
18
+ end
19
+
20
+ describe "#account" do
21
+ before do
22
+ @t.options = @t.options.merge(:profile => File.expand_path('../fixtures/.trc', __FILE__))
23
+ end
24
+ it "should have the correct output" do
25
+ @t.accounts
26
+ $stdout.string.should == <<-eos.gsub(/^ {8}/, '')
27
+ testcli
28
+ abc123 (default)
29
+ eos
30
+ end
31
+ end
32
+
33
+ describe "#authorize" do
34
+ before do
35
+ @t.options = @t.options.merge(:profile => File.expand_path('/tmp/trc', __FILE__), :consumer_key => "abc123", :consumer_secret => "asdfasd223sd2", :prompt => true, :dry_run => true)
36
+ stub_post("/oauth/request_token").
37
+ to_return(:body => fixture("request_token"))
38
+ stub_post("/oauth/access_token").
39
+ to_return(:body => fixture("access_token"))
40
+ stub_get("/1/account/verify_credentials.json").
41
+ to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
42
+ end
43
+ it "should request the correct resource" do
44
+ $stdout.should_receive(:print).with("Press [Enter] to open the Twitter app authorization page. ")
45
+ $stdin.should_receive(:gets).and_return("\n")
46
+ $stdout.should_receive(:print).with("Paste in the supplied PIN: ")
47
+ $stdin.should_receive(:gets).and_return("1234567890")
48
+ @t.authorize
49
+ a_post("/oauth/request_token").
50
+ should have_been_made
51
+ a_post("/oauth/access_token").
52
+ should have_been_made
53
+ a_get("/1/account/verify_credentials.json").
54
+ should have_been_made
55
+ end
56
+ it "should not raise error" do
57
+ lambda do
58
+ $stdout.should_receive(:print).with("Press [Enter] to open the Twitter app authorization page. ")
59
+ $stdin.should_receive(:gets).and_return("\n")
60
+ $stdout.should_receive(:print).with("Paste in the supplied PIN: ")
61
+ $stdin.should_receive(:gets).and_return("1234567890")
62
+ @t.authorize
63
+ end.should_not raise_error
64
+ end
65
+ end
66
+
67
+ describe "#block" do
68
+ before do
69
+ @t.options = @t.options.merge(:profile => File.expand_path('../fixtures/.trc', __FILE__))
70
+ stub_post("/1/blocks/create.json").
71
+ with(:body => {:screen_name => "sferik"}).
72
+ to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
73
+ end
74
+ it "should request the correct resource" do
75
+ @t.block("sferik")
76
+ a_post("/1/blocks/create.json").
77
+ with(:body => {:screen_name => "sferik"}).
78
+ should have_been_made
79
+ end
80
+ it "should have the correct output" do
81
+ @t.block("sferik")
82
+ $stdout.string.should =~ /^@testcli blocked @sferik/
83
+ end
84
+ end
85
+
86
+ describe "#direct_messages" do
87
+ before do
88
+ stub_get("/1/direct_messages.json").
89
+ to_return(:body => fixture("direct_messages.json"), :headers => {:content_type => "application/json; charset=utf-8"})
90
+ end
91
+ it "should request the correct resource" do
92
+ @t.direct_messages
93
+ a_get("/1/direct_messages.json").
94
+ should have_been_made
95
+ end
96
+ it "should have the correct output" do
97
+ @t.direct_messages
98
+ $stdout.string.should == <<-eos.gsub(/^/, ' ' * 6)
99
+ sferik: Sounds good. Meeting Tuesday is fine. (about 1 year ago)
100
+ sferik: if you want to add me to your GroupMe group, my phone number is 415-312-2382 (about 1 year ago)
101
+ sferik: That's great news! Let's plan to chat around 8 AM tomorrow Pacific time. Does that work for you? (about 1 year ago)
102
+ sferik: I asked Yehuda about the stipend. I believe it has already been sent. Glad you're feeling better. (about 1 year ago)
103
+ sferik: Just checking in. How's everything going? (about 1 year ago)
104
+ sferik: Any luck completing graphs this weekend? There have been lots of commits to RailsAdmin since summer ended but none from you. How's it going? (about 1 year ago)
105
+ sferik: Not sure about the payment. Feel free to ask Leah or Yehuda directly. Think you'll be able to finish up your work on graphs this weekend? (about 1 year ago)
106
+ sferik: Looks good to me. I'm going to pull in the change now. My only concern is that we don't have any tests for auth. (about 1 year ago)
107
+ sferik: How are the graph enhancements coming? (about 1 year ago)
108
+ sferik: Changes pushed. You should pull and re-bundle when you have a minute. (about 1 year ago)
109
+ sferik: Glad to hear the new graphs are coming along. Can't wait to see them! (about 1 year ago)
110
+ sferik: I figured out what was wrong with the tests: I accidentally unbundled webrat. The problem had nothing to do with rspec-rails. (about 1 year ago)
111
+ sferik: After the upgrade 54/80 specs are failing. I'm working on fixing them now. (about 1 year ago)
112
+ sferik: a new version of rspec-rails just shipped with some nice features and fixes http://github.com/rspec/rspec-rails/blob/master/History.md (about 1 year ago)
113
+ sferik: How are the graphs coming? I'm really looking forward to seeing what you do with Raphaël. (about 1 year ago)
114
+ sferik: Awesome! Any luck duplicating the Gemfile.lock error with Ruby 1.9.2 final? (about 1 year ago)
115
+ sferik: I just committed a bunch of cleanup and fixes to RailsAdmin that touched many of files. Make sure you pull to avoid conflicts. (about 1 year ago)
116
+ sferik: Can you try upgrading to 1.9.2 final, re-installing Bundler 1.0.0.rc.6 (don't remove 1.0.0) and see if you can reproduce the problem? (about 1 year ago)
117
+ sferik: I'm trying to debug the issue you were having with the Bundler Gemfile.lock shortref. What version of Ruby and RubyGems are you running? (about 1 year ago)
118
+ sferik: Let's try to debug that problem during our session in 1.5 hours. In the mean time, try working on the graphs or internationalization. (about 1 year ago)
119
+ eos
120
+ end
121
+ end
122
+
123
+ describe "#dm" do
124
+ before do
125
+ @t.options = @t.options.merge(:profile => File.expand_path('../fixtures/.trc', __FILE__))
126
+ stub_post("/1/direct_messages/new.json").
127
+ with(:body => {:screen_name => "pengwynn", :text => "Creating a fixture for the Twitter gem"}).
128
+ to_return(:body => fixture("direct_message.json"), :headers => {:content_type => "application/json; charset=utf-8"})
129
+ end
130
+ it "should request the correct resource" do
131
+ @t.dm("pengwynn", "Creating a fixture for the Twitter gem")
132
+ a_post("/1/direct_messages/new.json").
133
+ with(:body => {:screen_name => "pengwynn", :text => "Creating a fixture for the Twitter gem"}).
134
+ should have_been_made
135
+ end
136
+ it "should have the correct output" do
137
+ @t.dm("pengwynn", "Creating a fixture for the Twitter gem")
138
+ $stdout.string.chomp.should == "Direct Message sent from @testcli to @pengwynn (about 1 year ago)"
139
+ end
140
+ end
141
+
142
+ describe "#favorite" do
143
+ before do
144
+ @t.options = @t.options.merge(:profile => File.expand_path('../fixtures/.trc', __FILE__))
145
+ end
146
+ context "not found" do
147
+ before do
148
+ stub_get("/1/users/show.json").
149
+ with(:query => {:screen_name => "sferik"}).
150
+ to_return(:body => '{}', :headers => {:content_type => "application/json; charset=utf-8"})
151
+ end
152
+ it "should exit" do
153
+ lambda do
154
+ @t.favorite("sferik")
155
+ end.should raise_error(Thor::Error, "Tweet not found")
156
+ end
157
+ end
158
+ context "forbidden" do
159
+ before do
160
+ stub_get("/1/users/show.json").
161
+ with(:query => {:screen_name => "sferik"}).
162
+ to_return(:body => '{"error":"Forbidden"}', :headers => {:content_type => "application/json; charset=utf-8"}, :status => 403)
163
+ end
164
+ it "should exit" do
165
+ lambda do
166
+ @t.favorite("sferik")
167
+ end.should raise_error(Twitter::Error::Forbidden, "Forbidden")
168
+ end
169
+ end
170
+ context "duplicate" do
171
+ before do
172
+ stub_get("/1/users/show.json").
173
+ with(:query => {:screen_name => "sferik"}).
174
+ to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
175
+ stub_post("/1/favorites/create/26755176471724032.json").
176
+ to_return(:body => '{"error":"You have already favorited this status."}', :headers => {:content_type => "application/json; charset=utf-8"}, :status => 403)
177
+ end
178
+ it "should have the correct output" do
179
+ @t.favorite("sferik")
180
+ $stdout.string.should =~ /^@testcli favorited @sferik's latest status: RT @tenderlove: \[ANN\] sqlite3-ruby =&gt; sqlite3$/
181
+ end
182
+ end
183
+ context "found" do
184
+ before do
185
+ stub_get("/1/users/show.json").
186
+ with(:query => {:screen_name => "sferik"}).
187
+ to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
188
+ stub_post("/1/favorites/create/26755176471724032.json").
189
+ to_return(:body => fixture("status.json"), :headers => {:content_type => "application/json; charset=utf-8"})
190
+ end
191
+ it "should request the correct resource" do
192
+ @t.favorite("sferik")
193
+ a_get("/1/users/show.json").
194
+ with(:query => {:screen_name => "sferik"}).
195
+ should have_been_made
196
+ a_post("/1/favorites/create/26755176471724032.json").
197
+ should have_been_made
198
+ end
199
+ it "should have the correct output" do
200
+ @t.favorite("sferik")
201
+ $stdout.string.should =~ /^@testcli favorited @sferik's latest status: RT @tenderlove: \[ANN\] sqlite3-ruby =&gt; sqlite3$/
202
+ end
203
+ end
204
+ end
205
+
206
+ describe "#follow" do
207
+ before do
208
+ @t.options = @t.options.merge(:profile => File.expand_path('../fixtures/.trc', __FILE__))
209
+ stub_post("/1/friendships/create.json").
210
+ with(:body => {:screen_name => "sferik"}).
211
+ to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
212
+ end
213
+ it "should request the correct resource" do
214
+ @t.follow("sferik")
215
+ a_post("/1/friendships/create.json").
216
+ with(:body => {:screen_name => "sferik"}).
217
+ should have_been_made
218
+ end
219
+ it "should have the correct output" do
220
+ @t.follow("sferik")
221
+ $stdout.string.should =~ /^@testcli is now following @sferik\.$/
222
+ end
223
+ end
224
+
225
+ describe "#get" do
226
+ context "not found" do
227
+ before do
228
+ stub_get("/1/users/show.json").
229
+ with(:query => {:screen_name => "sferik"}).
230
+ to_return(:body => '{}', :headers => {:content_type => "application/json; charset=utf-8"})
231
+ end
232
+ it "should exit" do
233
+ lambda do
234
+ @t.get("sferik")
235
+ end.should raise_error(Thor::Error, "Tweet not found")
236
+ end
237
+ end
238
+ context "found" do
239
+ before do
240
+ stub_get("/1/users/show.json").
241
+ with(:query => {:screen_name => "sferik"}).
242
+ to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
243
+ end
244
+ it "should request the correct resource" do
245
+ @t.get("sferik")
246
+ a_get("/1/users/show.json").
247
+ with(:query => {:screen_name => "sferik"}).
248
+ should have_been_made
249
+ end
250
+ it "should have the correct output" do
251
+ @t.get("sferik")
252
+ $stdout.string.chomp.should == "RT @tenderlove: [ANN] sqlite3-ruby =&gt; sqlite3 (10 months ago)"
253
+ end
254
+ end
255
+ end
256
+
257
+ describe "#mentions" do
258
+ before do
259
+ stub_get("/1/statuses/mentions.json").
260
+ to_return(:body => fixture("statuses.json"), :headers => {:content_type => "application/json; charset=utf-8"})
261
+ end
262
+ it "should request the correct resource" do
263
+ @t.mentions
264
+ a_get("/1/statuses/mentions.json").
265
+ should have_been_made
266
+ end
267
+ it "should have the correct output" do
268
+ @t.mentions
269
+ $stdout.string.should == <<-eos.gsub(/^/, ' ' * 6)
270
+ sferik: Ruby is the best programming language for hiding the ugly bits. (about 1 year ago)
271
+ sferik: There are 1.3 billion people in China; when people say there are 1 billion they are rounding off the entire population of the United States. (about 1 year ago)
272
+ sferik: The new Windows Phone campaign is the best advertising from Microsoft since "Start Me Up" (1995). Great work by CP+B. http://t.co/tIzxopI (about 1 year ago)
273
+ sferik: Fear not to sow seeds because of the birds. http://twitpic.com/2wg621 (about 1 year ago)
274
+ sferik: Speaking of things that are maddening: the interview with the Wall Street guys on the most recent This American Life http://bit.ly/af9pSD (about 1 year ago)
275
+ sferik: Holy cow! RailsAdmin is up to 200 watchers (from 100 yesterday). http://github.com/sferik/rails_admin (about 1 year ago)
276
+ sferik: Kind of cool that Facebook acts as a mirror for open-source projects that they use or like http://mirror.facebook.net/ (about 1 year ago)
277
+ sferik: RailsAdmin already has 100 watchers, 12 forks, and 6 contributors in less than 2 months. Let's keep the momentum going! http://bit.ly/cCMMqD (about 1 year ago)
278
+ sferik: This week's This American Life is amazing. @JoeLipari is an American hero. http://bit.ly/d9RbnB (about 1 year ago)
279
+ sferik: RT @polyseme: OH: shofars should be called jewvuzelas. (about 1 year ago)
280
+ sferik: Spent this morning fixing broken windows in RailsAdmin http://github.com/sferik/rails_admin/compare/ab6c598...0e3770f (about 1 year ago)
281
+ sferik: I'm a big believer that the broken windows theory applies to software development http://en.wikipedia.org/wiki/Broken_windows_theory (about 1 year ago)
282
+ sferik: I hope you idiots are happy with your piece of shit Android phones. http://www.apple.com/pr/library/2010/09/09statement.html (about 1 year ago)
283
+ sferik: Ping: kills MySpace dead. (about 1 year ago)
284
+ sferik: Crazy that iTunes Ping didn't leak a drop. (about 1 year ago)
285
+ sferik: The plot thickens http://twitpic.com/2k5lt2 (about 1 year ago)
286
+ sferik: 140 Proof Provides A Piece Of The Twitter Advertising Puzzle http://t.co/R2cUSDe via @techcrunch (about 1 year ago)
287
+ sferik: Try as you may http://www.thedoghousediaries.com/?p=1940 (about 1 year ago)
288
+ sferik: I know @SarahPalinUSA has a right to use Twitter, but should she? (over 1 year ago)
289
+ eos
290
+ end
291
+ end
292
+
293
+ describe "#open" do
294
+ before do
295
+ @t.options = @t.options.merge(:dry_run => true)
296
+ end
297
+ it "should not raise error" do
298
+ lambda do
299
+ @t.open("sferik")
300
+ end.should_not raise_error
301
+ end
302
+ end
303
+
304
+ describe "#reply" do
305
+ before do
306
+ @t.options = @t.options.merge(:profile => File.expand_path('../fixtures/.trc', __FILE__), :location => true)
307
+ stub_get("/1/users/show.json").
308
+ with(:query => {:screen_name => "sferik"}).
309
+ to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
310
+ stub_post("/1/statuses/update.json").
311
+ with(:body => {:in_reply_to_status_id => "26755176471724032", :status => "@sferik Testing", :lat => "37.76969909668", :long => "-122.39330291748"}).
312
+ to_return(:body => fixture("status.json"), :headers => {:content_type => "application/json; charset=utf-8"})
313
+ stub_request(:get, "http://checkip.dyndns.org/").
314
+ to_return(:body => fixture("checkip.html"), :headers => {:content_type => "text/html"})
315
+ stub_request(:get, "http://www.geoplugin.net/xml.gp?ip=50.131.22.169").
316
+ to_return(:body => fixture("xml.gp"), :headers => {:content_type => "application/xml"})
317
+ end
318
+ it "should request the correct resource" do
319
+ @t.reply("sferik", "Testing")
320
+ a_get("/1/users/show.json").
321
+ with(:query => {:screen_name => "sferik"}).
322
+ should have_been_made
323
+ a_post("/1/statuses/update.json").
324
+ with(:body => {:in_reply_to_status_id => "26755176471724032", :status => "@sferik Testing", :lat => "37.76969909668", :long => "-122.39330291748"}).
325
+ should have_been_made
326
+ a_request(:get, "http://checkip.dyndns.org/").
327
+ should have_been_made
328
+ a_request(:get, "http://www.geoplugin.net/xml.gp?ip=50.131.22.169").
329
+ should have_been_made
330
+ end
331
+ it "should have the correct output" do
332
+ @t.reply("sferik", "Testing")
333
+ $stdout.string.should =~ /^Reply created by @testcli to @sferik \(about 1 year ago\)$/
334
+ end
335
+ end
336
+
337
+ describe "#retweet" do
338
+ before do
339
+ @t.options = @t.options.merge(:profile => File.expand_path('../fixtures/.trc', __FILE__))
340
+ end
341
+ context "not found" do
342
+ before do
343
+ stub_get("/1/users/show.json").
344
+ with(:query => {:screen_name => "sferik"}).
345
+ to_return(:body => '{}', :headers => {:content_type => "application/json; charset=utf-8"})
346
+ end
347
+ it "should exit" do
348
+ lambda do
349
+ @t.retweet("sferik")
350
+ end.should raise_error(Thor::Error, "Tweet not found")
351
+ end
352
+ end
353
+ context "forbidden" do
354
+ before do
355
+ stub_get("/1/users/show.json").
356
+ with(:query => {:screen_name => "sferik"}).
357
+ to_return(:body => '{"error":"Forbidden"}', :headers => {:content_type => "application/json; charset=utf-8"}, :status => 403)
358
+ end
359
+ it "should exit" do
360
+ lambda do
361
+ @t.retweet("sferik")
362
+ end.should raise_error(Twitter::Error::Forbidden, "Forbidden")
363
+ end
364
+ end
365
+ context "duplicate" do
366
+ before do
367
+ stub_get("/1/users/show.json").
368
+ with(:query => {:screen_name => "sferik"}).
369
+ to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
370
+ stub_post("/1/statuses/retweet/26755176471724032.json").
371
+ to_return(:body => '{"error":"sharing is not permissable for this status (Share validations failed)"}', :headers => {:content_type => "application/json; charset=utf-8"}, :status => 403)
372
+ end
373
+ it "should have the correct output" do
374
+ @t.retweet("sferik")
375
+ $stdout.string.should =~ /^@testcli retweeted @sferik's latest status: RT @tenderlove: \[ANN\] sqlite3-ruby =&gt; sqlite3$/
376
+ end
377
+ end
378
+ context "found" do
379
+ before do
380
+ stub_get("/1/users/show.json").
381
+ with(:query => {:screen_name => "sferik"}).
382
+ to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
383
+ stub_post("/1/statuses/retweet/26755176471724032.json").
384
+ to_return(:body => fixture("retweet.json"), :headers => {:content_type => "application/json; charset=utf-8"})
385
+ end
386
+ it "should request the correct resource" do
387
+ @t.retweet("sferik")
388
+ a_get("/1/users/show.json").
389
+ with(:query => {:screen_name => "sferik"}).
390
+ should have_been_made
391
+ a_post("/1/statuses/retweet/26755176471724032.json").
392
+ should have_been_made
393
+ end
394
+ it "should have the correct output" do
395
+ @t.retweet("sferik")
396
+ $stdout.string.should =~ /^@testcli retweeted @sferik's latest status: RT @tenderlove: \[ANN\] sqlite3-ruby =&gt; sqlite3$/
397
+ end
398
+ end
399
+ end
400
+
401
+ describe "#sent_messages" do
402
+ before do
403
+ stub_get("/1/direct_messages/sent.json").
404
+ to_return(:body => fixture("direct_messages.json"), :headers => {:content_type => "application/json; charset=utf-8"})
405
+ end
406
+ it "should request the correct resource" do
407
+ @t.sent_messages
408
+ a_get("/1/direct_messages/sent.json").
409
+ should have_been_made
410
+ end
411
+ it "should have the correct output" do
412
+ @t.sent_messages
413
+ $stdout.string.should == <<-eos.gsub(/^/, ' ' * 3)
414
+ hurrycane: Sounds good. Meeting Tuesday is fine. (about 1 year ago)
415
+ technoweenie: if you want to add me to your GroupMe group, my phone number is 415-312-2382 (about 1 year ago)
416
+ hurrycane: That's great news! Let's plan to chat around 8 AM tomorrow Pacific time. Does that work for you? (about 1 year ago)
417
+ hurrycane: I asked Yehuda about the stipend. I believe it has already been sent. Glad you're feeling better. (about 1 year ago)
418
+ hurrycane: Just checking in. How's everything going? (about 1 year ago)
419
+ hurrycane: Any luck completing graphs this weekend? There have been lots of commits to RailsAdmin since summer ended but none from you. How's it going? (about 1 year ago)
420
+ hurrycane: Not sure about the payment. Feel free to ask Leah or Yehuda directly. Think you'll be able to finish up your work on graphs this weekend? (about 1 year ago)
421
+ hurrycane: Looks good to me. I'm going to pull in the change now. My only concern is that we don't have any tests for auth. (about 1 year ago)
422
+ hurrycane: How are the graph enhancements coming? (about 1 year ago)
423
+ hurrycane: Changes pushed. You should pull and re-bundle when you have a minute. (about 1 year ago)
424
+ hurrycane: Glad to hear the new graphs are coming along. Can't wait to see them! (about 1 year ago)
425
+ hurrycane: I figured out what was wrong with the tests: I accidentally unbundled webrat. The problem had nothing to do with rspec-rails. (about 1 year ago)
426
+ hurrycane: After the upgrade 54/80 specs are failing. I'm working on fixing them now. (about 1 year ago)
427
+ hurrycane: a new version of rspec-rails just shipped with some nice features and fixes http://github.com/rspec/rspec-rails/blob/master/History.md (about 1 year ago)
428
+ hurrycane: How are the graphs coming? I'm really looking forward to seeing what you do with Raphaël. (about 1 year ago)
429
+ hurrycane: Awesome! Any luck duplicating the Gemfile.lock error with Ruby 1.9.2 final? (about 1 year ago)
430
+ hurrycane: I just committed a bunch of cleanup and fixes to RailsAdmin that touched many of files. Make sure you pull to avoid conflicts. (about 1 year ago)
431
+ hurrycane: Can you try upgrading to 1.9.2 final, re-installing Bundler 1.0.0.rc.6 (don't remove 1.0.0) and see if you can reproduce the problem? (about 1 year ago)
432
+ hurrycane: I'm trying to debug the issue you were having with the Bundler Gemfile.lock shortref. What version of Ruby and RubyGems are you running? (about 1 year ago)
433
+ hurrycane: Let's try to debug that problem during our session in 1.5 hours. In the mean time, try working on the graphs or internationalization. (about 1 year ago)
434
+ eos
435
+ end
436
+ end
437
+
438
+ describe "#stats" do
439
+ before do
440
+ stub_get("/1/users/show.json").
441
+ with(:query => {:screen_name => "sferik"}).
442
+ to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
443
+ end
444
+ it "should request the correct resource" do
445
+ @t.stats("sferik")
446
+ a_get("/1/users/show.json").
447
+ with(:query => {:screen_name => "sferik"}).
448
+ should have_been_made
449
+ end
450
+ it "should have the correct output" do
451
+ @t.stats("sferik")
452
+ $stdout.string.should =~ /^Followers: 1,048$/
453
+ $stdout.string.should =~ /^Following: 197$/
454
+ end
455
+ end
456
+
457
+ describe "#status" do
458
+ before do
459
+ @t.options = @t.options.merge(:profile => File.expand_path('../fixtures/.trc', __FILE__), :location => true)
460
+ stub_post("/1/statuses/update.json").
461
+ with(:body => {:status => "Testing", :lat => "37.76969909668", :long => "-122.39330291748"}).
462
+ to_return(:body => fixture("status.json"), :headers => {:content_type => "application/json; charset=utf-8"})
463
+ stub_request(:get, "http://checkip.dyndns.org/").
464
+ to_return(:body => fixture("checkip.html"), :headers => {:content_type => "text/html"})
465
+ stub_request(:get, "http://www.geoplugin.net/xml.gp?ip=50.131.22.169").
466
+ to_return(:body => fixture("xml.gp"), :headers => {:content_type => "application/xml"})
467
+ end
468
+ it "should request the correct resource" do
469
+ @t.status("Testing")
470
+ a_post("/1/statuses/update.json").
471
+ with(:body => {:status => "Testing", :lat => "37.76969909668", :long => "-122.39330291748"}).
472
+ should have_been_made
473
+ a_request(:get, "http://checkip.dyndns.org/").
474
+ should have_been_made
475
+ a_request(:get, "http://www.geoplugin.net/xml.gp?ip=50.131.22.169").
476
+ should have_been_made
477
+ end
478
+ it "should have the correct output" do
479
+ @t.status("Testing")
480
+ $stdout.string.should =~ /^Tweet created by @testcli \(about 1 year ago\)$/
481
+ end
482
+ end
483
+
484
+ describe "#suggest" do
485
+ before do
486
+ stub_get("/1/users/recommendations.json").
487
+ with(:query => {:limit => "1"}).
488
+ to_return(:body => fixture("recommendations.json"), :headers => {:content_type => "application/json; charset=utf-8"})
489
+ end
490
+ it "should request the correct resource" do
491
+ @t.suggest
492
+ a_get("/1/users/recommendations.json").
493
+ with(:query => {:limit => "1"}).
494
+ should have_been_made
495
+ end
496
+ it "should have the correct output" do
497
+ @t.suggest
498
+ $stdout.string.should =~ /^Try following @jtrupiano\.$/
499
+ end
500
+ end
501
+
502
+ describe "#timeline" do
503
+ before do
504
+ stub_get("/1/statuses/home_timeline.json").
505
+ to_return(:body => fixture("statuses.json"), :headers => {:content_type => "application/json; charset=utf-8"})
506
+ end
507
+ it "should request the correct resource" do
508
+ @t.timeline
509
+ a_get("/1/statuses/home_timeline.json").
510
+ should have_been_made
511
+ end
512
+ it "should have the correct output" do
513
+ @t.timeline
514
+ $stdout.string.should == <<-eos.gsub(/^/, ' ' * 6)
515
+ sferik: Ruby is the best programming language for hiding the ugly bits. (about 1 year ago)
516
+ sferik: There are 1.3 billion people in China; when people say there are 1 billion they are rounding off the entire population of the United States. (about 1 year ago)
517
+ sferik: The new Windows Phone campaign is the best advertising from Microsoft since "Start Me Up" (1995). Great work by CP+B. http://t.co/tIzxopI (about 1 year ago)
518
+ sferik: Fear not to sow seeds because of the birds. http://twitpic.com/2wg621 (about 1 year ago)
519
+ sferik: Speaking of things that are maddening: the interview with the Wall Street guys on the most recent This American Life http://bit.ly/af9pSD (about 1 year ago)
520
+ sferik: Holy cow! RailsAdmin is up to 200 watchers (from 100 yesterday). http://github.com/sferik/rails_admin (about 1 year ago)
521
+ sferik: Kind of cool that Facebook acts as a mirror for open-source projects that they use or like http://mirror.facebook.net/ (about 1 year ago)
522
+ sferik: RailsAdmin already has 100 watchers, 12 forks, and 6 contributors in less than 2 months. Let's keep the momentum going! http://bit.ly/cCMMqD (about 1 year ago)
523
+ sferik: This week's This American Life is amazing. @JoeLipari is an American hero. http://bit.ly/d9RbnB (about 1 year ago)
524
+ sferik: RT @polyseme: OH: shofars should be called jewvuzelas. (about 1 year ago)
525
+ sferik: Spent this morning fixing broken windows in RailsAdmin http://github.com/sferik/rails_admin/compare/ab6c598...0e3770f (about 1 year ago)
526
+ sferik: I'm a big believer that the broken windows theory applies to software development http://en.wikipedia.org/wiki/Broken_windows_theory (about 1 year ago)
527
+ sferik: I hope you idiots are happy with your piece of shit Android phones. http://www.apple.com/pr/library/2010/09/09statement.html (about 1 year ago)
528
+ sferik: Ping: kills MySpace dead. (about 1 year ago)
529
+ sferik: Crazy that iTunes Ping didn't leak a drop. (about 1 year ago)
530
+ sferik: The plot thickens http://twitpic.com/2k5lt2 (about 1 year ago)
531
+ sferik: 140 Proof Provides A Piece Of The Twitter Advertising Puzzle http://t.co/R2cUSDe via @techcrunch (about 1 year ago)
532
+ sferik: Try as you may http://www.thedoghousediaries.com/?p=1940 (about 1 year ago)
533
+ sferik: I know @SarahPalinUSA has a right to use Twitter, but should she? (over 1 year ago)
534
+ eos
535
+ end
536
+ end
537
+
538
+ describe "#unfollow" do
539
+ before do
540
+ @t.options = @t.options.merge(:profile => File.expand_path('../fixtures/.trc', __FILE__))
541
+ stub_delete("/1/friendships/destroy.json").
542
+ with(:query => {:screen_name => "sferik"}).
543
+ to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
544
+ end
545
+ it "should request the correct resource" do
546
+ @t.unfollow("sferik")
547
+ a_delete("/1/friendships/destroy.json").
548
+ with(:query => {:screen_name => "sferik"}).
549
+ should have_been_made
550
+ end
551
+ it "should have the correct output" do
552
+ @t.unfollow("sferik")
553
+ $stdout.string.should =~ /^@testcli is no longer following @sferik\.$/
554
+ end
555
+ end
556
+
557
+ describe "#version" do
558
+ it "should have the correct output" do
559
+ @t.version
560
+ $stdout.string.chomp.should == T::Version.to_s
561
+ end
562
+ end
563
+
564
+ describe "#whois" do
565
+ before do
566
+ stub_get("/1/users/show.json").
567
+ with(:query => {:screen_name => "sferik"}).
568
+ to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
569
+ end
570
+ it "should request the correct resource" do
571
+ @t.whois("sferik")
572
+ a_get("/1/users/show.json").
573
+ with(:query => {:screen_name => "sferik"}).
574
+ should have_been_made
575
+ end
576
+ it "should have the correct output" do
577
+ @t.whois("sferik")
578
+ $stdout.string.should == <<-eos.gsub(/^ {8}/, '')
579
+ Erik Michaels-Ober, since Jul 2007.
580
+ bio: A mind forever voyaging through strange seas of thought, alone.
581
+ location: San Francisco
582
+ web: https://github.com/sferik
583
+ eos
584
+ end
585
+ end
586
+
587
+ end