t 0.3.1 → 0.4.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.
- data/.rspec +1 -1
- data/.travis.yml +4 -4
- data/README.md +19 -8
- data/lib/t/cli.rb +33 -17
- data/lib/t/cli/delete.rb +4 -31
- data/lib/t/cli/follow.rb +5 -33
- data/lib/t/cli/list.rb +2 -29
- data/lib/t/cli/list/add.rb +27 -41
- data/lib/t/cli/list/remove.rb +19 -43
- data/lib/t/cli/search.rb +54 -33
- data/lib/t/cli/set.rb +2 -29
- data/lib/t/cli/unfollow.rb +7 -35
- data/lib/t/core_ext/enumerable.rb +9 -0
- data/lib/t/rcfile.rb +0 -4
- data/lib/t/requestable.rb +37 -0
- data/lib/t/version.rb +2 -2
- data/spec/cli/delete_spec.rb +2 -1
- data/spec/cli/follow_spec.rb +2 -0
- data/spec/cli/list/add_spec.rb +60 -0
- data/spec/cli/list/remove_spec.rb +82 -92
- data/spec/cli/list_spec.rb +4 -0
- data/spec/cli/search_spec.rb +232 -0
- data/spec/cli/set_spec.rb +2 -1
- data/spec/cli/unfollow_spec.rb +2 -0
- data/spec/cli_spec.rb +81 -1
- data/spec/helper.rb +5 -2
- data/t.gemspec +3 -3
- metadata +129 -42
data/.rspec
CHANGED
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# Twitter CLI [][travis] [][gemnasium]
|
2
|
-
A command-line
|
3
|
-
|
4
|
-
|
2
|
+
### A command-line power tool for Twitter.
|
3
|
+
|
4
|
+
The CLI attempts to mimic the [Twitter SMS commands][sms] wherever possible,
|
5
|
+
however it offers many more commands than are available via SMS.
|
5
6
|
|
6
7
|
[travis]: http://travis-ci.org/sferik/t
|
7
8
|
[gemnasium]: https://gemnasium.com/sferik/t
|
@@ -156,15 +157,27 @@ type `t help TASK` to get help for a specific command.
|
|
156
157
|
|
157
158
|
### <a name="search-all"></a>Retrieve the 20 most recent Tweets that match a specified query
|
158
159
|
|
159
|
-
t search all
|
160
|
+
t search all "query"
|
161
|
+
|
162
|
+
### <a name="search-retweets"></a>Returns Tweets you've favorited that mach a specified query
|
163
|
+
|
164
|
+
t search favorites "query"
|
165
|
+
|
166
|
+
### <a name="search-mentions"></a>Returns Tweets mentioning you that mach a specified query
|
167
|
+
|
168
|
+
t search mentions "query"
|
169
|
+
|
170
|
+
### <a name="search-retweets"></a>Returns Tweets you've retweeted that mach a specified query
|
171
|
+
|
172
|
+
t search retweets "query"
|
160
173
|
|
161
174
|
### <a name="search-timeline"></a>Retrieve Tweets in your timeline that match a specified query
|
162
175
|
|
163
|
-
t search timeline
|
176
|
+
t search timeline "query"
|
164
177
|
|
165
178
|
### <a name="search-user"></a>Retrieve Tweets in a user's timeline that match a specified query
|
166
179
|
|
167
|
-
t search user sferik
|
180
|
+
t search user sferik "query"
|
168
181
|
|
169
182
|
## <a name="history"></a>History
|
170
183
|

