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 +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/README.md +1 -0
- data/bin/t +4 -9
- data/lib/t.rb +7 -7
- data/lib/t/cli.rb +148 -135
- data/lib/t/collectable.rb +1 -1
- data/lib/t/delete.rb +3 -3
- data/lib/t/list.rb +7 -4
- data/lib/t/printable.rb +29 -30
- data/lib/t/search.rb +18 -19
- data/lib/t/set.rb +3 -3
- data/lib/t/stream.rb +2 -2
- data/lib/t/utils.rb +4 -4
- data/lib/t/version.rb +6 -21
- data/spec/cli_spec.rb +257 -182
- data/spec/fixtures/geo.json +414 -0
- data/spec/fixtures/geo_no_city.json +344 -0
- data/spec/fixtures/geo_no_state.json +299 -0
- data/spec/helper.rb +1 -1
- data/spec/list_spec.rb +25 -11
- data/spec/search_spec.rb +107 -107
- data/spec/stream_spec.rb +15 -15
- data/t.gemspec +13 -13
- metadata +65 -82
- metadata.gz.sig +0 -0
- data/spec/fixtures/geo.kml +0 -64
- data/spec/fixtures/geo_no_city.kml +0 -24
- data/spec/fixtures/geo_no_state.kml +0 -16
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
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') {
|
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
|
-
|
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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
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,
|
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}",
|
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
|
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,
|
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}",
|
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
|
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
|
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
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
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
|
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
|
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
|
-
|
245
|
-
exit 1
|
244
|
+
abort "No, #{list} does not contain @#{user}."
|
246
245
|
end
|
247
246
|
end
|
248
|
-
map %w
|
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
|
-
|
255
|
-
|
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
|
-
|
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
|
-
|
264
|
-
exit 1
|
271
|
+
abort "No, @#{user1} does not follow @#{user2}."
|
265
272
|
end
|
266
273
|
end
|
267
|
-
map %w
|
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
|
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
|
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
|
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
|
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
|
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
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
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
|
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
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
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
|
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
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
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
|
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
|
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
|
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
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
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
|
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
|
-
|
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
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
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 '
|
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
|
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
|
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
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
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
|
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
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
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
|
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
|
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
|
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
|
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
|
777
|
+
map %w[user] => :whois
|
765
778
|
|
766
779
|
desc 'delete SUBCOMMAND ...ARGS', 'Delete Tweets, Direct Messages, etc.'
|
767
780
|
subcommand 'delete', T::Delete
|