t 2.2.0 → 2.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a30a59d381d4a4e6815086c4e45d1541fb372855
4
+ data.tar.gz: 300d0fedac30548d0fea628774e4b9a632716017
5
+ SHA512:
6
+ metadata.gz: 09c862bc9a765df7f652ea0820631c8d284266df0a87af3a9840694c9a1ce75cdae8e143c8312eba5cae686194185602ffe2b90e9f7d0633c80c3c43b0c8bab7
7
+ data.tar.gz: 15970f41bc2c623d6040eeb3fb7cc721ac67742b4697ec4826e6d1d8123525b4e9e039a6485299b545c625482cd77c1cde917146a6540a1217d2205def19aa71
checksums.yaml.gz.sig ADDED
Binary file
data.tar.gz.sig CHANGED
Binary file
data/README.md CHANGED
@@ -280,6 +280,7 @@ implementations:
280
280
  * Ruby 1.9.2
281
281
  * Ruby 1.9.3
282
282
  * Ruby 2.0.0
283
+ * Ruby 2.1.0
283
284
 
284
285
  If something doesn't work on one of these Ruby versions, it's a bug.
285
286
 
data/bin/t CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Trap interrupts to quit cleanly. See
4
4
  # https://twitter.com/mitchellh/status/283014103189053442
5
- Signal.trap('INT') { exit 1 }
5
+ Signal.trap('INT') { abort }
6
6
 
7
7
  require 'oauth'
8
8
  require 't'
@@ -13,28 +13,23 @@ def pute(*args)
13
13
  first = args.shift.dup
14
14
  first.insert(0, "#{$PROGRAM_NAME}: ")
15
15
  args.unshift(first)
16
- $stderr.puts(*args)
16
+ abort(*args)
17
17
  end
18
18
 
19
19
  begin
20
20
  T::CLI.start(ARGV)
21
21
  rescue Interrupt
22
22
  pute 'Quitting...'
23
- exit 1
24
23
  rescue OAuth::Unauthorized
25
24
  pute 'Authorization failed'
26
- exit 1
27
25
  rescue Twitter::Error::TooManyRequests => error
28
26
  pute error.message,
29
27
  "The rate limit for this request will reset in #{error.rate_limit.reset_in} seconds.",
30
28
  'While you wait, consider making a polite request for Twitter to increase the API rate limit at https://dev.twitter.com/discussions/10644'
31
- exit 1
32
29
  rescue Twitter::Error::BadRequest => error
33
30
  pute error.message,
34
31
  'Run `t authorize` to authorize.'
35
- exit 1
36
32
  rescue Twitter::Error::Forbidden, Twitter::Error::Unauthorized => error
37
- pute error.message
38
33
  if error.message == 'Error processing your OAuth request: Read-only application cannot POST' ||
39
34
  error.message == 'This application is not allowed to access or delete your direct messages'