|
@@ -229,11 +242,9 @@ implementations:
|
|
229
242
|
* Ruby 1.9.3
|
230
243
|
* [JRuby][]
|
231
244
|
* [Rubinius][]
|
232
|
-
* [Ruby Enterprise Edition][ree]
|
233
245
|
|
234
246
|
[jruby]: http://www.jruby.org/
|
235
247
|
[rubinius]: http://rubini.us/
|
236
|
-
[ree]: http://www.rubyenterpriseedition.com/
|
237
248
|
|
238
249
|
If something doesn't work on one of these interpreters, it should be considered
|
239
250
|
a bug.
|
data/lib/t/cli.rb
CHANGED
@@ -86,10 +86,10 @@ module T
|
|
86
86
|
user = client.block(screen_name, :include_entities => false)
|
87
87
|
say "@#{@rcfile.default_profile[0]} blocked @#{user.screen_name}"
|
88
88
|
say
|
89
|
-
say "Run `#{$0} delete block #{user.screen_name}` to unblock."
|
89
|
+
say "Run `#{File.basename($0)} delete block #{user.screen_name}` to unblock."
|
90
90
|
end
|
91
91
|
|
92
|
-
desc "direct_messages", "Returns the
|
92
|
+
desc "direct_messages", "Returns the #{DEFAULT_NUM_RESULTS} most recent Direct Messages sent to you."
|
93
93
|
method_option :number, :aliases => "-n", :type => :numeric, :default => DEFAULT_NUM_RESULTS
|
94
94
|
def direct_messages
|
95
95
|
defaults = {:include_entities => false}
|
@@ -117,7 +117,7 @@ module T
|
|
117
117
|
client.favorite(user.status.id, :include_entities => false)
|
118
118
|
say "@#{@rcfile.default_profile[0]} favorited @#{user.screen_name}'s latest status: \"#{user.status.text}\""
|
119
119
|
say
|
120
|
-
say "Run `#{$0} delete favorite` to unfavorite."
|
120
|
+
say "Run `#{File.basename($0)} delete favorite` to unfavorite."
|
121
121
|
else
|
122
122
|
raise Thor::Error, "Tweet not found"
|
123
123
|
end
|
@@ -178,7 +178,7 @@ module T
|
|
178
178
|
status = client.update("@#{user.screen_name} #{message}", defaults)
|
179
179
|
say "Reply created by @#{@rcfile.default_profile[0]} to @#{user.screen_name} (#{time_ago_in_words(status.created_at)} ago)"
|
180
180
|
say
|
181
|
-
say "Run `#{$0} delete status` to delete."
|
181
|
+
say "Run `#{File.basename($0)} delete status` to delete."
|
182
182
|
end
|
183
183
|
|
184
184
|
desc "retweet SCREEN_NAME", "Sends that user's latest Tweet to your followers."
|
@@ -189,7 +189,7 @@ module T
|
|
189
189
|
client.retweet(user.status.id, :include_entities => false, :trim_user => true)
|
190
190
|
say "@#{@rcfile.default_profile[0]} retweeted @#{user.screen_name}'s latest status: \"#{user.status.text}\""
|
191
191
|
say
|
192
|
-
say "Run `#{$0} delete status` to undo."
|
192
|
+
say "Run `#{File.basename($0)} delete status` to undo."
|
193
193
|
else
|
194
194
|
raise Thor::Error, "Tweet not found"
|
195
195
|
end
|
@@ -202,7 +202,23 @@ module T
|
|
202
202
|
end
|
203
203
|
map %w(rt) => :retweet
|
204
204
|
|
205
|
-
desc "
|
205
|
+
desc "retweets [SCREEN_NAME]", "Returns the #{DEFAULT_NUM_RESULTS} most recent Retweets by a user."
|
206
|
+
method_option :number, :aliases => "-n", :type => :numeric, :default => DEFAULT_NUM_RESULTS
|
207
|
+
method_option :reverse, :aliases => "-r", :type => :boolean, :default => false
|
208
|
+
def retweets(screen_name=nil)
|
209
|
+
screen_name = screen_name.strip_at if screen_name
|
210
|
+
defaults = {:include_entities => false}
|
211
|
+
defaults.merge!(:count => options['number']) if options['number']
|
212
|
+
timeline = client.retweeted_by(screen_name, defaults)
|
213
|
+
timeline.reverse! if options['reverse']
|
214
|
+
page unless T.env.test?
|
215
|
+
timeline.each do |status|
|
216
|
+
say "#{status.user.screen_name.rjust(MAX_SCREEN_NAME_SIZE)}: #{status.text} (#{time_ago_in_words(status.created_at)} ago)"
|
217
|
+
end
|
218
|
+
end
|
219
|
+
map %w(rts) => :retweets
|
220
|
+
|
221
|
+
desc "sent_messages", "Returns the #{DEFAULT_NUM_RESULTS} most recent Direct Messages sent to you."
|
206
222
|
method_option :number, :aliases => "-n", :type => :numeric, :default => DEFAULT_NUM_RESULTS
|
207
223
|
def sent_messages
|
208
224
|
defaults = {:include_entities => false}
|
@@ -224,7 +240,7 @@ module T
|
|
224
240
|
say "Favorites: #{number_with_delimiter(user.favorites_count)}"
|
225
241
|
say "Listed: #{number_with_delimiter(user.listed_count)}"
|
226
242
|
say
|
227
|
-
say "Run `#{$0} whois #{user.screen_name}` to view profile."
|
243
|
+
say "Run `#{File.basename($0)} whois #{user.screen_name}` to view profile."
|
228
244
|
end
|
229
245
|
|
230
246
|
desc "status MESSAGE", "Post a Tweet."
|
@@ -235,7 +251,7 @@ module T
|
|
235
251
|
status = client.update(message, defaults)
|
236
252
|
say "Tweet created by @#{@rcfile.default_profile[0]} (#{time_ago_in_words(status.created_at)} ago)"
|
237
253
|
say
|
238
|
-
say "Run `#{$0} delete status` to delete."
|
254
|
+
say "Run `#{File.basename($0)} delete status` to delete."
|
239
255
|
end
|
240
256
|
map %w(post tweet update) => :status
|
241
257
|
|
@@ -245,9 +261,9 @@ module T
|
|
245
261
|
if recommendation
|
246
262
|
say "Try following @#{recommendation.screen_name}."
|
247
263
|
say
|
248
|
-
say "Run `#{$0} follow #{recommendation.screen_name}` to follow."
|
249
|
-
say "Run `#{$0} whois #{recommendation.screen_name}` for profile."
|
250
|
-
say "Run `#{$0} suggest` for another recommendation."
|
264
|
+
say "Run `#{File.basename($0)} follow #{recommendation.screen_name}` to follow."
|
265
|
+
say "Run `#{File.basename($0)} whois #{recommendation.screen_name}` for profile."
|
266
|
+
say "Run `#{File.basename($0)} suggest` for another recommendation."
|
251
267
|
end
|
252
268
|
end
|
253
269
|
|
@@ -288,29 +304,29 @@ module T
|
|
288
304
|
say "web: #{user.url}"
|
289
305
|
end
|
290
306
|
|
307
|
+
require 't/cli/delete'
|
291
308
|
desc "delete SUBCOMMAND ...ARGS", "Delete Tweets, Direct Messages, etc."
|
292
309
|
method_option :force, :aliases => "-f", :type => :boolean
|
293
|
-
require 't/cli/delete'
|
294
310
|
subcommand 'delete', CLI::Delete
|
295
311
|
|
296
|
-
desc "follow SUBCOMMAND ...ARGS", "Follow users."
|
297
312
|
require 't/cli/follow'
|
313
|
+
desc "follow SUBCOMMAND ...ARGS", "Follow users."
|
298
314
|
subcommand 'follow', CLI::Follow
|
299
315
|
|
300
|
-
desc "list SUBCOMMAND ...ARGS", "Do various things with lists."
|
301
316
|
require 't/cli/list'
|
317
|
+
desc "list SUBCOMMAND ...ARGS", "Do various things with lists."
|
302
318
|
subcommand 'list', CLI::List
|
303
319
|
|
304
|
-
desc "search SUBCOMMAND ...ARGS", "Search through Tweets."
|
305
320
|
require 't/cli/search'
|
321
|
+
desc "search SUBCOMMAND ...ARGS", "Search through Tweets."
|
306
322
|
subcommand 'search', CLI::Search
|
307
323
|
|
308
|
-
desc "set SUBCOMMAND ...ARGS", "Change various account settings."
|
309
324
|
require 't/cli/set'
|
325
|
+
desc "set SUBCOMMAND ...ARGS", "Change various account settings."
|
310
326
|
subcommand 'set', CLI::Set
|
311
327
|
|
312
|
-
desc "unfollow SUBCOMMAND ...ARGS", "Unfollow users."
|
313
328
|
require 't/cli/unfollow'
|
329
|
+
desc "unfollow SUBCOMMAND ...ARGS", "Unfollow users."
|
314
330
|
subcommand 'unfollow', CLI::Unfollow
|
315
331
|
|
316
332
|
private
|
data/lib/t/cli/delete.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
require 't/core_ext/string'
|
2
2
|
require 't/rcfile'
|
3
|
+
require 't/requestable'
|
3
4
|
require 'thor'
|
4
|
-
require 'twitter'
|
5
5
|
|
6
6
|
module T
|
7
7
|
class CLI
|
8
8
|
class Delete < Thor
|
9
|
-
|
10
|
-
DEFAULT_PROTOCOL = 'https'
|
9
|
+
include T::Requestable
|
11
10
|
|
12
11
|
check_unknown_options!
|
13
12
|
|
@@ -22,7 +21,7 @@ module T
|
|
22
21
|
user = client.unblock(screen_name, :include_entities => false)
|
23
22
|
say "@#{@rcfile.default_profile[0]} unblocked @#{user.screen_name}."
|
24
23
|
say
|
25
|
-
say "Run `#{$0} block #{user.screen_name}` to block."
|
24
|
+
say "Run `#{File.basename($0)} block #{user.screen_name}` to block."
|
26
25
|
end
|
27
26
|
|
28
27
|
desc "dm", "Delete the last Direct Message sent."
|
@@ -50,7 +49,7 @@ module T
|
|
50
49
|
client.unfavorite(status.id, :include_entities => false)
|
51
50
|
say "@#{@rcfile.default_profile[0]} unfavorited @#{status.user.screen_name}'s latest status: \"#{status.text}\""
|
52
51
|
say
|
53
|
-
say "Run `#{$0} favorite #{status.user.screen_name}` to favorite."
|
52
|
+
say "Run `#{File.basename($0)} favorite #{status.user.screen_name}` to favorite."
|
54
53
|
else
|
55
54
|
raise Thor::Error, "Tweet not found"
|
56
55
|
end
|
@@ -81,32 +80,6 @@ module T
|
|
81
80
|
end
|
82
81
|
map %w(post tweet update) => :status
|
83
82
|
|
84
|
-
private
|
85
|
-
|
86
|
-
def base_url
|
87
|
-
"#{protocol}://#{host}"
|
88
|
-
end
|
89
|
-
|
90
|
-
def client
|
91
|
-
return @client if @client
|
92
|
-
@rcfile.path = parent_options['profile'] if parent_options['profile']
|
93
|
-
@client = Twitter::Client.new(
|
94
|
-
:endpoint => base_url,
|
95
|
-
:consumer_key => @rcfile.default_consumer_key,
|
96
|
-
:consumer_secret => @rcfile.default_consumer_secret,
|
97
|
-
:oauth_token => @rcfile.default_token,
|
98
|
-
:oauth_token_secret => @rcfile.default_secret
|
99
|
-
)
|
100
|
-
end
|
101
|
-
|
102
|
-
def host
|
103
|
-
parent_options['host'] || DEFAULT_HOST
|
104
|
-
end
|
105
|
-
|
106
|
-
def protocol
|
107
|
-
parent_options['no_ssl'] ? 'http' : DEFAULT_PROTOCOL
|
108
|
-
end
|
109
|
-
|
110
83
|
end
|
111
84
|
end
|
112
85
|
end
|
data/lib/t/cli/follow.rb
CHANGED
@@ -3,16 +3,14 @@ require 't/core_ext/enumerable'
|
|
3
3
|
require 't/core_ext/string'
|
4
4
|
require 't/collectable'
|
5
5
|
require 't/rcfile'
|
6
|
+
require 't/requestable'
|
6
7
|
require 'thor'
|
7
|
-
require 'twitter'
|
8
8
|
|
9
9
|
module T
|
10
10
|
class CLI
|
11
11
|
class Follow < Thor
|
12
12
|
include T::Collectable
|
13
|
-
|
14
|
-
DEFAULT_HOST = 'api.twitter.com'
|
15
|
-
DEFAULT_PROTOCOL = 'https'
|
13
|
+
include T::Requestable
|
16
14
|
|
17
15
|
check_unknown_options!
|
18
16
|
|
@@ -40,7 +38,7 @@ module T
|
|
40
38
|
end
|
41
39
|
say "@#{@rcfile.default_profile[0]} is now following #{number} more #{number == 1 ? 'user' : 'users'}."
|
42
40
|
say
|
43
|
-
say "Run `#{$0} unfollow all followers` to stop."
|
41
|
+
say "Run `#{File.basename($0)} unfollow all followers` to stop."
|
44
42
|
end
|
45
43
|
|
46
44
|
desc "listed LIST_NAME", "Follow all members of a list."
|
@@ -58,7 +56,7 @@ module T
|
|
58
56
|
end
|
59
57
|
say "@#{@rcfile.default_profile[0]} is now following #{number} more #{number == 1 ? 'user' : 'users'}."
|
60
58
|
say
|
61
|
-
say "Run `#{$0} unfollow all listed #{list_name}` to stop."
|
59
|
+
say "Run `#{File.basename($0)} unfollow all listed #{list_name}` to stop."
|
62
60
|
end
|
63
61
|
|
64
62
|
desc "users SCREEN_NAME [SCREEN_NAME...]", "Allows you to start following users."
|
@@ -72,33 +70,7 @@ module T
|
|
72
70
|
number = screen_names.length
|
73
71
|
say "@#{@rcfile.default_profile[0]} is now following #{number} more #{number == 1 ? 'user' : 'users'}."
|
74
72
|
say
|
75
|
-
say "Run `#{$0} unfollow users #{screen_names.join(' ')}` to stop."
|
76
|
-
end
|
77
|
-
|
78
|
-
private
|
79
|
-
|
80
|
-
def base_url
|
81
|
-
"#{protocol}://#{host}"
|
82
|
-
end
|
83
|
-
|
84
|
-
def client
|
85
|
-
return @client if @client
|
86
|
-
@rcfile.path = parent_options['profile'] if parent_options['profile']
|
87
|
-
@client = Twitter::Client.new(
|
88
|
-
:endpoint => base_url,
|
89
|
-
:consumer_key => @rcfile.default_consumer_key,
|
90
|
-
:consumer_secret => @rcfile.default_consumer_secret,
|
91
|
-
:oauth_token => @rcfile.default_token,
|
92
|
-
:oauth_token_secret => @rcfile.default_secret
|
93
|
-
)
|
94
|
-
end
|
95
|
-
|
96
|
-
def host
|
97
|
-
parent_options['host'] || DEFAULT_HOST
|
98
|
-
end
|
99
|
-
|
100
|
-
def protocol
|
101
|
-
parent_options['no_ssl'] ? 'http' : DEFAULT_PROTOCOL
|
73
|
+
say "Run `#{File.basename($0)} unfollow users #{screen_names.join(' ')}` to stop."
|
102
74
|
end
|
103
75
|
|
104
76
|
end
|
data/lib/t/cli/list.rb
CHANGED
@@ -1,17 +1,16 @@
|
|
1
1
|
require 'action_view'
|
2
2
|
require 'pager'
|
3
3
|
require 't/rcfile'
|
4
|
+
require 't/requestable'
|
4
5
|
require 'thor'
|
5
|
-
require 'twitter'
|
6
6
|
|
7
7
|
module T
|
8
8
|
class CLI
|
9
9
|
class List < Thor
|
10
10
|
include ActionView::Helpers::DateHelper
|
11
11
|
include Pager
|
12
|
+
include T::Requestable
|
12
13
|
|
13
|
-
DEFAULT_HOST = 'api.twitter.com'
|
14
|
-
DEFAULT_PROTOCOL = 'https'
|
15
14
|
DEFAULT_NUM_RESULTS = 20
|
16
15
|
MAX_SCREEN_NAME_SIZE = 20
|
17
16
|
|
@@ -54,32 +53,6 @@ module T
|
|
54
53
|
require 't/cli/list/remove'
|
55
54
|
subcommand 'remove', CLI::List::Remove
|
56
55
|
|
57
|
-
private
|
58
|
-
|
59
|
-
def base_url
|
60
|
-
"#{protocol}://#{host}"
|
61
|
-
end
|
62
|
-
|
63
|
-
def client
|
64
|
-
return @client if @client
|
65
|
-
@rcfile.path = parent_options['profile'] if parent_options['profile']
|
66
|
-
@client = Twitter::Client.new(
|
67
|
-
:endpoint => base_url,
|
68
|
-
:consumer_key => @rcfile.default_consumer_key,
|
69
|
-
:consumer_secret => @rcfile.default_consumer_secret,
|
70
|
-
:oauth_token => @rcfile.default_token,
|
71
|
-
:oauth_token_secret => @rcfile.default_secret
|
72
|
-
)
|
73
|
-
end
|
74
|
-
|
75
|
-
def host
|
76
|
-
parent_options['host'] || DEFAULT_HOST
|
77
|
-
end
|
78
|
-
|
79
|
-
def protocol
|
80
|
-
parent_options['no_ssl'] ? 'http' : DEFAULT_PROTOCOL
|
81
|
-
end
|
82
|
-
|
83
56
|
end
|
84
57
|
end
|
85
58
|
end
|
data/lib/t/cli/list/add.rb
CHANGED
@@ -1,19 +1,21 @@
|
|
1
1
|
require 'active_support/core_ext/array/grouping'
|
2
|
+
require 'retryable'
|
3
|
+
require 't/core_ext/enumerable'
|
2
4
|
require 't/core_ext/string'
|
3
5
|
require 't/collectable'
|
4
6
|
require 't/rcfile'
|
7
|
+
require 't/requestable'
|
5
8
|
require 'thor'
|
6
|
-
require 'twitter'
|
7
9
|
|
8
10
|
module T
|
9
11
|
class CLI
|
10
12
|
class List
|
11
13
|
class Add < Thor
|
12
14
|
include T::Collectable
|
15
|
+
include T::Requestable
|
13
16
|
|
14
|
-
DEFAULT_HOST = 'api.twitter.com'
|
15
|
-
DEFAULT_PROTOCOL = 'https'
|
16
17
|
MAX_USERS_PER_LIST = 500
|
18
|
+
MAX_USERS_PER_REQUEST = 100
|
17
19
|
|
18
20
|
check_unknown_options!
|
19
21
|
|
@@ -44,13 +46,15 @@ module T
|
|
44
46
|
return unless yes? "Are you sure you want to add #{number} #{number == 1 ? 'friend' : 'friends'} to the list \"#{list_name}\"?"
|
45
47
|
end
|
46
48
|
max_members_to_add = MAX_USERS_PER_LIST - existing_list_members
|
47
|
-
list_member_ids_to_add[0...max_members_to_add].in_groups_of(
|
48
|
-
|
49
|
+
list_member_ids_to_add[0...max_members_to_add].in_groups_of(MAX_USERS_PER_REQUEST, false).threaded_each do |user_id_group|
|
50
|
+
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
51
|
+
client.list_add_members(list_name, user_id_group)
|
52
|
+
end
|
49
53
|
end
|
50
54
|
number_added = [number, max_members_to_add].min
|
51
55
|
say "@#{@rcfile.default_profile[0]} added #{number_added} #{number_added == 1 ? 'friend' : 'friends'} to the list \"#{list_name}\"."
|
52
56
|
say
|
53
|
-
say "Run `#{$0} list remove all friends #{list_name}` to undo."
|
57
|
+
say "Run `#{File.basename($0)} list remove all friends #{list_name}` to undo."
|
54
58
|
end
|
55
59
|
|
56
60
|
desc "followers LIST_NAME", "Add all followers to a list."
|
@@ -75,13 +79,15 @@ module T
|
|
75
79
|
return unless yes? "Are you sure you want to add #{number} #{number == 1 ? 'follower' : 'followers'} to the list \"#{list_name}\"?"
|
76
80
|
end
|
77
81
|
max_members_to_add = MAX_USERS_PER_LIST - existing_list_members
|
78
|
-
list_member_ids_to_add[0...max_members_to_add].in_groups_of(
|
79
|
-
|
82
|
+
list_member_ids_to_add[0...max_members_to_add].in_groups_of(MAX_USERS_PER_REQUEST, false).threaded_each do |user_id_group|
|
83
|
+
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
84
|
+
client.list_add_members(list_name, user_id_group)
|
85
|
+
end
|
80
86
|
end
|
81
87
|
number_added = [number, max_members_to_add].min
|
82
88
|
say "@#{@rcfile.default_profile[0]} added #{number_added} #{number_added == 1 ? 'follower' : 'followers'} to the list \"#{list_name}\"."
|
83
89
|
say
|
84
|
-
say "Run `#{$0} list remove all followers #{list_name}` to undo."
|
90
|
+
say "Run `#{File.basename($0)} list remove all followers #{list_name}` to undo."
|
85
91
|
end
|
86
92
|
|
87
93
|
desc "listed FROM_LIST_NAME TO_LIST_NAME", "Add all list memebers to a list."
|
@@ -106,50 +112,30 @@ module T
|
|
106
112
|
return unless yes? "Are you sure you want to add #{number} #{number == 1 ? 'member' : 'members'} to the list \"#{to_list_name}\"?"
|
107
113
|
end
|
108
114
|
max_members_to_add = MAX_USERS_PER_LIST - existing_list_members
|
109
|
-
list_member_ids_to_add[0...max_members_to_add].in_groups_of(
|
110
|
-
|
115
|
+
list_member_ids_to_add[0...max_members_to_add].in_groups_of(MAX_USERS_PER_REQUEST, false).threaded_each do |user_id_group|
|
116
|
+
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
117
|
+
client.list_add_members(to_list_name, user_id_group)
|
118
|
+
end
|
111
119
|
end
|
112
120
|
number_added = [number, max_members_to_add].min
|
113
121
|
say "@#{@rcfile.default_profile[0]} added #{number_added} #{number_added == 1 ? 'member' : 'members'} to the list \"#{to_list_name}\"."
|
114
122
|
say
|
115
|
-
say "Run `#{$0} list remove all listed #{from_list_name} #{to_list_name}` to undo."
|
123
|
+
say "Run `#{File.basename($0)} list remove all listed #{from_list_name} #{to_list_name}` to undo."
|
116
124
|
end
|
117
125
|
|
118
126
|
desc "users LIST_NAME SCREEN_NAME [SCREEN_NAME...]", "Add users to a list."
|
119
127
|
def users(list_name, screen_name, *screen_names)
|
120
128
|
screen_names.unshift(screen_name)
|
121
|
-
screen_names.map!
|
122
|
-
|
129
|
+
screen_names.map!(&:strip_at)
|
130
|
+
screen_names.in_groups_of(MAX_USERS_PER_REQUEST, false).threaded_each do |user_id_group|
|
131
|
+
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
132
|
+
client.list_add_members(list_name, user_id_group)
|
133
|
+
end
|
134
|
+
end
|
123
135
|
number = screen_names.length
|
124
136
|
say "@#{@rcfile.default_profile[0]} added #{number} #{number == 1 ? 'user' : 'users'} to the list \"#{list_name}\"."
|
125
137
|
say
|
126
|
-
say "Run `#{$0} list remove users #{list_name} #{screen_names.join(' ')}` to undo."
|
127
|
-
end
|
128
|
-
|
129
|
-
private
|
130
|
-
|
131
|
-
def base_url
|
132
|
-
"#{protocol}://#{host}"
|
133
|
-
end
|
134
|
-
|
135
|
-
def client
|
136
|
-
return @client if @client
|
137
|
-
@rcfile.path = parent_options['profile'] if parent_options['profile']
|
138
|
-
@client = Twitter::Client.new(
|
139
|
-
:endpoint => base_url,
|
140
|
-
:consumer_key => @rcfile.default_consumer_key,
|
141
|
-
:consumer_secret => @rcfile.default_consumer_secret,
|
142
|
-
:oauth_token => @rcfile.default_token,
|
143
|
-
:oauth_token_secret => @rcfile.default_secret
|
144
|
-
)
|
145
|
-
end
|
146
|
-
|
147
|
-
def host
|
148
|
-
parent_options['host'] || DEFAULT_HOST
|
149
|
-
end
|
150
|
-
|
151
|
-
def protocol
|
152
|
-
parent_options['no_ssl'] ? 'http' : DEFAULT_PROTOCOL
|
138
|
+
say "Run `#{File.basename($0)} list remove users #{list_name} #{screen_names.join(' ')}` to undo."
|
153
139
|
end
|
154
140
|
|
155
141
|
end
|