t 2.9.0 → 2.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.md +1 -1
- data/README.md +17 -14
- data/bin/t +2 -5
- data/lib/t/cli.rb +25 -27
- data/lib/t/collectable.rb +2 -2
- data/lib/t/core_ext/string.rb +1 -1
- data/lib/t/delete.rb +5 -8
- data/lib/t/identicon.rb +1 -1
- data/lib/t/list.rb +1 -1
- data/lib/t/printable.rb +9 -11
- data/lib/t/rcfile.rb +3 -3
- data/lib/t/search.rb +1 -1
- data/lib/t/stream.rb +3 -3
- data/lib/t/utils.rb +2 -2
- data/lib/t/version.rb +1 -1
- data/t.gemspec +2 -3
- metadata +10 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a26d91bbbf1248998297b1ca780c2b60c18749cc
|
4
|
+
data.tar.gz: b525d7aebabfa57f79f05af951d3eca545daee8c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f7ccdf367adc9c47042a52f822e6f7b5f12d22fb4dffece434f70cc1d968d6d842dffcab8fe5807e0288cb7310aa54840fa3037978c067ba158d0fe4375960e4
|
7
|
+
data.tar.gz: 6d4fd9b61299729e4bbfc2889ae3cd6817b17c0588f86f8b091abd633e058abedf1aaf68ae2dcb57285d8f06217eef71a748423da8dc9b89dfcde28224bf8af0
|
data/LICENSE.md
CHANGED
data/README.md
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
[icon]: https://github.com/sferik/t/raw/master/icon/t.png
|
3
3
|
|
4
4
|
# Twitter CLI
|
5
|
-
[![Gem Version](
|
6
|
-
[![Build Status](
|
7
|
-
[![Dependency Status](
|
8
|
-
[![Coverage Status](
|
5
|
+
[![Gem Version](https://img.shields.io/gem/v/t.svg)][gem]
|
6
|
+
[![Build Status](https://img.shields.io/travis/sferik/t.svg)][travis]
|
7
|
+
[![Dependency Status](https://img.shields.io/gemnasium/sferik/t.svg)][gemnasium]
|
8
|
+
[![Coverage Status](https://img.shields.io/coveralls/sferik/t.svg)][coveralls]
|
9
9
|
[![tip for next commit](https://tip4commit.com/projects/102.svg)](https://tip4commit.com/github/sferik/t)
|
10
10
|
|
11
11
|
[gem]: https://rubygems.org/gems/t
|
12
|
-
[travis]:
|
12
|
+
[travis]: https://travis-ci.org/sferik/t
|
13
13
|
[gemnasium]: https://gemnasium.com/sferik/t
|
14
14
|
[coveralls]: https://coveralls.io/r/sferik/t
|
15
15
|
|
@@ -19,7 +19,7 @@ offers vastly more commands and capabilities than are available via SMS.
|
|
19
19
|
|
20
20
|
[sms]: https://support.twitter.com/articles/14020-twitter-sms-command
|
21
21
|
|
22
|
-
##
|
22
|
+
## Dependencies
|
23
23
|
First, make sure you have Ruby installed.
|
24
24
|
|
25
25
|
**On a Mac**, open `/Applications/Utilities/Terminal.app` and type:
|
@@ -31,7 +31,7 @@ If the output looks something like this, you're in good shape:
|
|
31
31
|
ruby 1.9.3p484 (2013-11-22 revision 43786) [x86_64-darwin13.0.0]
|
32
32
|
|
33
33
|
If the output looks more like this, you need to [install Ruby][ruby]:
|
34
|
-
[ruby]:
|
34
|
+
[ruby]: https://www.ruby-lang.org/en/downloads/
|
35
35
|
|
36
36
|
ruby: command not found
|
37
37
|
|
@@ -48,6 +48,7 @@ or for Red Hat-based distros like Fedora and CentOS, type:
|
|
48
48
|
**On Windows**, you can install Ruby with [RubyInstaller][].
|
49
49
|
[rubyinstaller]: http://rubyinstaller.org/downloads/
|
50
50
|
|
51
|
+
## Installation
|
51
52
|
Once you've verified that Ruby is installed:
|
52
53
|
|
53
54
|
gem install t
|
@@ -56,9 +57,9 @@ Once you've verified that Ruby is installed:
|
|
56
57
|
Twitter API v1.1 requires OAuth for all of its functionality, so you'll need a
|
57
58
|
registered Twitter application. If you've never registered a Twitter
|
58
59
|
application before, it's easy! Just sign-in using your Twitter account and then
|
59
|
-
fill out the short form at <
|
60
|
+
fill out the short form at <https://apps.twitter.com/app/new>. If you've
|
60
61
|
previously registered a Twitter application, it should be listed at
|
61
|
-
<
|
62
|
+
<https://apps.twitter.com/>. Once you've registered an application, make sure
|
62
63
|
to set your application's Access Level to "Read, Write and Access direct
|
63
64
|
messages", otherwise you'll receive an error that looks like this:
|
64
65
|
|
@@ -77,6 +78,8 @@ terminal. If you type the PIN correctly, you should now be authorized to use
|
|
77
78
|
`t` as that user. To authorize multiple accounts, simply repeat the last step,
|
78
79
|
signing into Twitter as a different user.
|
79
80
|
|
81
|
+
**NOTE**: If you have problems authorizing multiple accounts, open a new window in your browser in incognito/private-browsing mode and repeat the `t authorize` steps. This is apparently due to a bug in twitter's cookie handling.
|
82
|
+
|
80
83
|
You can see a list of all the accounts you've authorized by typing the command:
|
81
84
|
|
82
85
|
t accounts
|
@@ -212,7 +215,7 @@ example, here's how to send a user a direct message only if they already follow
|
|
212
215
|
by adding the `--csv` flag.
|
213
216
|
* 95% C0 Code Coverage: Well tested, with a 2.5:1 test-to-code ratio.
|
214
217
|
|
215
|
-
[search]: https://dev.twitter.com/
|
218
|
+
[search]: https://dev.twitter.com/rest/public/search
|
216
219
|
|
217
220
|
## Using T for Backup
|
218
221
|
[@jphpsf][jphpsf] wrote a [blog post][blog] explaining how to use `t` to backup
|
@@ -225,9 +228,9 @@ your Twitter account.
|
|
225
228
|
|
226
229
|
`t` was also discussed on [an episode of the Ruby Rogues podcast][rubyrogues].
|
227
230
|
|
228
|
-
[ruby5]:
|
231
|
+
[ruby5]: https://ruby5.codeschool.com/episodes/273-episode-269-may-4th-2012/stories/2400-t-command-line-power-tool-for-twitter
|
229
232
|
|
230
|
-
[rubyrogues]:
|
233
|
+
[rubyrogues]: https://devchat.tv/ruby-rogues/127-rr-erik-michaels-ober
|
231
234
|
|
232
235
|
If you discuss `t` in a blog post or podcast, [let me know][email] and I'll
|
233
236
|
link it here.
|
@@ -308,8 +311,8 @@ If you are running t on a remote computer you can use the flag --display-uri dur
|
|
308
311
|
t authorize --display-uri
|
309
312
|
|
310
313
|
## Copyright
|
311
|
-
Copyright (c) 2011-
|
314
|
+
Copyright (c) 2011-2016 Erik Michaels-Ober. See [LICENSE][] for details.
|
312
315
|
Application icon by [@nvk][nvk].
|
313
316
|
|
314
317
|
[license]: https://github.com/sferik/t/blob/master/LICENSE.md
|
315
|
-
[nvk]: http://
|
318
|
+
[nvk]: http://www.rnvk.org
|
data/bin/t
CHANGED
@@ -23,12 +23,9 @@ rescue Interrupt
|
|
23
23
|
rescue OAuth::Unauthorized
|
24
24
|
pute 'Authorization failed'
|
25
25
|
rescue Twitter::Error::TooManyRequests => error
|
26
|
-
pute error.message,
|
27
|
-
"The rate limit for this request will reset in #{error.rate_limit.reset_in} #{error.rate_limit.reset_in == 1 ? 'second' : 'seconds'}.",
|
28
|
-
'While you wait, consider making a polite request for Twitter to increase the API rate limit at https://twittercommunity.com/t/discussing-api-v1-1/10180'
|
26
|
+
pute error.message, "The rate limit for this request will reset in #{error.rate_limit.reset_in} #{error.rate_limit.reset_in == 1 ? 'second' : 'seconds'}."
|
29
27
|
rescue Twitter::Error::BadRequest => error
|
30
|
-
pute error.message,
|
31
|
-
'Run `t authorize` to authorize.'
|
28
|
+
pute error.message, 'Run `t authorize` to authorize.'
|
32
29
|
rescue Twitter::Error::Forbidden, Twitter::Error::Unauthorized => error
|
33
30
|
if error.message == 'Error processing your OAuth request: Read-only application cannot POST' ||
|
34
31
|
error.message == 'This application is not allowed to access or delete your direct messages'
|
data/lib/t/cli.rb
CHANGED
@@ -24,9 +24,9 @@ module T
|
|
24
24
|
include T::Utils
|
25
25
|
|
26
26
|
DEFAULT_NUM_RESULTS = 20
|
27
|
-
DIRECT_MESSAGE_HEADINGS = ['ID', 'Posted at', 'Screen name', 'Text']
|
27
|
+
DIRECT_MESSAGE_HEADINGS = ['ID', 'Posted at', 'Screen name', 'Text'].freeze
|
28
28
|
MAX_SEARCH_RESULTS = 100
|
29
|
-
TREND_HEADINGS = ['WOEID', 'Parent ID', 'Type', 'Name', 'Country']
|
29
|
+
TREND_HEADINGS = ['WOEID', 'Parent ID', 'Type', 'Name', 'Country'].freeze
|
30
30
|
|
31
31
|
check_unknown_options!
|
32
32
|
|
@@ -62,21 +62,19 @@ module T
|
|
62
62
|
say ' Note: Your application must have a unique name.'
|
63
63
|
say ' 3. Go to the Permissions tab of your application, and change the'
|
64
64
|
say ' Access setting to "Read, Write and Access direct messages".'
|
65
|
-
say ' 4. Go to the
|
66
|
-
say " which you'll need to copy and paste below when
|
67
|
-
say
|
68
|
-
ask 'Press [Enter] to open the Twitter Developer site.'
|
69
|
-
say
|
65
|
+
say ' 4. Go to the Keys and Access Tokens tab to view the consumer key'
|
66
|
+
say " and secret which you'll need to copy and paste below when"
|
67
|
+
say ' prompted.'
|
70
68
|
else
|
71
69
|
say "It looks like you've already registered an application with Twitter."
|
72
70
|
say 'To authorize a new account, just follow the steps below:'
|
73
71
|
say ' 1. Sign in to the Twitter Developer site.'
|
74
72
|
say " 2. Select the application for which you'd like to authorize an account."
|
75
73
|
say ' 3. Copy and paste the consumer key and secret below when prompted.'
|
76
|
-
say
|
77
|
-
ask 'Press [Enter] to open the Twitter Developer site.'
|
78
|
-
say
|
79
74
|
end
|
75
|
+
say
|
76
|
+
ask 'Press [Enter] to open the Twitter Developer site.'
|
77
|
+
say
|
80
78
|
require 'launchy'
|
81
79
|
open_or_print('https://apps.twitter.com', dry_run: options['display-uri'])
|
82
80
|
key = ask 'Enter your API key:'
|
@@ -147,7 +145,7 @@ module T
|
|
147
145
|
array = direct_messages.collect do |direct_message|
|
148
146
|
[direct_message.id, ls_formatted_time(direct_message), "@#{direct_message.sender.screen_name}", decode_full_text(direct_message, options['decode_uris']).gsub(/\n+/, ' ')]
|
149
147
|
end
|
150
|
-
format = options['format'] || DIRECT_MESSAGE_HEADINGS.size
|
148
|
+
format = options['format'] || Array.new(DIRECT_MESSAGE_HEADINGS.size) { '%s' }
|
151
149
|
print_table_with_headings(array, DIRECT_MESSAGE_HEADINGS, format)
|
152
150
|
else
|
153
151
|
direct_messages.each do |direct_message|
|
@@ -182,7 +180,7 @@ module T
|
|
182
180
|
array = direct_messages.collect do |direct_message|
|
183
181
|
[direct_message.id, ls_formatted_time(direct_message), "@#{direct_message.recipient.screen_name}", decode_full_text(direct_message, options['decode_uris']).gsub(/\n+/, ' ')]
|
184
182
|
end
|
185
|
-
format = options['format'] || DIRECT_MESSAGE_HEADINGS.size
|
183
|
+
format = options['format'] || Array.new(DIRECT_MESSAGE_HEADINGS.size) { '%s' }
|
186
184
|
print_table_with_headings(array, DIRECT_MESSAGE_HEADINGS, format)
|
187
185
|
else
|
188
186
|
direct_messages.each do |direct_message|
|
@@ -223,7 +221,7 @@ module T
|
|
223
221
|
desc 'does_follow USER [USER]', 'Find out whether one user follows another.'
|
224
222
|
method_option 'id', aliases: '-i', type: :boolean, desc: 'Specify user via ID instead of screen name.'
|
225
223
|
def does_follow(user1, user2 = nil)
|
226
|
-
abort 'No, you are not following yourself.' if user2.nil? &&
|
224
|
+
abort 'No, you are not following yourself.' if user2.nil? && @rcfile.active_profile[0].casecmp(user1).zero?
|
227
225
|
abort "No, @#{user1} is not following themself." if user1 == user2
|
228
226
|
require 't/core_ext/string'
|
229
227
|
thread1 = if options['id']
|
@@ -233,14 +231,13 @@ module T
|
|
233
231
|
end
|
234
232
|
thread2 = if user2.nil?
|
235
233
|
Thread.new { @rcfile.active_profile[0] }
|
234
|
+
elsif options['id']
|
235
|
+
Thread.new { client.user(user2.to_i).screen_name }
|
236
236
|
else
|
237
|
-
|
238
|
-
Thread.new { client.user(user2.to_i).screen_name }
|
239
|
-
else
|
240
|
-
Thread.new { user2.strip_ats }
|
241
|
-
end
|
237
|
+
Thread.new { user2.strip_ats }
|
242
238
|
end
|
243
|
-
user1
|
239
|
+
user1 = thread1.value
|
240
|
+
user2 = thread2.value
|
244
241
|
if client.friendship?(user1, user2)
|
245
242
|
say "Yes, @#{user1} follows @#{user2}."
|
246
243
|
else
|
@@ -431,7 +428,7 @@ module T
|
|
431
428
|
method_option 'relative_dates', aliases: '-a', type: :boolean, desc: 'Show relative dates.'
|
432
429
|
method_option 'reverse', aliases: '-r', type: :boolean, desc: 'Reverse the order of the sort.'
|
433
430
|
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'
|
434
|
-
method_option 'type', aliases: '-t', type: :string, enum: %w(followers followings), default: 'followings', desc: 'Specify the
|
431
|
+
method_option 'type', aliases: '-t', type: :string, enum: %w(followers followings), default: 'followings', desc: 'Specify the type of intersection.'
|
435
432
|
method_option 'unsorted', aliases: '-u', type: :boolean, desc: 'Output is not sorted.'
|
436
433
|
def intersection(first_user, *users)
|
437
434
|
users.push(first_user)
|
@@ -594,11 +591,12 @@ module T
|
|
594
591
|
say number_with_delimiter(reach.size)
|
595
592
|
end
|
596
593
|
|
597
|
-
desc 'reply TWEET_ID MESSAGE', 'Post your Tweet as a reply directed at another person.'
|
594
|
+
desc 'reply TWEET_ID [MESSAGE]', 'Post your Tweet as a reply directed at another person.'
|
598
595
|
method_option 'all', aliases: '-a', type: :boolean, desc: 'Reply to all users mentioned in the Tweet.'
|
599
596
|
method_option 'location', aliases: '-l', type: :string, default: nil, desc: "Add location information. If the optional 'latitude,longitude' parameter is not supplied, looks up location by IP address."
|
600
597
|
method_option 'file', aliases: '-f', type: :string, desc: 'The path to an image to attach to your tweet.'
|
601
|
-
def reply(status_id, message)
|
598
|
+
def reply(status_id, message = nil)
|
599
|
+
message = T::Editor.gets if message.to_s.empty?
|
602
600
|
status = client.status(status_id.to_i, include_my_retweet: false)
|
603
601
|
users = Array(status.user.screen_name)
|
604
602
|
if options['all']
|
@@ -730,7 +728,7 @@ module T
|
|
730
728
|
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
|
731
729
|
elsif options['long']
|
732
730
|
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]
|
733
|
-
format = options['format'] || status_headings.size
|
731
|
+
format = options['format'] || Array.new(status_headings.size) { '%s' }
|
734
732
|
print_table_with_headings([array], status_headings, format)
|
735
733
|
else
|
736
734
|
array = []
|
@@ -784,7 +782,7 @@ module T
|
|
784
782
|
method_option 'exclude-hashtags', aliases: '-x', type: :boolean, desc: 'Remove all hashtags from the trends list.'
|
785
783
|
def trends(woe_id = 1)
|
786
784
|
opts = {}
|
787
|
-
opts
|
785
|
+
opts[:exclude] = 'hashtags' if options['exclude-hashtags']
|
788
786
|
trends = client.trends(woe_id, opts)
|
789
787
|
print_attribute(trends, :name)
|
790
788
|
end
|
@@ -821,7 +819,7 @@ module T
|
|
821
819
|
array = places.collect do |place|
|
822
820
|
[place.woeid, place.parent_id, place.place_type, place.name, place.country]
|
823
821
|
end
|
824
|
-
format = options['format'] || TREND_HEADINGS.size
|
822
|
+
format = options['format'] || Array.new(TREND_HEADINGS.size) { '%s' }
|
825
823
|
print_table_with_headings(array, TREND_HEADINGS, format)
|
826
824
|
else
|
827
825
|
print_attribute(places, :name)
|
@@ -844,7 +842,7 @@ module T
|
|
844
842
|
method_option 'location', aliases: '-l', type: :string, default: nil, desc: "Add location information. If the optional 'latitude,longitude' parameter is not supplied, looks up location by IP address."
|
845
843
|
method_option 'file', aliases: '-f', type: :string, desc: 'The path to an image to attach to your tweet.'
|
846
844
|
def update(message = nil)
|
847
|
-
message = T::Editor.gets if message.
|
845
|
+
message = T::Editor.gets if message.to_s.empty?
|
848
846
|
opts = {trim_user: true}
|
849
847
|
add_location!(options, opts)
|
850
848
|
status = if options['file']
|
@@ -891,7 +889,7 @@ module T
|
|
891
889
|
method_option 'id', aliases: '-i', type: :boolean, desc: 'Specify user via ID instead of screen name.'
|
892
890
|
method_option 'long', aliases: '-l', type: :boolean, desc: 'Output in long format.'
|
893
891
|
method_option 'relative_dates', aliases: '-a', type: :boolean, desc: 'Show relative dates.'
|
894
|
-
def whois(user)
|
892
|
+
def whois(user)
|
895
893
|
require 't/core_ext/string'
|
896
894
|
opts = {}
|
897
895
|
opts[:include_entities] = !!options['decode_uris']
|
data/lib/t/collectable.rb
CHANGED
@@ -30,9 +30,9 @@ module T
|
|
30
30
|
end.flatten.compact
|
31
31
|
end
|
32
32
|
|
33
|
-
def collect_with_page(collection = ::Set.new, page = 1, previous = nil, &block)
|
33
|
+
def collect_with_page(collection = ::Set.new, page = 1, previous = nil, &block)
|
34
34
|
tweets = Retryable.retryable(tries: 3, on: Twitter::Error, sleep: 0) do
|
35
|
-
|
35
|
+
yield page
|
36
36
|
end
|
37
37
|
return collection if tweets.nil? || tweets == previous || page >= MAX_PAGE
|
38
38
|
collection += tweets
|
data/lib/t/core_ext/string.rb
CHANGED
data/lib/t/delete.rb
CHANGED
@@ -42,7 +42,7 @@ module T
|
|
42
42
|
else
|
43
43
|
direct_message_ids.each do |direct_message_id_to_delete|
|
44
44
|
direct_message = client.direct_message(direct_message_id_to_delete)
|
45
|
-
|
45
|
+
next unless yes? "Are you sure you want to permanently delete the direct message to @#{direct_message.recipient.screen_name}: \"#{direct_message.text}\"? [y/N]"
|
46
46
|
client.destroy_direct_message(direct_message_id_to_delete)
|
47
47
|
say "@#{@rcfile.active_profile[0]} deleted the direct message sent to @#{direct_message.recipient.screen_name}: \"#{direct_message.text}\""
|
48
48
|
end
|
@@ -64,7 +64,7 @@ module T
|
|
64
64
|
else
|
65
65
|
status_ids.each do |status_id_to_unfavorite|
|
66
66
|
status = client.status(status_id_to_unfavorite, include_my_retweet: false)
|
67
|
-
|
67
|
+
next unless yes? "Are you sure you want to remove @#{status.user.screen_name}'s status: \"#{status.full_text}\" from your favorites? [y/N]"
|
68
68
|
client.unfavorite(status_id_to_unfavorite)
|
69
69
|
say "@#{@rcfile.active_profile[0]} unfavorited @#{status.user.screen_name}'s status: \"#{status.full_text}\""
|
70
70
|
end
|
@@ -102,11 +102,8 @@ module T
|
|
102
102
|
|
103
103
|
desc 'account SCREEN_NAME [CONSUMER_KEY]', 'delete account or consumer key from t'
|
104
104
|
def account(account, key = nil)
|
105
|
-
if key && @rcfile.profiles[account].keys.
|
106
|
-
|
107
|
-
return if continue.downcase != 'y'
|
108
|
-
elsif key
|
109
|
-
return @rcfile.delete_key(account, key)
|
105
|
+
if key && @rcfile.profiles[account].keys.size > 1
|
106
|
+
@rcfile.delete_key(account, key)
|
110
107
|
else
|
111
108
|
@rcfile.delete_profile(account)
|
112
109
|
end
|
@@ -126,7 +123,7 @@ module T
|
|
126
123
|
else
|
127
124
|
status_ids.each do |status_id_to_delete|
|
128
125
|
status = client.status(status_id_to_delete, include_my_retweet: false)
|
129
|
-
|
126
|
+
next unless yes? "Are you sure you want to permanently delete @#{status.user.screen_name}'s status: \"#{status.full_text}\"? [y/N]"
|
130
127
|
client.destroy_status(status_id_to_delete, trim_user: true)
|
131
128
|
say "@#{@rcfile.active_profile[0]} deleted the Tweet: \"#{status.full_text}\""
|
132
129
|
end
|
data/lib/t/identicon.rb
CHANGED
data/lib/t/list.rb
CHANGED
@@ -42,7 +42,7 @@ module T
|
|
42
42
|
method_option 'private', aliases: '-p', type: :boolean
|
43
43
|
def create(list_name, description = nil)
|
44
44
|
opts = description ? {description: description} : {}
|
45
|
-
opts
|
45
|
+
opts[:mode] = 'private' if options['private']
|
46
46
|
client.create_list(list_name, opts)
|
47
47
|
say "@#{@rcfile.active_profile[0]} created the list \"#{list_name}\"."
|
48
48
|
end
|
data/lib/t/printable.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
module T
|
2
|
-
module Printable
|
3
|
-
LIST_HEADINGS = ['ID', 'Created at', 'Screen name', 'Slug', 'Members', 'Subscribers', 'Mode', 'Description']
|
4
|
-
TWEET_HEADINGS = ['ID', 'Posted at', 'Screen name', 'Text']
|
5
|
-
USER_HEADINGS = ['ID', 'Since', 'Last tweeted at', 'Tweets', 'Favorites', 'Listed', 'Following', 'Followers', 'Screen name', 'Name', 'Verified', 'Protected', 'Bio', 'Status', 'Location', 'URL']
|
2
|
+
module Printable # rubocop:disable ModuleLength
|
3
|
+
LIST_HEADINGS = ['ID', 'Created at', 'Screen name', 'Slug', 'Members', 'Subscribers', 'Mode', 'Description'].freeze
|
4
|
+
TWEET_HEADINGS = ['ID', 'Posted at', 'Screen name', 'Text'].freeze
|
5
|
+
USER_HEADINGS = ['ID', 'Since', 'Last tweeted at', 'Tweets', 'Favorites', 'Listed', 'Following', 'Followers', 'Screen name', 'Name', 'Verified', 'Protected', 'Bio', 'Status', 'Location', 'URL'].freeze
|
6
6
|
MONTH_IN_SECONDS = 2_592_000
|
7
7
|
|
8
8
|
private
|
@@ -76,7 +76,7 @@ module T
|
|
76
76
|
array = lists.collect do |list|
|
77
77
|
build_long_list(list)
|
78
78
|
end
|
79
|
-
format = options['format'] || LIST_HEADINGS.size
|
79
|
+
format = options['format'] || Array.new(LIST_HEADINGS.size) { '%s' }
|
80
80
|
print_table_with_headings(array, LIST_HEADINGS, format)
|
81
81
|
else
|
82
82
|
print_attribute(lists, :full_name)
|
@@ -118,16 +118,14 @@ module T
|
|
118
118
|
when 'icon'
|
119
119
|
print_identicon(from_user, message)
|
120
120
|
say
|
121
|
-
say
|
122
121
|
when 'auto'
|
123
122
|
say(" @#{from_user}", [:bold, :yellow])
|
124
123
|
print_wrapped(HTMLEntities.new.decode(message), indent: 3)
|
125
|
-
say
|
126
124
|
else
|
127
125
|
say(" @#{from_user}")
|
128
126
|
print_wrapped(HTMLEntities.new.decode(message), indent: 3)
|
129
|
-
say
|
130
127
|
end
|
128
|
+
say
|
131
129
|
end
|
132
130
|
|
133
131
|
def print_identicon(from_user, message)
|
@@ -138,7 +136,7 @@ module T
|
|
138
136
|
# Save 6 chars for icon, ensure at least 3 lines long
|
139
137
|
lines = wrapped(HTMLEntities.new.decode(message), indent: 2, width: terminal_width - (6 + 5))
|
140
138
|
lines.unshift(set_color(" @#{from_user}", :bold, :yellow))
|
141
|
-
lines.push(*(3 - lines.length)
|
139
|
+
lines.push(*Array.new([3 - lines.length, 0].max) { '' })
|
142
140
|
|
143
141
|
$stdout.puts lines.zip(icon.lines).map { |x, i| " #{i || ' '}#{x}" }
|
144
142
|
end
|
@@ -173,7 +171,7 @@ module T
|
|
173
171
|
array = tweets.collect do |tweet|
|
174
172
|
build_long_tweet(tweet)
|
175
173
|
end
|
176
|
-
format = options['format'] || TWEET_HEADINGS.size
|
174
|
+
format = options['format'] || Array.new(TWEET_HEADINGS.size) { '%s' }
|
177
175
|
print_table_with_headings(array, TWEET_HEADINGS, format)
|
178
176
|
else
|
179
177
|
tweets.each do |tweet|
|
@@ -212,7 +210,7 @@ module T
|
|
212
210
|
array = users.collect do |user|
|
213
211
|
build_long_user(user)
|
214
212
|
end
|
215
|
-
format = options['format'] || USER_HEADINGS.size
|
213
|
+
format = options['format'] || Array.new(USER_HEADINGS.size) { '%s' }
|
216
214
|
print_table_with_headings(array, USER_HEADINGS, format)
|
217
215
|
else
|
218
216
|
print_attribute(users, :screen_name)
|
data/lib/t/rcfile.rb
CHANGED
@@ -4,7 +4,7 @@ module T
|
|
4
4
|
class RCFile
|
5
5
|
include Singleton
|
6
6
|
attr_reader :path
|
7
|
-
FILE_NAME = '.trc'
|
7
|
+
FILE_NAME = '.trc'.freeze
|
8
8
|
|
9
9
|
def initialize
|
10
10
|
@path = File.join(File.expand_path('~'), FILE_NAME)
|
@@ -25,11 +25,11 @@ module T
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def find_case_insensitive_match(username)
|
28
|
-
profiles.keys.detect { |u| username.
|
28
|
+
profiles.keys.detect { |u| username.casecmp(u).zero? }
|
29
29
|
end
|
30
30
|
|
31
31
|
def find_case_insensitive_possibilities(username)
|
32
|
-
profiles.keys.select { |u| username.
|
32
|
+
profiles.keys.select { |u| username.casecmp(u[0, username.length]).zero? }
|
33
33
|
end
|
34
34
|
|
35
35
|
def []=(username, profile)
|
data/lib/t/search.rb
CHANGED
@@ -46,7 +46,7 @@ module T
|
|
46
46
|
array = tweets.collect do |tweet|
|
47
47
|
[tweet.id, ls_formatted_time(tweet), "@#{tweet.user.screen_name}", decode_full_text(tweet, options['decode_uris']).gsub(/\n+/, ' ')]
|
48
48
|
end
|
49
|
-
format = options['format'] || TWEET_HEADINGS.size
|
49
|
+
format = options['format'] || Array.new(TWEET_HEADINGS.size) { '%s' }
|
50
50
|
print_table_with_headings(array, TWEET_HEADINGS, format)
|
51
51
|
else
|
52
52
|
say unless tweets.empty?
|
data/lib/t/stream.rb
CHANGED
@@ -15,7 +15,7 @@ module T
|
|
15
15
|
'%-12s', # Add padding to length of a timestamp formatted with ls_formatted_time
|
16
16
|
'%-20s', # Add padding to maximum length of a Twitter screen name
|
17
17
|
'%s', # Last element does not need special formatting
|
18
|
-
]
|
18
|
+
].freeze
|
19
19
|
|
20
20
|
check_unknown_options!
|
21
21
|
|
@@ -34,7 +34,7 @@ module T
|
|
34
34
|
require 'csv'
|
35
35
|
say TWEET_HEADINGS.to_csv
|
36
36
|
elsif options['long'] && STDOUT.tty?
|
37
|
-
headings = TWEET_HEADINGS.size
|
37
|
+
headings = Array.new(TWEET_HEADINGS.size) do |index|
|
38
38
|
TWEET_HEADINGS_FORMATTING[index] % TWEET_HEADINGS[index]
|
39
39
|
end
|
40
40
|
print_table([headings])
|
@@ -170,7 +170,7 @@ module T
|
|
170
170
|
require 'csv'
|
171
171
|
say TWEET_HEADINGS.to_csv
|
172
172
|
elsif options['long'] && STDOUT.tty?
|
173
|
-
headings = TWEET_HEADINGS.size
|
173
|
+
headings = Array.new(TWEET_HEADINGS.size) do |index|
|
174
174
|
TWEET_HEADINGS_FORMATTING[index] % TWEET_HEADINGS[index]
|
175
175
|
end
|
176
176
|
print_table([headings])
|
data/lib/t/utils.rb
CHANGED
@@ -44,8 +44,8 @@ module T
|
|
44
44
|
format('%d years', (minutes.to_f / 525_600.0).round)
|
45
45
|
end
|
46
46
|
end
|
47
|
-
|
48
|
-
|
47
|
+
alias time_ago_in_words distance_of_time_in_words
|
48
|
+
alias time_from_now_in_words distance_of_time_in_words
|
49
49
|
|
50
50
|
def fetch_users(users, options)
|
51
51
|
format_users!(users, options)
|
data/lib/t/version.rb
CHANGED
data/t.gemspec
CHANGED
@@ -5,12 +5,12 @@ require 't/version'
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.add_dependency 'launchy', '~> 2.4'
|
8
|
-
spec.add_dependency 'geokit',
|
8
|
+
spec.add_dependency 'geokit', '~> 1.9'
|
9
9
|
spec.add_dependency 'htmlentities', '~> 4.3'
|
10
10
|
spec.add_dependency 'oauth', '~> 0.4.7'
|
11
11
|
spec.add_dependency 'retryable', '~> 2.0'
|
12
12
|
spec.add_dependency 'thor', ['>= 0.19.1', '< 2']
|
13
|
-
spec.add_dependency 'twitter', '~> 5.
|
13
|
+
spec.add_dependency 'twitter', '~> 5.16'
|
14
14
|
spec.add_development_dependency 'bundler', '~> 1.0'
|
15
15
|
spec.author = 'Erik Michaels-Ober'
|
16
16
|
spec.description = 'A command-line power tool for Twitter.'
|
@@ -22,7 +22,6 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.name = 't'
|
23
23
|
spec.require_paths = %w(lib)
|
24
24
|
spec.required_ruby_version = '>= 1.9.3'
|
25
|
-
spec.required_rubygems_version = '>= 1.3.5'
|
26
25
|
spec.summary = 'CLI for Twitter'
|
27
26
|
spec.version = T::Version
|
28
27
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: t
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Erik Michaels-Ober
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: launchy
|
@@ -28,22 +28,16 @@ dependencies:
|
|
28
28
|
name: geokit
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 1.8.3
|
34
|
-
- - "<"
|
31
|
+
- - "~>"
|
35
32
|
- !ruby/object:Gem::Version
|
36
|
-
version: '
|
33
|
+
version: '1.9'
|
37
34
|
type: :runtime
|
38
35
|
prerelease: false
|
39
36
|
version_requirements: !ruby/object:Gem::Requirement
|
40
37
|
requirements:
|
41
|
-
- - "
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
version: 1.8.3
|
44
|
-
- - "<"
|
38
|
+
- - "~>"
|
45
39
|
- !ruby/object:Gem::Version
|
46
|
-
version: '
|
40
|
+
version: '1.9'
|
47
41
|
- !ruby/object:Gem::Dependency
|
48
42
|
name: htmlentities
|
49
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -112,14 +106,14 @@ dependencies:
|
|
112
106
|
requirements:
|
113
107
|
- - "~>"
|
114
108
|
- !ruby/object:Gem::Version
|
115
|
-
version: '5.
|
109
|
+
version: '5.16'
|
116
110
|
type: :runtime
|
117
111
|
prerelease: false
|
118
112
|
version_requirements: !ruby/object:Gem::Requirement
|
119
113
|
requirements:
|
120
114
|
- - "~>"
|
121
115
|
- !ruby/object:Gem::Version
|
122
|
-
version: '5.
|
116
|
+
version: '5.16'
|
123
117
|
- !ruby/object:Gem::Dependency
|
124
118
|
name: bundler
|
125
119
|
requirement: !ruby/object:Gem::Requirement
|
@@ -180,10 +174,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
180
174
|
requirements:
|
181
175
|
- - ">="
|
182
176
|
- !ruby/object:Gem::Version
|
183
|
-
version:
|
177
|
+
version: '0'
|
184
178
|
requirements: []
|
185
179
|
rubyforge_project:
|
186
|
-
rubygems_version: 2.
|
180
|
+
rubygems_version: 2.5.1
|
187
181
|
signing_key:
|
188
182
|
specification_version: 4
|
189
183
|
summary: CLI for Twitter
|