t 2.9.0 → 2.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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]
|
6
|
+
[][travis]
|
7
|
+
[][gemnasium]
|
8
|
+
[][coveralls]
|
9
9
|
[](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
|