40
35
  $stderr.puts(%q(Make sure to set your Twitter application's Access Level to "Read, Write and Access direct messages".))
@@ -42,9 +37,9 @@ rescue Twitter::Error::Forbidden, Twitter::Error::Unauthorized => error
42
37
  Thor::Shell::Basic.new.ask 'Press [Enter] to open the Twitter Developer site.'
43
38
  require 'launchy'
44
39
  Launchy.open('https://dev.twitter.com/apps') { |u, o, e| $stderr.puts "Manually open #{u}" }
40
+ else
41
+ pute error.message
45
42
  end
46
- exit 1
47
43
  rescue Twitter::Error => error
48
44
  pute error.message
49
- exit 1
50
45
  end
data/lib/t.rb CHANGED
@@ -14,13 +14,13 @@ module T
14
14
 
15
15
  def utc_offset=(offset)
16
16
  @utc_offset = case offset
17
- when String
18
- Time.zone_offset(offset)
19
- when NilClass
20
- nil
21
- else
22
- offset.to_i
23
- end
17
+ when String
18
+ Time.zone_offset(offset)
19
+ when NilClass
20
+ nil
21
+ else
22
+ offset.to_i
23
+ end
24
24
  end
25
25
  end
26
26
  end
data/lib/t/cli.rb CHANGED
@@ -29,7 +29,7 @@ module T
29
29
 
30
30
  check_unknown_options!
31
31
 
32
- class_option 'color', :aliases => '-C', :type => :string, :enum => %w(auto never), :default => 'auto', :desc => 'Control how color is used in output'
32
+ class_option 'color', :aliases => '-C', :type => :string, :enum => %w[auto never], :default => 'auto', :desc => 'Control how color is used in output'
33
33
  class_option 'profile', :aliases => '-P', :type => :string, :default => File.join(File.expand_path('~'), T::RCFile::FILE_NAME), :desc => 'Path to RC file', :banner => 'FILE'
34
34
 
35
35
  def initialize(*)
@@ -124,26 +124,28 @@ module T
124
124
 
125
125
  desc 'direct_messages', "Returns the #{DEFAULT_NUM_RESULTS} most recent Direct Messages sent to you."
126
126
  method_option 'csv', :aliases => '-c', :type => :boolean, :default => false, :desc => 'Output in CSV format.'
127
+ method_option 'decode_uris', :aliases => '-d', :type => :boolean, :default => false, :desc => 'Decodes t.co URLs into their original form.'
127
128
  method_option 'long', :aliases => '-l', :type => :boolean, :default => false, :desc => 'Output in long format.'
128
129
  method_option 'relative_dates', :aliases => '-a', :type => :boolean, :desc => 'Show relative dates.'
129
130
  method_option 'number', :aliases => '-n', :type => :numeric, :default => DEFAULT_NUM_RESULTS, :desc => 'Limit the number of results.'
130
131
  method_option 'reverse', :aliases => '-r', :type => :boolean, :default => false, :desc => 'Reverse the order of the sort.'
131
132
  def direct_messages
132
133
  count = options['number'] || DEFAULT_NUM_RESULTS
134
+ opts = {}
135
+ opts[:include_entities] = !!options['decode_uris']
133
136
  direct_messages = collect_with_count(count) do |count_opts|
134
- client.direct_messages(count_opts)
137
+ client.direct_messages(count_opts.merge(opts))
135
138
  end
136
139
  direct_messages.reverse! if options['reverse']
137
- require 'htmlentities'
138
140
  if options['csv']
139
141
  require 'csv'
140
142
  say DIRECT_MESSAGE_HEADINGS.to_csv unless direct_messages.empty?
141
143
  direct_messages.each do |direct_message|
142
- say [direct_message.id, csv_formatted_time(direct_message), direct_message.sender.screen_name, HTMLEntities.new.decode(direct_message.text)].to_csv
144
+ say [direct_message.id, csv_formatted_time(direct_message), direct_message.sender.screen_name, decode_full_text(direct_message, options['decode_uris'])].to_csv
143
145
  end
144
146
  elsif options['long']
145
147
  array = direct_messages.map do |direct_message|
146
- [direct_message.id, ls_formatted_time(direct_message), "@#{direct_message.sender.screen_name}", HTMLEntities.new.decode(direct_message.text).gsub(/\n+/, ' ')]
148
+ [direct_message.id, ls_formatted_time(direct_message), "@#{direct_message.sender.screen_name}", decode_full_text(direct_message, options['decode_uris']).gsub(/\n+/, ' ')]
147
149
  end
148
150
  format = options['format'] || DIRECT_MESSAGE_HEADINGS.size.times.map { '%s' }
149
151
  print_table_with_headings(array, DIRECT_MESSAGE_HEADINGS, format)
@@ -153,30 +155,32 @@ module T
153
155
  end
154
156
  end
155
157
  end
156
- map %w(directmessages dms) => :direct_messages
158
+ map %w[directmessages dms] => :direct_messages
157
159
 
158
160
  desc 'direct_messages_sent', "Returns the #{DEFAULT_NUM_RESULTS} most recent Direct Messages you've sent."
159
161
  method_option 'csv', :aliases => '-c', :type => :boolean, :default => false, :desc => 'Output in CSV format.'
162
+ method_option 'decode_uris', :aliases => '-d', :type => :boolean, :default => false, :desc => 'Decodes t.co URLs into their original form.'
160
163
  method_option 'long', :aliases => '-l', :type => :boolean, :default => false, :desc => 'Output in long format.'
161
- method_option 'relative_dates', :aliases => '-a', :type => :boolean, :desc => 'Show relative dates.'
162
164
  method_option 'number', :aliases => '-n', :type => :numeric, :default => DEFAULT_NUM_RESULTS, :desc => 'Limit the number of results.'
165
+ method_option 'relative_dates', :aliases => '-a', :type => :boolean, :desc => 'Show relative dates.'
163
166
  method_option 'reverse', :aliases => '-r', :type => :boolean, :default => false, :desc => 'Reverse the order of the sort.'
164
167
  def direct_messages_sent
165
168
  count = options['number'] || DEFAULT_NUM_RESULTS
169
+ opts = {}
170
+ opts[:include_entities] = !!options['decode_uris']
166
171
  direct_messages = collect_with_count(count) do |count_opts|
167
- client.direct_messages_sent(count_opts)
172
+ client.direct_messages_sent(count_opts.merge(opts))
168
173
  end
169
174
  direct_messages.reverse! if options['reverse']
170
- require 'htmlentities'
171
175
  if options['csv']
172
176
  require 'csv'
173
177
  say DIRECT_MESSAGE_HEADINGS.to_csv unless direct_messages.empty?
174
178
  direct_messages.each do |direct_message|
175
- say [direct_message.id, csv_formatted_time(direct_message), direct_message.recipient.screen_name, HTMLEntities.new.decode(direct_message.text)].to_csv
179
+ say [direct_message.id, csv_formatted_time(direct_message), direct_message.recipient.screen_name, decode_full_text(direct_message, options['decode_uris'])].to_csv
176
180
  end
177
181
  elsif options['long']
178
182
  array = direct_messages.map do |direct_message|
179
- [direct_message.id, ls_formatted_time(direct_message), "@#{direct_message.recipient.screen_name}", HTMLEntities.new.decode(direct_message.text).gsub(/\n+/, ' ')]
183
+ [direct_message.id, ls_formatted_time(direct_message), "@#{direct_message.recipient.screen_name}", decode_full_text(direct_message, options['decode_uris']).gsub(/\n+/, ' ')]
180
184
  end
181
185
  format = options['format'] || DIRECT_MESSAGE_HEADINGS.size.times.map { '%s' }
182
186
  print_table_with_headings(array, DIRECT_MESSAGE_HEADINGS, format)
@@ -186,7 +190,7 @@ module T
186
190
  end
187
191
  end
188
192
  end
189
- map %w(directmessagessent sent_messages sentmessages sms) => :direct_messages_sent
193
+ map %w[directmessagessent sent_messages sentmessages sms] => :direct_messages_sent
190
194
 
191
195
  desc 'groupies [USER]', "Returns the list of people who follow you but you don't follow back."
192
196
  method_option 'csv', :aliases => '-c', :type => :boolean, :default => false, :desc => 'Output in CSV format.'
@@ -194,21 +198,17 @@ module T
194
198
  method_option 'long', :aliases => '-l', :type => :boolean, :default => false, :desc => 'Output in long format.'
195
199
  method_option 'relative_dates', :aliases => '-a', :type => :boolean, :desc => 'Show relative dates.'
196
200
  method_option 'reverse', :aliases => '-r', :type => :boolean, :default => false, :desc => 'Reverse the order of the sort.'
197
- method_option 'sort', :aliases => '-s', :type => :string, :enum => %w(favorites followers friends listed screen_name since tweets tweeted), :default => 'screen_name', :desc => 'Specify the order of the results.', :banner => 'ORDER'
201
+ method_option 'sort', :aliases => '-s', :type => :string, :enum => %w[favorites followers friends listed screen_name since tweets tweeted], :default => 'screen_name', :desc => 'Specify the order of the results.', :banner => 'ORDER'
198
202
  method_option 'unsorted', :aliases => '-u', :type => :boolean, :default => false, :desc => 'Output is not sorted.'
199
203
  def groupies(user = nil)
200
204
  user = if user
201
- require 't/core_ext/string'
202
- options['id'] ? user.to_i : user.strip_ats
203
- else
204
- client.verify_credentials.screen_name
205
- end
206
- follower_ids = Thread.new do
207
- client.follower_ids(user).to_a
208
- end
209
- following_ids = Thread.new do
210
- client.friend_ids(user).to_a
205
+ require 't/core_ext/string'
206
+ options['id'] ? user.to_i : user.strip_ats
207
+ else
208
+ client.verify_credentials.screen_name
211
209
  end
210
+ follower_ids = Thread.new { client.follower_ids(user).to_a }
211
+ following_ids = Thread.new { client.friend_ids(user).to_a }
212
212
  disciple_ids = (follower_ids.value - following_ids.value)
213
213
  require 'retryable'
214
214
  users = retryable(:tries => 3, :on => Twitter::Error, :sleep => 0) do
@@ -216,7 +216,7 @@ module T
216
216
  end
217
217
  print_users(users)
218
218
  end
219
- map %w(disciples) => :groupies
219
+ map %w[disciples] => :groupies
220
220
 
221
221
  desc 'dm USER MESSAGE', 'Sends that person a Direct Message.'
222
222
  method_option 'id', :aliases => '-i', :type => :boolean, :default => false, :desc => 'Specify user via ID instead of screen name.'
@@ -226,7 +226,7 @@ module T
226
226
  direct_message = client.create_direct_message(user, message)
227
227
  say "Direct Message sent from @#{@rcfile.active_profile[0]} to @#{direct_message.recipient.screen_name}."
228
228
  end
229
- map %w(d m) => :dm
229
+ map %w[d m] => :dm
230
230
 
231
231
  desc 'does_contain [USER/]LIST USER', 'Find out whether a list contains a user.'
232
232
  method_option 'id', :aliases => '-i', :type => :boolean, :default => false, :desc => 'Specify user via ID instead of screen name.'
@@ -241,30 +241,37 @@ module T
241
241
  if client.list_member?(owner, list, user)
242
242
  say "Yes, #{list} contains @#{user}."
243
243
  else
244
- say "No, #{list} does not contain @#{user}."
245
- exit 1
244
+ abort "No, #{list} does not contain @#{user}."
246
245
  end
247
246
  end
248
- map %w(dc doescontain) => :does_contain
247
+ map %w[dc doescontain] => :does_contain
249
248
 
250
249
  desc 'does_follow USER [USER]', 'Find out whether one user follows another.'
251
250
  method_option 'id', :aliases => '-i', :type => :boolean, :default => false, :desc => 'Specify user via ID instead of screen name.'
252
251
  def does_follow(user1, user2 = nil)
253
252
  require 't/core_ext/string'
254
- user1 = options['id'] ? client.user(user1.to_i).screen_name : user1.strip_ats
255
- if user2.nil?
256
- user2 = @rcfile.active_profile[0]
253
+ thread1 = if options['id']
254
+ Thread.new { client.user(user1.to_i).screen_name }
257
255
  else
258
- user2 = options['id'] ? client.user(user2.to_i).screen_name : user2.strip_ats
256
+ Thread.new { user1.strip_ats }
259
257
  end
258
+ thread2 = if user2.nil?
259
+ Thread.new { @rcfile.active_profile[0] }
260
+ else
261
+ if options['id']
262
+ Thread.new { client.user(user2.to_i).screen_name }
263
+ else
264
+ Thread.new { user2.strip_ats }
265
+ end
266
+ end
267
+ user1, user2 = thread1.value, thread2.value
260
268
  if client.friendship?(user1, user2)
261
269
  say "Yes, @#{user1} follows @#{user2}."
262
270
  else
263
- say "No, @#{user1} does not follow @#{user2}."
264
- exit 1
271
+ abort "No, @#{user1} does not follow @#{user2}."
265
272
  end
266
273
  end
267
- map %w(df doesfollow) => :does_follow
274
+ map %w[df doesfollow] => :does_follow
268
275
 
269
276
  desc 'favorite TWEET_ID [TWEET_ID...]', 'Marks Tweets as favorites.'
270
277
  def favorite(status_id, *status_ids)
@@ -279,21 +286,23 @@ module T
279
286
  say
280
287
  say "Run `#{File.basename($PROGRAM_NAME)} delete favorite #{status_ids.join(' ')}` to unfavorite."
281
288
  end
282
- map %w(fave favourite) => :favorite
289
+ map %w[fave favourite] => :favorite
283
290
 
284
291
  desc 'favorites [USER]', "Returns the #{DEFAULT_NUM_RESULTS} most recent Tweets you favorited."
285
292
  method_option 'csv', :aliases => '-c', :type => :boolean, :default => false, :desc => 'Output in CSV format.'
293
+ method_option 'decode_uris', :aliases => '-d', :type => :boolean, :default => false, :desc => 'Decodes t.co URLs into their original form.'
286
294
  method_option 'id', :aliases => '-i', :type => :boolean, :default => false, :desc => 'Specify user via ID instead of screen name.'
287
295
  method_option 'long', :aliases => '-l', :type => :boolean, :default => false, :desc => 'Output in long format.'
288
- method_option 'relative_dates', :aliases => '-a', :type => :boolean, :desc => 'Show relative dates.'
289
296
  method_option 'max_id', :aliases => '-m', :type => :numeric, :desc => 'Returns only the results with an ID less than the specified ID.'
290
297
  method_option 'number', :aliases => '-n', :type => :numeric, :default => DEFAULT_NUM_RESULTS, :desc => 'Limit the number of results.'
298
+ method_option 'relative_dates', :aliases => '-a', :type => :boolean, :desc => 'Show relative dates.'
291
299
  method_option 'reverse', :aliases => '-r', :type => :boolean, :default => false, :desc => 'Reverse the order of the sort.'
292
300
  method_option 'since_id', :aliases => '-s', :type => :numeric, :desc => 'Returns only the results with an ID greater than the specified ID.'
293
301
  def favorites(user = nil)
294
302
  count = options['number'] || DEFAULT_NUM_RESULTS
295
303
  opts = {}
296
304
  opts[:exclude_replies] = true if options['exclude'] == 'replies'
305
+ opts[:include_entities] = !!options['decode_uris']
297
306
  opts[:include_rts] = false if options['exclude'] == 'retweets'
298
307
  opts[:max_id] = options['max_id'] if options['max_id']
299
308
  opts[:since_id] = options['since_id'] if options['since_id']
@@ -306,7 +315,7 @@ module T
306
315
  end
307
316
  print_tweets(tweets)
308
317
  end
309
- map %w(faves favourites) => :favorites
318
+ map %w[faves favourites] => :favorites
310
319
 
311
320
  desc 'follow USER [USER...]', 'Allows you to start following users.'
312
321
  method_option 'id', :aliases => '-i', :type => :boolean, :default => false, :desc => 'Specify input as Twitter user IDs instead of screen names.'
@@ -325,7 +334,7 @@ module T
325
334
  method_option 'long', :aliases => '-l', :type => :boolean, :default => false, :desc => 'Output in long format.'
326
335
  method_option 'relative_dates', :aliases => '-a', :type => :boolean, :desc => 'Show relative dates.'
327
336
  method_option 'reverse', :aliases => '-r', :type => :boolean, :default => false, :desc => 'Reverse the order of the sort.'
328
- method_option 'sort', :aliases => '-s', :type => :string, :enum => %w(favorites followers friends listed screen_name since tweets tweeted), :default => 'screen_name', :desc => 'Specify the order of the results.', :banner => 'ORDER'
337
+ method_option 'sort', :aliases => '-s', :type => :string, :enum => %w[favorites followers friends listed screen_name since tweets tweeted], :default => 'screen_name', :desc => 'Specify the order of the results.', :banner => 'ORDER'
329
338
  method_option 'unsorted', :aliases => '-u', :type => :boolean, :default => false, :desc => 'Output is not sorted.'
330
339
  def followings(user = nil)
331
340
  if user
@@ -346,7 +355,7 @@ module T
346
355
  method_option 'long', :aliases => '-l', :type => :boolean, :default => false, :desc => 'Output in long format.'
347
356
  method_option 'relative_dates', :aliases => '-a', :type => :boolean, :desc => 'Show relative dates.'
348
357
  method_option 'reverse', :aliases => '-r', :type => :boolean, :default => false, :desc => 'Reverse the order of the sort.'
349
- method_option 'sort', :aliases => '-s', :type => :string, :enum => %w(favorites followers friends listed screen_name since tweets tweeted), :default => 'screen_name', :desc => 'Specify the order of the results.', :banner => 'ORDER'
358
+ method_option 'sort', :aliases => '-s', :type => :string, :enum => %w[favorites followers friends listed screen_name since tweets tweeted], :default => 'screen_name', :desc => 'Specify the order of the results.', :banner => 'ORDER'
350
359
  method_option 'unsorted', :aliases => '-u', :type => :boolean, :default => false, :desc => 'Output is not sorted.'
351
360
  def followers(user = nil)
352
361
  if user
@@ -367,21 +376,17 @@ module T
367
376
  method_option 'long', :aliases => '-l', :type => :boolean, :default => false, :desc => 'Output in long format.'
368
377
  method_option 'relative_dates', :aliases => '-a', :type => :boolean, :desc => 'Show relative dates.'
369
378
  method_option 'reverse', :aliases => '-r', :type => :boolean, :default => false, :desc => 'Reverse the order of the sort.'
370
- method_option 'sort', :aliases => '-s', :type => :string, :enum => %w(favorites followers friends listed screen_name since tweets tweeted), :default => 'screen_name', :desc => 'Specify the order of the results.', :banner => 'ORDER'
379
+ method_option 'sort', :aliases => '-s', :type => :string, :enum => %w[favorites followers friends listed screen_name since tweets tweeted], :default => 'screen_name', :desc => 'Specify the order of the results.', :banner => 'ORDER'
371
380
  method_option 'unsorted', :aliases => '-u', :type => :boolean, :default => false, :desc => 'Output is not sorted.'
372
381
  def friends(user = nil)
373
382
  user = if user
374
- require 't/core_ext/string'
375
- options['id'] ? user.to_i : user.strip_ats
376
- else
377
- client.verify_credentials.screen_name
378
- end
379
- following_ids = Thread.new do
380
- client.friend_ids(user).to_a
381
- end
382
- follower_ids = Thread.new do
383
- client.follower_ids(user).to_a
383
+ require 't/core_ext/string'
384
+ options['id'] ? user.to_i : user.strip_ats
385
+ else
386
+ client.verify_credentials.screen_name
384
387
  end
388
+ following_ids = Thread.new { client.friend_ids(user).to_a }
389
+ follower_ids = Thread.new { client.follower_ids(user).to_a }
385
390
  friend_ids = (following_ids.value & follower_ids.value)
386
391
  require 'retryable'
387
392
  users = retryable(:tries => 3, :on => Twitter::Error, :sleep => 0) do
@@ -396,21 +401,17 @@ module T
396
401
  method_option 'long', :aliases => '-l', :type => :boolean, :default => false, :desc => 'Output in long format.'
397
402
  method_option 'relative_dates', :aliases => '-a', :type => :boolean, :desc => 'Show relative dates.'
398
403
  method_option 'reverse', :aliases => '-r', :type => :boolean, :default => false, :desc => 'Reverse the order of the sort.'
399
- method_option 'sort', :aliases => '-s', :type => :string, :enum => %w(favorites followers friends listed screen_name since tweets tweeted), :default => 'screen_name', :desc => 'Specify the order of the results.', :banner => 'ORDER'
404
+ method_option 'sort', :aliases => '-s', :type => :string, :enum => %w[favorites followers friends listed screen_name since tweets tweeted], :default => 'screen_name', :desc => 'Specify the order of the results.', :banner => 'ORDER'
400
405
  method_option 'unsorted', :aliases => '-u', :type => :boolean, :default => false, :desc => 'Output is not sorted.'
401
406
  def leaders(user = nil)
402
407
  user = if user
403
- require 't/core_ext/string'
404
- options['id'] ? user.to_i : user.strip_ats
405
- else
406
- client.verify_credentials.screen_name
407
- end
408
- following_ids = Thread.new do
409
- client.friend_ids(user).to_a
410
- end
411
- follower_ids = Thread.new do
412
- client.follower_ids(user).to_a
408
+ require 't/core_ext/string'
409
+ options['id'] ? user.to_i : user.strip_ats
410
+ else
411
+ client.verify_credentials.screen_name
413
412
  end
413
+ following_ids = Thread.new { client.friend_ids(user).to_a }
414
+ follower_ids = Thread.new { client.follower_ids(user).to_a }
414
415
  leader_ids = (following_ids.value - follower_ids.value)
415
416
  require 'retryable'
416
417
  users = retryable(:tries => 3, :on => Twitter::Error, :sleep => 0) do
@@ -425,16 +426,16 @@ module T
425
426
  method_option 'long', :aliases => '-l', :type => :boolean, :default => false, :desc => 'Output in long format.'
426
427
  method_option 'relative_dates', :aliases => '-a', :type => :boolean, :desc => 'Show relative dates.'
427
428
  method_option 'reverse', :aliases => '-r', :type => :boolean, :default => false, :desc => 'Reverse the order of the sort.'
428
- method_option 'sort', :aliases => '-s', :type => :string, :enum => %w(members mode since slug subscribers), :default => 'slug', :desc => 'Specify the order of the results.', :banner => 'ORDER'
429
+ method_option 'sort', :aliases => '-s', :type => :string, :enum => %w[members mode since slug subscribers], :default => 'slug', :desc => 'Specify the order of the results.', :banner => 'ORDER'
429
430
  method_option 'unsorted', :aliases => '-u', :type => :boolean, :default => false, :desc => 'Output is not sorted.'
430
431
  def lists(user = nil)
431
432
  lists = if user
432
- require 't/core_ext/string'
433
- user = options['id'] ? user.to_i : user.strip_ats
434
- client.lists(user)
435
- else
436
- client.lists
437
- end
433
+ require 't/core_ext/string'
434
+ user = options['id'] ? user.to_i : user.strip_ats
435
+ client.lists(user)
436
+ else
437
+ client.lists
438
+ end
438
439
  print_lists(lists)
439
440
  end
440
441
 
@@ -443,18 +444,21 @@ module T
443
444
 
444
445
  desc 'mentions', "Returns the #{DEFAULT_NUM_RESULTS} most recent Tweets mentioning you."
445
446
  method_option 'csv', :aliases => '-c', :type => :boolean, :default => false, :desc => 'Output in CSV format.'
447
+ method_option 'decode_uris', :aliases => '-d', :type => :boolean, :default => false, :desc => 'Decodes t.co URLs into their original form.'
446
448
  method_option 'long', :aliases => '-l', :type => :boolean, :default => false, :desc => 'Output in long format.'
447
- method_option 'relative_dates', :aliases => '-a', :type => :boolean, :desc => 'Show relative dates.'
448
449
  method_option 'number', :aliases => '-n', :type => :numeric, :default => DEFAULT_NUM_RESULTS, :desc => 'Limit the number of results.'
450
+ method_option 'relative_dates', :aliases => '-a', :type => :boolean, :desc => 'Show relative dates.'
449
451
  method_option 'reverse', :aliases => '-r', :type => :boolean, :default => false, :desc => 'Reverse the order of the sort.'
450
452
  def mentions
451
453
  count = options['number'] || DEFAULT_NUM_RESULTS
454
+ opts = {}
455
+ opts[:include_entities] = !!options['decode_uris']
452
456
  tweets = collect_with_count(count) do |count_opts|
453
- client.mentions(count_opts)
457
+ client.mentions(count_opts.merge(opts))
454
458
  end
455
459
  print_tweets(tweets)
456
460
  end
457
- map %w(replies) => :mentions
461
+ map %w[replies] => :mentions
458
462
 
459
463
  desc 'open USER', "Opens that user's profile in a web browser."
460
464
  method_option 'display-uri', :aliases => '-d', :type => :boolean, :default => false, :desc => 'Display the requested URL instead of attempting to open it.'
@@ -502,7 +506,7 @@ module T
502
506
  end
503
507
  say "@#{@rcfile.active_profile[0]} reported #{pluralize(number, 'user')}."
504
508
  end
505
- map %w(report reportspam spam) => :report_spam
509
+ map %w[report reportspam spam] => :report_spam
506
510
 
507
511
  desc 'retweet TWEET_ID [TWEET_ID...]', 'Sends Tweets to your followers.'
508
512
  def retweet(status_id, *status_ids)
@@ -517,31 +521,34 @@ module T
517
521
  say
518
522
  say "Run `#{File.basename($PROGRAM_NAME)} delete status #{retweets.map { |tweet| tweet.retweeted_status.id }.join(' ')}` to undo."
519
523
  end
520
- map %w(rt) => :retweet
524
+ map %w[rt] => :retweet
521
525
 
522
526
  desc 'retweets [USER]', "Returns the #{DEFAULT_NUM_RESULTS} most recent Retweets by a user."
523
527
  method_option 'csv', :aliases => '-c', :type => :boolean, :default => false, :desc => 'Output in CSV format.'
528
+ method_option 'decode_uris', :aliases => '-d', :type => :boolean, :default => false, :desc => 'Decodes t.co URLs into their original form.'
524
529
  method_option 'id', :aliases => '-i', :type => :boolean, :default => false, :desc => 'Specify user via ID instead of screen name.'
525
530
  method_option 'long', :aliases => '-l', :type => :boolean, :default => false, :desc => 'Output in long format.'
526
- method_option 'relative_dates', :aliases => '-a', :type => :boolean, :desc => 'Show relative dates.'
527
531
  method_option 'number', :aliases => '-n', :type => :numeric, :default => DEFAULT_NUM_RESULTS, :desc => 'Limit the number of results.'
532
+ method_option 'relative_dates', :aliases => '-a', :type => :boolean, :desc => 'Show relative dates.'
528
533
  method_option 'reverse', :aliases => '-r', :type => :boolean, :default => false, :desc => 'Reverse the order of the sort.'
529
534
  def retweets(user = nil)
530
535
  count = options['number'] || DEFAULT_NUM_RESULTS
536
+ opts = {}
537
+ opts[:include_entities] = !!options['decode_uris']
531
538
  tweets = if user
532
- require 't/core_ext/string'
533
- user = options['id'] ? user.to_i : user.strip_ats
534
- collect_with_count(count) do |count_opts|
535
- client.retweeted_by_user(user, count_opts)
536
- end
537
- else
538
- collect_with_count(count) do |count_opts|
539
- client.retweeted_by_me(count_opts)
540
- end
541
- end
539
+ require 't/core_ext/string'
540
+ user = options['id'] ? user.to_i : user.strip_ats
541
+ collect_with_count(count) do |count_opts|
542
+ client.retweeted_by_user(user, count_opts.merge(opts))
543
+ end
544
+ else
545
+ collect_with_count(count) do |count_opts|
546
+ client.retweeted_by_me(count_opts.merge(opts))
547
+ end
548
+ end
542
549
  print_tweets(tweets)
543
550
  end
544
- map %w(rts) => :retweets
551
+ map %w[rts] => :retweets
545
552
 
546
553
  desc 'ruler', 'Prints a 140-character ruler'
547
554
  method_option 'indent', :aliases => '-i', :type => :numeric, :default => 0, :desc => 'The number of space to print before the ruler.'
@@ -552,40 +559,43 @@ module T
552
559
 
553
560
  desc 'status TWEET_ID', 'Retrieves detailed information about a Tweet.'
554
561
  method_option 'csv', :aliases => '-c', :type => :boolean, :default => false, :desc => 'Output in CSV format.'
562
+ method_option 'decode_uris', :aliases => '-d', :type => :boolean, :default => false, :desc => 'Decodes t.co URLs into their original form.'
555
563
  method_option 'long', :aliases => '-l', :type => :boolean, :default => false, :desc => 'Output in long format.'
556
564
  method_option 'relative_dates', :aliases => '-a', :type => :boolean, :desc => 'Show relative dates.'
557
565
  def status(status_id) # rubocop:disable CyclomaticComplexity
558
- status = client.status(status_id.to_i, :include_my_retweet => false)
566
+ opts = {:include_my_retweet => false}
567
+ opts[:include_entities] = !!options['decode_uris']
568
+ status = client.status(status_id.to_i, opts)
559
569
  location = if status.place?
560
- if status.place.name && status.place.attributes && status.place.attributes[:street_address] && status.place.attributes[:locality] && status.place.attributes[:region] && status.place.country
561
- [status.place.name, status.place.attributes[:street_address], status.place.attributes[:locality], status.place.attributes[:region], status.place.country].join(', ')
562
- elsif status.place.name && status.place.attributes && status.place.attributes[:locality] && status.place.attributes[:region] && status.place.country
563
- [status.place.name, status.place.attributes[:locality], status.place.attributes[:region], status.place.country].join(', ')
564
- elsif status.place.full_name && status.place.attributes && status.place.attributes[:region] && status.place.country
565
- [status.place.full_name, status.place.attributes[:region], status.place.country].join(', ')
566
- elsif status.place.full_name && status.place.country
567
- [status.place.full_name, status.place.country].join(', ')
568
- elsif status.place.full_name
569
- status.place.full_name
570
- else
571
- status.place.name
572
- end
573
- elsif status.geo?
574
- reverse_geocode(status.geo)
575
- end
570
+ if status.place.name && status.place.attributes && status.place.attributes[:street_address] && status.place.attributes[:locality] && status.place.attributes[:region] && status.place.country
571
+ [status.place.name, status.place.attributes[:street_address], status.place.attributes[:locality], status.place.attributes[:region], status.place.country].join(', ')
572
+ elsif status.place.name && status.place.attributes && status.place.attributes[:locality] && status.place.attributes[:region] && status.place.country
573
+ [status.place.name, status.place.attributes[:locality], status.place.attributes[:region], status.place.country].join(', ')
574
+ elsif status.place.full_name && status.place.attributes && status.place.attributes[:region] && status.place.country
575
+ [status.place.full_name, status.place.attributes[:region], status.place.country].join(', ')
576
+ elsif status.place.full_name && status.place.country
577
+ [status.place.full_name, status.place.country].join(', ')
578
+ elsif status.place.full_name
579
+ status.place.full_name
580
+ else
581
+ status.place.name
582
+ end
583
+ elsif status.geo?
584
+ reverse_geocode(status.geo)
585
+ end
576
586
  status_headings = ['ID', 'Posted at', 'Screen name', 'Text', 'Retweets', 'Favorites', 'Source', 'Location']
577
587
  if options['csv']
578
588
  require 'csv'
579
589
  say status_headings.to_csv
580
- say [status.id, csv_formatted_time(status), status.user.screen_name, decode_full_text(status), status.retweet_count, status.favorite_count, strip_tags(status.source), location].to_csv
590
+ say [status.id, csv_formatted_time(status), status.user.screen_name, decode_full_text(status, options['decode_uris']), status.retweet_count, status.favorite_count, strip_tags(status.source), location].to_csv
581
591
  elsif options['long']
582
- array = [status.id, ls_formatted_time(status), "@#{status.user.screen_name}", decode_full_text(status).gsub(/\n+/, ' '), status.retweet_count, status.favorite_count, strip_tags(status.source), location]
592
+ array = [status.id, ls_formatted_time(status), "@#{status.user.screen_name}", decode_full_text(status, options['decode_uris']).gsub(/\n+/, ' '), status.retweet_count, status.favorite_count, strip_tags(status.source), location]
583
593
  format = options['format'] || status_headings.size.times.map { '%s' }
584
594
  print_table_with_headings([array], status_headings, format)
585
595
  else
586
596
  array = []
587
597
  array << ['ID', status.id.to_s]
588
- array << ['Text', decode_full_text(status).gsub(/\n+/, ' ')]
598
+ array << ['Text', decode_full_text(status, options['decode_uris']).gsub(/\n+/, ' ')]
589
599
  array << ['Screen name', "@#{status.user.screen_name}"]
590
600
  array << ['Posted at', "#{ls_formatted_time(status, :created_at, false)} (#{time_ago_in_words(status.created_at)} ago)"]
591
601
  array << ['Retweets', number_with_delimiter(status.retweet_count)]
@@ -598,18 +608,20 @@ module T
598
608
 
599
609
  desc 'timeline [USER]', "Returns the #{DEFAULT_NUM_RESULTS} most recent Tweets posted by a user."
600
610
  method_option 'csv', :aliases => '-c', :type => :boolean, :default => false, :desc => 'Output in CSV format.'
601
- method_option 'exclude', :aliases => '-e', :type => :string, :enum => %w(replies retweets), :desc => 'Exclude certain types of Tweets from the results.', :banner => 'TYPE'
611
+ method_option 'decode_uris', :aliases => '-d', :type => :boolean, :default => false, :desc => 'Decodes t.co URLs into their original form.'
612
+ method_option 'exclude', :aliases => '-e', :type => :string, :enum => %w[replies retweets], :desc => 'Exclude certain types of Tweets from the results.', :banner => 'TYPE'
602
613
  method_option 'id', :aliases => '-i', :type => :boolean, :default => false, :desc => 'Specify user via ID instead of screen name.'
603
614
  method_option 'long', :aliases => '-l', :type => :boolean, :default => false, :desc => 'Output in long format.'
604
- method_option 'relative_dates', :aliases => '-a', :type => :boolean, :desc => 'Show relative dates.'
605
615
  method_option 'max_id', :aliases => '-m', :type => :numeric, :desc => 'Returns only the results with an ID less than the specified ID.'
606
616
  method_option 'number', :aliases => '-n', :type => :numeric, :default => DEFAULT_NUM_RESULTS, :desc => 'Limit the number of results.'
617
+ method_option 'relative_dates', :aliases => '-a', :type => :boolean, :desc => 'Show relative dates.'
607
618
  method_option 'reverse', :aliases => '-r', :type => :boolean, :default => false, :desc => 'Reverse the order of the sort.'
608
619
  method_option 'since_id', :aliases => '-s', :type => :numeric, :desc => 'Returns only the results with an ID greater than the specified ID.'
609
620
  def timeline(user = nil)
610
621
  count = options['number'] || DEFAULT_NUM_RESULTS
611
622
  opts = {}
612
623
  opts[:exclude_replies] = true if options['exclude'] == 'replies'
624
+ opts[:include_entities] = !!options['decode_uris']
613
625
  opts[:include_rts] = false if options['exclude'] == 'retweets'
614
626
  opts[:max_id] = options['max_id'] if options['max_id']
615
627
  opts[:since_id] = options['since_id'] if options['since_id']
@@ -626,7 +638,7 @@ module T
626
638
  end
627
639
  print_tweets(tweets)
628
640
  end
629
- map %w(tl) => :timeline
641
+ map %w[tl] => :timeline
630
642
 
631
643
  desc 'trends [WOEID]', 'Returns the top 10 trending topics.'
632
644
  method_option 'exclude-hashtags', :aliases => '-x', :type => :boolean, :default => false, :desc => 'Remove all hashtags from the trends list.'
@@ -642,22 +654,22 @@ module T
642
654
  method_option 'long', :aliases => '-l', :type => :boolean, :default => false, :desc => 'Output in long format.'
643
655
  method_option 'relative_dates', :aliases => '-a', :type => :boolean, :desc => 'Show relative dates.'
644
656
  method_option 'reverse', :aliases => '-r', :type => :boolean, :default => false, :desc => 'Reverse the order of the sort.'
645
- method_option 'sort', :aliases => '-s', :type => :string, :enum => %w(country name parent type woeid), :default => 'name', :desc => 'Specify the order of the results.', :banner => 'ORDER'
657
+ method_option 'sort', :aliases => '-s', :type => :string, :enum => %w[country name parent type woeid], :default => 'name', :desc => 'Specify the order of the results.', :banner => 'ORDER'
646
658
  method_option 'unsorted', :aliases => '-u', :type => :boolean, :default => false, :desc => 'Output is not sorted.'
647
659
  def trend_locations
648
660
  places = client.trend_locations
649
661
  places = case options['sort']
650
- when 'country'
651
- places.sort_by { |place| place.country.downcase }
652
- when 'parent'
653
- places.sort_by { |place| place.parent_id.to_i }
654
- when 'type'
655
- places.sort_by { |place| place.place_type.downcase }
656
- when 'woeid'
657
- places.sort_by { |place| place.woeid.to_i }
658
- else
659
- places.sort_by { |place| place.name.downcase }
660
- end unless options['unsorted']
662
+ when 'country'
663
+ places.sort_by { |place| place.country.downcase }
664
+ when 'parent'
665
+ places.sort_by { |place| place.parent_id.to_i }
666
+ when 'type'
667
+ places.sort_by { |place| place.place_type.downcase }
668
+ when 'woeid'
669
+ places.sort_by { |place| place.woeid.to_i }
670
+ else
671
+ places.sort_by { |place| place.name.downcase }
672
+ end unless options['unsorted']
661
673
  places.reverse! if options['reverse']
662
674
  if options['csv']
663
675
  require 'csv'
@@ -675,7 +687,7 @@ module T
675
687
  print_attribute(places, :name)
676
688
  end
677
689
  end
678
- map %w(locations trendlocations) => :trend_locations
690
+ map %w[locations trendlocations] => :trend_locations
679
691
 
680
692
  desc 'unfollow USER [USER...]', 'Allows you to stop following users.'
681
693
  method_option 'id', :aliases => '-i', :type => :boolean, :default => false, :desc => 'Specify input as Twitter user IDs instead of screen names.'
@@ -695,17 +707,16 @@ module T
695
707
  message = T::Editor.gets if message.nil? || message.empty?
696
708
  opts = {:trim_user => true}
697
709
  add_location!(options, opts)
698
-
699
710
  status = if options['file']
700
- client.update_with_media(message, File.new(File.expand_path(options['file'])), opts)
701
- else
702
- client.update(message, opts)
703
- end
711
+ client.update_with_media(message, File.new(File.expand_path(options['file'])), opts)
712
+ else
713
+ client.update(message, opts)
714
+ end
704
715
  say "Tweet posted by @#{@rcfile.active_profile[0]}."
705
716
  say
706
717
  say "Run `#{File.basename($PROGRAM_NAME)} delete status #{status.id}` to delete."
707
718
  end
708
- map %w(post tweet) => :update
719
+ map %w[post tweet] => :update
709
720
 
710
721
  desc 'users USER [USER...]', 'Returns a list of users you specify.'
711
722
  method_option 'csv', :aliases => '-c', :type => :boolean, :default => false, :desc => 'Output in CSV format.'
@@ -713,7 +724,7 @@ module T
713
724
  method_option 'long', :aliases => '-l', :type => :boolean, :default => false, :desc => 'Output in long format.'
714
725
  method_option 'relative_dates', :aliases => '-a', :type => :boolean, :desc => 'Show relative dates.'
715
726
  method_option 'reverse', :aliases => '-r', :type => :boolean, :default => false, :desc => 'Reverse the order of the sort.'
716
- method_option 'sort', :aliases => '-s', :type => :string, :enum => %w(favorites followers friends listed screen_name since tweets tweeted), :default => 'screen_name', :desc => 'Specify the order of the results.', :banner => 'ORDER'
727
+ method_option 'sort', :aliases => '-s', :type => :string, :enum => %w[favorites followers friends listed screen_name since tweets tweeted], :default => 'screen_name', :desc => 'Specify the order of the results.', :banner => 'ORDER'
717
728
  method_option 'unsorted', :aliases => '-u', :type => :boolean, :default => false, :desc => 'Output is not sorted.'
718
729
  def users(user, *users)
719
730
  users.unshift(user)
@@ -722,32 +733,34 @@ module T
722
733
  users = client.users(users)
723
734
  print_users(users)
724
735
  end
725
- map %w(stats) => :users
736
+ map %w[stats] => :users
726
737
 
727
738
  desc 'version', 'Show version.'
728
739
  def version
729
740
  require 't/version'
730
741
  say T::Version
731
742
  end
732
- map %w(-v --version) => :version
743
+ map %w[-v --version] => :version
733
744
 
734
745
  desc 'whois USER', 'Retrieves profile information for the user.'
735
746
  method_option 'csv', :aliases => '-c', :type => :boolean, :default => false, :desc => 'Output in CSV format.'
747
+ method_option 'decode_uris', :aliases => '-d', :type => :boolean, :default => false, :desc => 'Decodes t.co URLs into their original form.'
736
748
  method_option 'id', :aliases => '-i', :type => :boolean, :default => false, :desc => 'Specify user via ID instead of screen name.'
737
749
  method_option 'long', :aliases => '-l', :type => :boolean, :default => false, :desc => 'Output in long format.'
738
750
  method_option 'relative_dates', :aliases => '-a', :type => :boolean, :desc => 'Show relative dates.'
739
751
  def whois(user) # rubocop:disable CyclomaticComplexity
740
752
  require 't/core_ext/string'
753
+ opts = {}
754
+ opts[:include_entities] = !!options['decode_uris']
741
755
  user = options['id'] ? user.to_i : user.strip_ats
742
- user = client.user(user)
743
- require 'htmlentities'
756
+ user = client.user(user, opts)
744
757
  if options['csv'] || options['long']
745
758
  print_users([user])
746
759
  else
747
760
  array = []
748
761
  array << ['ID', user.id.to_s]
749
762
  array << ['Since', "#{ls_formatted_time(user, :created_at, false)} (#{time_ago_in_words(user.created_at)} ago)"]
750
- array << ['Last update', "#{decode_full_text(user.status).gsub(/\n+/, ' ')} (#{time_ago_in_words(user.status.created_at)} ago)"] unless user.status.nil?
763
+ array << ['Last update', "#{decode_full_text(user.status, options['decode_uris']).gsub(/\n+/, ' ')} (#{time_ago_in_words(user.status.created_at)} ago)"] unless user.status.nil?
751
764
  array << ['Screen name', "@#{user.screen_name}"]
752
765
  array << [user.verified ? 'Name (Verified)' : 'Name', user.name] unless user.name.nil?
753
766
  array << ['Tweets', number_with_delimiter(user.statuses_count)]
@@ -761,7 +774,7 @@ module T
761
774
  print_table(array)
762
775
  end
763
776
  end
764
- map %w(user) => :whois
777
+ map %w[user] => :whois
765
778
 
766
779
  desc 'delete SUBCOMMAND ...ARGS', 'Delete Tweets, Direct Messages, etc.'
767
780
  subcommand 'delete', T::Delete