t 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +0 -1
- data/.travis.yml +0 -1
- data/README.md +28 -99
- data/lib/t.rb +0 -13
- data/lib/t/cli.rb +385 -147
- data/lib/t/collectable.rb +1 -1
- data/lib/t/delete.rb +84 -0
- data/lib/t/list.rb +103 -0
- data/lib/t/search.rb +133 -0
- data/lib/t/set.rb +57 -0
- data/lib/t/version.rb +1 -1
- data/spec/cli_spec.rb +330 -201
- data/spec/{cli/delete_spec.rb → delete_spec.rb} +86 -124
- data/spec/fixtures/recommendations.json +1 -1
- data/spec/fixtures/users.json +1 -0
- data/spec/helper.rb +0 -1
- data/spec/{cli/list_spec.rb → list_spec.rb} +77 -6
- data/spec/rcfile_spec.rb +0 -4
- data/spec/{cli/search_spec.rb → search_spec.rb} +1 -1
- data/spec/{cli/set_spec.rb → set_spec.rb} +1 -1
- data/t.gemspec +2 -2
- metadata +26 -36
- data/lib/t/cli/delete.rb +0 -85
- data/lib/t/cli/follow.rb +0 -78
- data/lib/t/cli/list.rb +0 -58
- data/lib/t/cli/list/add.rb +0 -144
- data/lib/t/cli/list/remove.rb +0 -136
- data/lib/t/cli/search.rb +0 -124
- data/lib/t/cli/set.rb +0 -59
- data/lib/t/cli/unfollow.rb +0 -121
- data/spec/cli/follow_spec.rb +0 -240
- data/spec/cli/list/add_spec.rb +0 -518
- data/spec/cli/list/remove_spec.rb +0 -422
- data/spec/cli/unfollow_spec.rb +0 -410
data/lib/t/cli/list/remove.rb
DELETED
@@ -1,136 +0,0 @@
|
|
1
|
-
require 'active_support/core_ext/array/grouping'
|
2
|
-
require 'retryable'
|
3
|
-
require 't/core_ext/enumerable'
|
4
|
-
require 't/core_ext/string'
|
5
|
-
require 't/collectable'
|
6
|
-
require 't/rcfile'
|
7
|
-
require 't/requestable'
|
8
|
-
require 'thor'
|
9
|
-
|
10
|
-
module T
|
11
|
-
class CLI
|
12
|
-
class List
|
13
|
-
class Remove < Thor
|
14
|
-
include T::Collectable
|
15
|
-
include T::Requestable
|
16
|
-
|
17
|
-
MAX_USERS_PER_REQUEST = 100
|
18
|
-
|
19
|
-
check_unknown_options!
|
20
|
-
|
21
|
-
def initialize(*)
|
22
|
-
super
|
23
|
-
@rcfile = RCFile.instance
|
24
|
-
end
|
25
|
-
|
26
|
-
desc "friends LIST_NAME", "Remove all friends from a list."
|
27
|
-
def friends(list_name)
|
28
|
-
list_member_ids = collect_with_cursor do |cursor|
|
29
|
-
client.list_members(list_name, :cursor => cursor, :skip_status => true, :include_entities => false)
|
30
|
-
end
|
31
|
-
friend_ids = collect_with_cursor do |cursor|
|
32
|
-
client.friend_ids(:cursor => cursor)
|
33
|
-
end
|
34
|
-
list_member_ids_to_remove = (friend_ids - list_member_ids)
|
35
|
-
number = list_member_ids_to_remove.length
|
36
|
-
if number.zero?
|
37
|
-
return say "None of @#{@rcfile.default_profile[0]}'s friends are members of the list \"#{list_name}\"."
|
38
|
-
else
|
39
|
-
return unless yes? "Are you sure you want to remove #{number} #{number == 1 ? 'friend' : 'friends'} from the list \"#{list_name}\"?"
|
40
|
-
end
|
41
|
-
list_member_ids_to_remove.in_groups_of(MAX_USERS_PER_REQUEST, false).threaded_each do |user_id_group|
|
42
|
-
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
43
|
-
client.list_remove_members(list_name, user_id_group)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
say "@#{@rcfile.default_profile[0]} removed #{number} #{number == 1 ? 'friend' : 'friends'} from the list \"#{list_name}\"."
|
47
|
-
say
|
48
|
-
say "Run `#{File.basename($0)} list add all friends #{list_name}` to undo."
|
49
|
-
end
|
50
|
-
|
51
|
-
desc "followers LIST_NAME", "Remove all followers from a list."
|
52
|
-
def followers(list_name)
|
53
|
-
list_member_ids = collect_with_cursor do |cursor|
|
54
|
-
client.list_members(list_name, :cursor => cursor, :skip_status => true, :include_entities => false)
|
55
|
-
end
|
56
|
-
follower_ids = collect_with_cursor do |cursor|
|
57
|
-
client.follower_ids(:cursor => cursor)
|
58
|
-
end
|
59
|
-
list_member_ids_to_remove = (follower_ids - list_member_ids)
|
60
|
-
number = list_member_ids_to_remove.length
|
61
|
-
if number.zero?
|
62
|
-
return say "None of @#{@rcfile.default_profile[0]}'s followers are members of the list \"#{list_name}\"."
|
63
|
-
else
|
64
|
-
return unless yes? "Are you sure you want to remove #{number} #{number == 1 ? 'follower' : 'followers'} from the list \"#{list_name}\"?"
|
65
|
-
end
|
66
|
-
list_member_ids_to_remove.in_groups_of(MAX_USERS_PER_REQUEST, false).threaded_each do |user_id_group|
|
67
|
-
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
68
|
-
client.list_remove_members(list_name, user_id_group)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
say "@#{@rcfile.default_profile[0]} removed #{number} #{number == 1 ? 'follower' : 'followers'} from the list \"#{list_name}\"."
|
72
|
-
say
|
73
|
-
say "Run `#{File.basename($0)} list add all followers #{list_name}` to undo."
|
74
|
-
end
|
75
|
-
|
76
|
-
desc "listed FROM_LIST_NAME TO_LIST_NAME", "Remove all list members from a list."
|
77
|
-
def listed(from_list_name, to_list_name)
|
78
|
-
to_list_members = collect_with_cursor do |cursor|
|
79
|
-
client.list_members(to_list_name, :cursor => cursor, :skip_status => true, :include_entities => false)
|
80
|
-
end
|
81
|
-
from_list_members = collect_with_cursor do |cursor|
|
82
|
-
client.list_members(from_list_name, :cursor => cursor, :skip_status => true, :include_entities => false)
|
83
|
-
end
|
84
|
-
list_member_ids_to_remove = (from_list_members.collect(&:id) - to_list_members.collect(&:id))
|
85
|
-
number = list_member_ids_to_remove.length
|
86
|
-
if number.zero?
|
87
|
-
return say "None of the members of the list \"#{from_list_name}\" are members of the list \"#{to_list_name}\"."
|
88
|
-
else
|
89
|
-
return unless yes? "Are you sure you want to remove #{number} #{number == 1 ? 'member' : 'members'} from the list \"#{to_list_name}\"?"
|
90
|
-
end
|
91
|
-
list_member_ids_to_remove.in_groups_of(MAX_USERS_PER_REQUEST, false).threaded_each do |user_id_group|
|
92
|
-
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
93
|
-
client.list_remove_members(to_list_name, user_id_group)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
say "@#{@rcfile.default_profile[0]} removed #{number} #{number == 1 ? 'member' : 'members'} from the list \"#{to_list_name}\"."
|
97
|
-
say
|
98
|
-
say "Run `#{File.basename($0)} list add all listed #{from_list_name} #{to_list_name}` to undo."
|
99
|
-
end
|
100
|
-
|
101
|
-
desc "members LIST_NAME", "Remove all members from a list."
|
102
|
-
def members(list_name)
|
103
|
-
list_members = collect_with_cursor do |cursor|
|
104
|
-
client.list_members(list_name, :cursor => cursor, :skip_status => true, :include_entities => false)
|
105
|
-
end
|
106
|
-
number = list_members.length
|
107
|
-
return say "The list \"#{list_name}\" doesn't have any members." if number.zero?
|
108
|
-
return unless yes? "Are you sure you want to remove #{number} #{number == 1 ? 'member' : 'members'} from the list \"#{list_name}\"?"
|
109
|
-
list_members.collect(&:id).in_groups_of(MAX_USERS_PER_REQUEST, false).threaded_each do |user_id_group|
|
110
|
-
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
111
|
-
client.list_remove_members(list_name, user_id_group)
|
112
|
-
end
|
113
|
-
end
|
114
|
-
say "@#{@rcfile.default_profile[0]} removed #{number} #{number == 1 ? 'member' : 'members'} from the list \"#{list_name}\"."
|
115
|
-
end
|
116
|
-
map %w(all) => :members
|
117
|
-
|
118
|
-
desc "users LIST_NAME SCREEN_NAME [SCREEN_NAME...]", "Remove users from a list."
|
119
|
-
def users(list_name, screen_name, *screen_names)
|
120
|
-
screen_names.unshift(screen_name)
|
121
|
-
screen_names.map!(&:strip_at)
|
122
|
-
screen_names.in_groups_of(MAX_USERS_PER_REQUEST, false).threaded_each do |user_id_group|
|
123
|
-
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
124
|
-
client.list_remove_members(list_name, user_id_group)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
number = screen_names.length
|
128
|
-
say "@#{@rcfile.default_profile[0]} removed #{number} #{number == 1 ? 'user' : 'users'} from the list \"#{list_name}\"."
|
129
|
-
say
|
130
|
-
say "Run `#{File.basename($0)} list add users #{list_name} #{screen_names.join(' ')}` to undo."
|
131
|
-
end
|
132
|
-
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
data/lib/t/cli/search.rb
DELETED
@@ -1,124 +0,0 @@
|
|
1
|
-
require 'action_view'
|
2
|
-
require 'pager'
|
3
|
-
require 'retryable'
|
4
|
-
require 't/core_ext/enumerable'
|
5
|
-
require 't/rcfile'
|
6
|
-
require 't/requestable'
|
7
|
-
require 'thor'
|
8
|
-
|
9
|
-
module T
|
10
|
-
class CLI
|
11
|
-
class Search < Thor
|
12
|
-
include ActionView::Helpers::DateHelper
|
13
|
-
include Pager
|
14
|
-
include T::Requestable
|
15
|
-
|
16
|
-
DEFAULT_NUM_RESULTS = 20
|
17
|
-
MAX_PAGES = 16
|
18
|
-
MAX_NUM_RESULTS = 200
|
19
|
-
MAX_SCREEN_NAME_SIZE = 20
|
20
|
-
|
21
|
-
check_unknown_options!
|
22
|
-
|
23
|
-
def initialize(*)
|
24
|
-
super
|
25
|
-
@rcfile = RCFile.instance
|
26
|
-
end
|
27
|
-
|
28
|
-
desc "all QUERY", "Returns the #{DEFAULT_NUM_RESULTS} most recent Tweets that match a specified query."
|
29
|
-
method_option :number, :aliases => "-n", :type => :numeric, :default => DEFAULT_NUM_RESULTS
|
30
|
-
method_option :reverse, :aliases => "-r", :type => :boolean, :default => false
|
31
|
-
def all(query)
|
32
|
-
defaults = {:include_entities => false}
|
33
|
-
defaults.merge!(:rpp => options['number']) if options['number']
|
34
|
-
timeline = client.search(query, defaults)
|
35
|
-
timeline.reverse! if options['reverse']
|
36
|
-
page unless T.env.test?
|
37
|
-
timeline.each do |status|
|
38
|
-
say "#{status.from_user.rjust(MAX_SCREEN_NAME_SIZE)}: #{status.text} (#{time_ago_in_words(status.created_at)} ago)"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
desc "favorites QUERY", "Returns Tweets you've favorited that mach a specified query."
|
43
|
-
def favorites(query)
|
44
|
-
timeline = 1.upto(MAX_PAGES).threaded_map do |page|
|
45
|
-
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
46
|
-
client.favorites(:page => page, :count => MAX_NUM_RESULTS).select do |status|
|
47
|
-
/#{query}/i.match(status.text)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
page unless T.env.test?
|
52
|
-
timeline.flatten.compact.each do |status|
|
53
|
-
say "#{status.user.screen_name.rjust(MAX_SCREEN_NAME_SIZE)}: #{status.text} (#{time_ago_in_words(status.created_at)} ago)"
|
54
|
-
end
|
55
|
-
end
|
56
|
-
map %w(faves) => :favorites
|
57
|
-
|
58
|
-
desc "mentions QUERY", "Returns Tweets mentioning you that mach a specified query."
|
59
|
-
def mentions(query)
|
60
|
-
timeline = 1.upto(MAX_PAGES).threaded_map do |page|
|
61
|
-
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
62
|
-
client.mentions(:page => page, :count => MAX_NUM_RESULTS).select do |status|
|
63
|
-
/#{query}/i.match(status.text)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
page unless T.env.test?
|
68
|
-
timeline.flatten.compact.each do |status|
|
69
|
-
say "#{status.user.screen_name.rjust(MAX_SCREEN_NAME_SIZE)}: #{status.text} (#{time_ago_in_words(status.created_at)} ago)"
|
70
|
-
end
|
71
|
-
end
|
72
|
-
map %w(replies) => :mentions
|
73
|
-
|
74
|
-
desc "retweets QUERY", "Returns Tweets you've retweeted that mach a specified query."
|
75
|
-
def retweets(query)
|
76
|
-
timeline = 1.upto(MAX_PAGES).threaded_map do |page|
|
77
|
-
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
78
|
-
client.retweeted_by(:page => page, :count => MAX_NUM_RESULTS).select do |status|
|
79
|
-
/#{query}/i.match(status.text)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
page unless T.env.test?
|
84
|
-
timeline.flatten.compact.each do |status|
|
85
|
-
say "#{status.user.screen_name.rjust(MAX_SCREEN_NAME_SIZE)}: #{status.text} (#{time_ago_in_words(status.created_at)} ago)"
|
86
|
-
end
|
87
|
-
end
|
88
|
-
map %w(rts) => :retweets
|
89
|
-
|
90
|
-
desc "timeline QUERY", "Returns Tweets in your timeline that match a specified query."
|
91
|
-
def timeline(query)
|
92
|
-
timeline = 1.upto(MAX_PAGES).threaded_map do |page|
|
93
|
-
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
94
|
-
client.home_timeline(:page => page, :count => MAX_NUM_RESULTS).select do |status|
|
95
|
-
/#{query}/i.match(status.text)
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
page unless T.env.test?
|
100
|
-
timeline.flatten.compact.each do |status|
|
101
|
-
say "#{status.user.screen_name.rjust(MAX_SCREEN_NAME_SIZE)}: #{status.text} (#{time_ago_in_words(status.created_at)} ago)"
|
102
|
-
end
|
103
|
-
end
|
104
|
-
map %w(tl) => :timeline
|
105
|
-
|
106
|
-
desc "user SCREEN_NAME QUERY", "Returns Tweets in a user's timeline that match a specified query."
|
107
|
-
def user(screen_name, query)
|
108
|
-
screen_name = screen_name.strip_at
|
109
|
-
timeline = 1.upto(MAX_PAGES).threaded_map do |page|
|
110
|
-
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
111
|
-
client.user_timeline(screen_name, :page => page, :count => MAX_NUM_RESULTS).select do |status|
|
112
|
-
/#{query}/i.match(status.text)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
page unless T.env.test?
|
117
|
-
timeline.flatten.compact.each do |status|
|
118
|
-
say "#{status.user.screen_name.rjust(MAX_SCREEN_NAME_SIZE)}: #{status.text} (#{time_ago_in_words(status.created_at)} ago)"
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
data/lib/t/cli/set.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
require 't/core_ext/string'
|
2
|
-
require 't/rcfile'
|
3
|
-
require 't/requestable'
|
4
|
-
require 'thor'
|
5
|
-
|
6
|
-
module T
|
7
|
-
class CLI
|
8
|
-
class Set < Thor
|
9
|
-
include T::Requestable
|
10
|
-
|
11
|
-
check_unknown_options!
|
12
|
-
|
13
|
-
def initialize(*)
|
14
|
-
super
|
15
|
-
@rcfile = RCFile.instance
|
16
|
-
end
|
17
|
-
|
18
|
-
desc "bio DESCRIPTION", "Edits your Bio information on your Twitter profile."
|
19
|
-
def bio(description)
|
20
|
-
client.update_profile(:description => description, :include_entities => false)
|
21
|
-
say "@#{@rcfile.default_profile[0]}'s bio has been updated."
|
22
|
-
end
|
23
|
-
|
24
|
-
desc "default SCREEN_NAME [CONSUMER_KEY]", "Set your default account."
|
25
|
-
def default(screen_name, consumer_key=nil)
|
26
|
-
screen_name = screen_name.strip_at
|
27
|
-
@rcfile.path = parent_options['profile'] if parent_options['profile']
|
28
|
-
consumer_key = @rcfile[screen_name].keys.last if consumer_key.nil?
|
29
|
-
@rcfile.default_profile = {'username' => screen_name, 'consumer_key' => consumer_key}
|
30
|
-
say "Default account has been updated."
|
31
|
-
end
|
32
|
-
|
33
|
-
desc "language LANGUAGE_NAME", "Selects the language you'd like to receive notifications in."
|
34
|
-
def language(language_name)
|
35
|
-
client.settings(:lang => language_name)
|
36
|
-
say "@#{@rcfile.default_profile[0]}'s language has been updated."
|
37
|
-
end
|
38
|
-
|
39
|
-
desc "location PLACE_NAME", "Updates the location field in your profile."
|
40
|
-
def location(place_name)
|
41
|
-
client.update_profile(:location => place_name, :include_entities => false)
|
42
|
-
say "@#{@rcfile.default_profile[0]}'s location has been updated."
|
43
|
-
end
|
44
|
-
|
45
|
-
desc "name NAME", "Sets the name field on your Twitter profile."
|
46
|
-
def name(name)
|
47
|
-
client.update_profile(:name => name, :include_entities => false)
|
48
|
-
say "@#{@rcfile.default_profile[0]}'s name has been updated."
|
49
|
-
end
|
50
|
-
|
51
|
-
desc "url URL", "Sets the URL field on your profile."
|
52
|
-
def url(url)
|
53
|
-
client.update_profile(:url => url, :include_entities => false)
|
54
|
-
say "@#{@rcfile.default_profile[0]}'s URL has been updated."
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
data/lib/t/cli/unfollow.rb
DELETED
@@ -1,121 +0,0 @@
|
|
1
|
-
require 'retryable'
|
2
|
-
require 't/core_ext/enumerable'
|
3
|
-
require 't/core_ext/string'
|
4
|
-
require 't/collectable'
|
5
|
-
require 't/rcfile'
|
6
|
-
require 't/requestable'
|
7
|
-
require 'thor'
|
8
|
-
|
9
|
-
module T
|
10
|
-
class CLI
|
11
|
-
class Unfollow < Thor
|
12
|
-
include T::Collectable
|
13
|
-
include T::Requestable
|
14
|
-
|
15
|
-
check_unknown_options!
|
16
|
-
|
17
|
-
def initialize(*)
|
18
|
-
super
|
19
|
-
@rcfile = RCFile.instance
|
20
|
-
end
|
21
|
-
|
22
|
-
desc "listed LIST_NAME", "Unfollow all members of a list."
|
23
|
-
def listed(list_name)
|
24
|
-
list_member_collection = collect_with_cursor do |cursor|
|
25
|
-
client.list_members(list_name, :cursor => cursor, :include_entities => false, :skip_status => true)
|
26
|
-
end
|
27
|
-
number = list_member_collection.length
|
28
|
-
return say "@#{@rcfile.default_profile[0]} is already not following any list members." if number.zero?
|
29
|
-
return unless yes? "Are you sure you want to unfollow #{number} #{number == 1 ? 'user' : 'users'}?"
|
30
|
-
list_member_collection.threaded_map do |list_member|
|
31
|
-
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
32
|
-
client.unfollow(list_member.id, :include_entities => false)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
say "@#{@rcfile.default_profile[0]} is no longer following #{number} #{number == 1 ? 'user' : 'users'}."
|
36
|
-
say
|
37
|
-
say "Run `#{File.basename($0)} follow all listed #{list_name}` to follow again."
|
38
|
-
end
|
39
|
-
|
40
|
-
desc "followers", "Unfollow all followers."
|
41
|
-
def followers
|
42
|
-
follower_ids = collect_with_cursor do |cursor|
|
43
|
-
client.follower_ids(:cursor => cursor)
|
44
|
-
end
|
45
|
-
friend_ids = collect_with_cursor do |cursor|
|
46
|
-
friends = client.friend_ids(:cursor => cursor)
|
47
|
-
end
|
48
|
-
follow_ids = (follower_ids - friend_ids)
|
49
|
-
number = follow_ids.length
|
50
|
-
return say "@#{@rcfile.default_profile[0]} is already not following any followers." if number.zero?
|
51
|
-
return unless yes? "Are you sure you want to unfollow #{number} #{number == 1 ? 'user' : 'users'}?"
|
52
|
-
screen_names = follow_ids.threaded_map do |follow_id|
|
53
|
-
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
54
|
-
client.unfollow(follow_id, :include_entities => false)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
say "@#{@rcfile.default_profile[0]} is no longer following #{number} #{number == 1 ? 'user' : 'users'}."
|
58
|
-
say
|
59
|
-
say "Run `#{File.basename($0)} follow all followers` to stop."
|
60
|
-
end
|
61
|
-
|
62
|
-
desc "friends", "Unfollow all friends."
|
63
|
-
def friends
|
64
|
-
friend_ids = collect_with_cursor do |cursor|
|
65
|
-
client.friend_ids(:cursor => cursor)
|
66
|
-
end
|
67
|
-
number = friend_ids.length
|
68
|
-
return say "@#{@rcfile.default_profile[0]} is already not following anyone." if number.zero?
|
69
|
-
return unless yes? "Are you sure you want to unfollow #{number} #{number == 1 ? 'user' : 'users'}?"
|
70
|
-
screen_names = friend_ids.threaded_map do |friend_id|
|
71
|
-
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
72
|
-
user = client.unfollow(friend_id, :include_entities => false)
|
73
|
-
user.screen_name
|
74
|
-
end
|
75
|
-
end
|
76
|
-
say "@#{@rcfile.default_profile[0]} is no longer following #{number} #{number == 1 ? 'user' : 'users'}."
|
77
|
-
say
|
78
|
-
say "Run `#{File.basename($0)} follow users #{screen_names.join(' ')}` to follow again."
|
79
|
-
end
|
80
|
-
map %w(everyone everybody) => :friends
|
81
|
-
|
82
|
-
desc "nonfollowers", "Unfollow all non-followers."
|
83
|
-
def nonfollowers
|
84
|
-
friend_ids = collect_with_cursor do |cursor|
|
85
|
-
client.friend_ids(:cursor => cursor)
|
86
|
-
end
|
87
|
-
follower_ids = collect_with_cursor do |cursor|
|
88
|
-
client.follower_ids(:cursor => cursor)
|
89
|
-
end
|
90
|
-
unfollow_ids = (friend_ids - follower_ids)
|
91
|
-
number = unfollow_ids.length
|
92
|
-
return say "@#{@rcfile.default_profile[0]} is already not following any non-followers." if number.zero?
|
93
|
-
return unless yes? "Are you sure you want to unfollow #{number} #{number == 1 ? 'user' : 'users'}?"
|
94
|
-
screen_names = unfollow_ids.threaded_map do |unfollow_id|
|
95
|
-
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
96
|
-
user = client.unfollow(unfollow_id, :include_entities => false)
|
97
|
-
user.screen_name
|
98
|
-
end
|
99
|
-
end
|
100
|
-
say "@#{@rcfile.default_profile[0]} is no longer following #{number} #{number == 1 ? 'user' : 'users'}."
|
101
|
-
say
|
102
|
-
say "Run `#{File.basename($0)} follow users #{screen_names.join(' ')}` to follow again."
|
103
|
-
end
|
104
|
-
|
105
|
-
desc "users SCREEN_NAME [SCREEN_NAME...]", "Allows you to stop following users."
|
106
|
-
def users(screen_name, *screen_names)
|
107
|
-
screen_names.unshift(screen_name)
|
108
|
-
screen_names.threaded_map do |screen_name|
|
109
|
-
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
110
|
-
client.unfollow(screen_name, :include_entities => false)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
number = screen_names.length
|
114
|
-
say "@#{@rcfile.default_profile[0]} is no longer following #{number} #{number == 1 ? 'user' : 'users'}."
|
115
|
-
say
|
116
|
-
say "Run `#{File.basename($0)} follow users #{screen_names.join(' ')}` to follow again."
|
117
|
-
end
|
118
|
-
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
data/spec/cli/follow_spec.rb
DELETED
@@ -1,240 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
require 'helper'
|
3
|
-
|
4
|
-
describe T::CLI::Follow do
|
5
|
-
|
6
|
-
before do
|
7
|
-
rcfile = RCFile.instance
|
8
|
-
rcfile.path = fixture_path + "/.trc"
|
9
|
-
@t = T::CLI.new
|
10
|
-
@old_stderr = $stderr
|
11
|
-
$stderr = StringIO.new
|
12
|
-
@old_stdout = $stdout
|
13
|
-
$stdout = StringIO.new
|
14
|
-
end
|
15
|
-
|
16
|
-
after do
|
17
|
-
$stderr = @old_stderr
|
18
|
-
$stdout = @old_stdout
|
19
|
-
end
|
20
|
-
|
21
|
-
describe "#followers" do
|
22
|
-
before do
|
23
|
-
@t.options = @t.options.merge(:profile => fixture_path + "/.trc")
|
24
|
-
end
|
25
|
-
context "no followers" do
|
26
|
-
before do
|
27
|
-
stub_get("/1/followers/ids.json").
|
28
|
-
with(:query => {:cursor => "-1"}).
|
29
|
-
to_return(:body => fixture("friends_ids.json"), :headers => {:content_type => "application/json; charset=utf-8"})
|
30
|
-
stub_get("/1/friends/ids.json").
|
31
|
-
with(:query => {:cursor => "-1"}).
|
32
|
-
to_return(:body => fixture("friends_ids.json"), :headers => {:content_type => "application/json; charset=utf-8"})
|
33
|
-
end
|
34
|
-
it "should request the correct resource" do
|
35
|
-
@t.follow("followers")
|
36
|
-
a_get("/1/followers/ids.json").
|
37
|
-
with(:query => {:cursor => "-1"}).
|
38
|
-
should have_been_made
|
39
|
-
a_get("/1/friends/ids.json").
|
40
|
-
with(:query => {:cursor => "-1"}).
|
41
|
-
should have_been_made
|
42
|
-
end
|
43
|
-
it "should have the correct output" do
|
44
|
-
@t.follow("followers")
|
45
|
-
$stdout.string.chomp.should == "@testcli is already following all followers."
|
46
|
-
end
|
47
|
-
end
|
48
|
-
context "one follower" do
|
49
|
-
before do
|
50
|
-
stub_get("/1/followers/ids.json").
|
51
|
-
with(:query => {:cursor => "-1"}).
|
52
|
-
to_return(:body => fixture("friends_ids.json"), :headers => {:content_type => "application/json; charset=utf-8"})
|
53
|
-
stub_get("/1/friends/ids.json").
|
54
|
-
with(:query => {:cursor => "-1"}).
|
55
|
-
to_return(:body => fixture("followers_ids.json"), :headers => {:content_type => "application/json; charset=utf-8"})
|
56
|
-
end
|
57
|
-
it "should request the correct resource" do
|
58
|
-
stub_post("/1/friendships/create.json").
|
59
|
-
with(:body => {:user_id => "7505382", :include_entities => "false"}).
|
60
|
-
to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
|
61
|
-
$stdout.should_receive(:print).with("Are you sure you want to follow 1 user? ")
|
62
|
-
$stdin.should_receive(:gets).and_return("yes")
|
63
|
-
@t.follow("followers")
|
64
|
-
a_get("/1/followers/ids.json").
|
65
|
-
with(:query => {:cursor => "-1"}).
|
66
|
-
should have_been_made
|
67
|
-
a_get("/1/friends/ids.json").
|
68
|
-
with(:query => {:cursor => "-1"}).
|
69
|
-
should have_been_made
|
70
|
-
a_post("/1/friendships/create.json").
|
71
|
-
with(:body => {:user_id => "7505382", :include_entities => "false"}).
|
72
|
-
should have_been_made
|
73
|
-
end
|
74
|
-
context "yes" do
|
75
|
-
it "should have the correct output" do
|
76
|
-
stub_post("/1/friendships/create.json").
|
77
|
-
with(:body => {:user_id => "7505382", :include_entities => "false"}).
|
78
|
-
to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
|
79
|
-
$stdout.should_receive(:print).with("Are you sure you want to follow 1 user? ")
|
80
|
-
$stdin.should_receive(:gets).and_return("yes")
|
81
|
-
@t.follow("followers")
|
82
|
-
$stdout.string.should =~ /^@testcli is now following 1 more user\.$/
|
83
|
-
end
|
84
|
-
end
|
85
|
-
context "no" do
|
86
|
-
it "should have the correct output" do
|
87
|
-
$stdout.should_receive(:print).with("Are you sure you want to follow 1 user? ")
|
88
|
-
$stdin.should_receive(:gets).and_return("no")
|
89
|
-
@t.follow("followers")
|
90
|
-
$stdout.string.chomp.should == ""
|
91
|
-
end
|
92
|
-
end
|
93
|
-
context "Twitter is down" do
|
94
|
-
it "should retry 3 times and then raise an error" do
|
95
|
-
stub_post("/1/friendships/create.json").
|
96
|
-
with(:body => {:user_id => "7505382", :include_entities => "false"}).
|
97
|
-
to_return(:status => 502)
|
98
|
-
$stdout.should_receive(:print).with("Are you sure you want to follow 1 user? ")
|
99
|
-
$stdin.should_receive(:gets).and_return("yes")
|
100
|
-
lambda do
|
101
|
-
@t.follow("followers")
|
102
|
-
end.should raise_error("Twitter is down or being upgraded.")
|
103
|
-
a_post("/1/friendships/create.json").
|
104
|
-
with(:body => {:user_id => "7505382", :include_entities => "false"}).
|
105
|
-
should have_been_made.times(3)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
describe "#listed" do
|
112
|
-
before do
|
113
|
-
@t.options = @t.options.merge(:profile => fixture_path + "/.trc")
|
114
|
-
stub_get("/1/account/verify_credentials.json").
|
115
|
-
to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
|
116
|
-
end
|
117
|
-
context "no users" do
|
118
|
-
before do
|
119
|
-
stub_get("/1/lists/members.json").
|
120
|
-
with(:query => {:cursor => "-1", :include_entities => "false", :owner_screen_name => "sferik", :skip_status => "true", :slug => "presidents"}).
|
121
|
-
to_return(:body => fixture("empty_cursor.json"), :headers => {:content_type => "application/json; charset=utf-8"})
|
122
|
-
end
|
123
|
-
it "should request the correct resource" do
|
124
|
-
@t.follow("listed", "presidents")
|
125
|
-
a_get("/1/account/verify_credentials.json").
|
126
|
-
should have_been_made
|
127
|
-
a_get("/1/lists/members.json").
|
128
|
-
with(:query => {:cursor => "-1", :include_entities => "false", :owner_screen_name => "sferik", :skip_status => "true", :slug => "presidents"}).
|
129
|
-
should have_been_made
|
130
|
-
end
|
131
|
-
it "should have the correct output" do
|
132
|
-
@t.follow("listed", "presidents")
|
133
|
-
$stdout.string.chomp.should == "@testcli is already following all list members."
|
134
|
-
end
|
135
|
-
end
|
136
|
-
context "one user" do
|
137
|
-
before do
|
138
|
-
@t.options = @t.options.merge(:profile => fixture_path + "/.trc")
|
139
|
-
stub_get("/1/lists/members.json").
|
140
|
-
with(:query => {:cursor => "-1", :include_entities => "false", :owner_screen_name => "sferik", :skip_status => "true", :slug => "presidents"}).
|
141
|
-
to_return(:body => fixture("users_list.json"), :headers => {:content_type => "application/json; charset=utf-8"})
|
142
|
-
end
|
143
|
-
it "should request the correct resource" do
|
144
|
-
stub_post("/1/friendships/create.json").
|
145
|
-
with(:body => {:user_id => "7505382", :include_entities => "false"}).
|
146
|
-
to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
|
147
|
-
$stdout.should_receive(:print).with("Are you sure you want to follow 1 user? ")
|
148
|
-
$stdin.should_receive(:gets).and_return("yes")
|
149
|
-
@t.follow("listed", "presidents")
|
150
|
-
a_get("/1/account/verify_credentials.json").
|
151
|
-
should have_been_made
|
152
|
-
a_get("/1/lists/members.json").
|
153
|
-
with(:query => {:cursor => "-1", :include_entities => "false", :owner_screen_name => "sferik", :skip_status => "true", :slug => "presidents"}).
|
154
|
-
should have_been_made
|
155
|
-
a_post("/1/friendships/create.json").
|
156
|
-
with(:body => {:user_id => "7505382", :include_entities => "false"}).
|
157
|
-
should have_been_made
|
158
|
-
end
|
159
|
-
context "yes" do
|
160
|
-
it "should have the correct output" do
|
161
|
-
stub_post("/1/friendships/create.json").
|
162
|
-
with(:body => {:user_id => "7505382", :include_entities => "false"}).
|
163
|
-
to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
|
164
|
-
$stdout.should_receive(:print).with("Are you sure you want to follow 1 user? ")
|
165
|
-
$stdin.should_receive(:gets).and_return("yes")
|
166
|
-
@t.follow("listed", "presidents")
|
167
|
-
$stdout.string.should =~ /^@testcli is now following 1 more user\.$/
|
168
|
-
end
|
169
|
-
end
|
170
|
-
context "no" do
|
171
|
-
it "should have the correct output" do
|
172
|
-
$stdout.should_receive(:print).with("Are you sure you want to follow 1 user? ")
|
173
|
-
$stdin.should_receive(:gets).and_return("no")
|
174
|
-
@t.follow("listed", "presidents")
|
175
|
-
$stdout.string.chomp.should == ""
|
176
|
-
end
|
177
|
-
end
|
178
|
-
context "Twitter is down" do
|
179
|
-
it "should retry 3 times and then raise an error" do
|
180
|
-
stub_post("/1/friendships/create.json").
|
181
|
-
with(:body => {:user_id => "7505382", :include_entities => "false"}).
|
182
|
-
to_return(:status => 502)
|
183
|
-
$stdout.should_receive(:print).with("Are you sure you want to follow 1 user? ")
|
184
|
-
$stdin.should_receive(:gets).and_return("yes")
|
185
|
-
lambda do
|
186
|
-
@t.follow("listed", "presidents")
|
187
|
-
end.should raise_error("Twitter is down or being upgraded.")
|
188
|
-
a_post("/1/friendships/create.json").
|
189
|
-
with(:body => {:user_id => "7505382", :include_entities => "false"}).
|
190
|
-
should have_been_made.times(3)
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
describe "#users" do
|
197
|
-
before do
|
198
|
-
@t.options = @t.options.merge(:profile => fixture_path + "/.trc")
|
199
|
-
end
|
200
|
-
context "no users" do
|
201
|
-
it "should exit" do
|
202
|
-
lambda do
|
203
|
-
@t.follow("users")
|
204
|
-
end.should raise_error
|
205
|
-
end
|
206
|
-
end
|
207
|
-
context "one user" do
|
208
|
-
it "should request the correct resource" do
|
209
|
-
stub_post("/1/friendships/create.json").
|
210
|
-
with(:body => {:screen_name => "sferik", :include_entities => "false"}).
|
211
|
-
to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
|
212
|
-
@t.follow("users", "sferik")
|
213
|
-
a_post("/1/friendships/create.json").
|
214
|
-
with(:body => {:screen_name => "sferik", :include_entities => "false"}).
|
215
|
-
should have_been_made
|
216
|
-
end
|
217
|
-
it "should have the correct output" do
|
218
|
-
stub_post("/1/friendships/create.json").
|
219
|
-
with(:body => {:screen_name => "sferik", :include_entities => "false"}).
|
220
|
-
to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
|
221
|
-
@t.follow("users", "sferik")
|
222
|
-
$stdout.string.should =~ /^@testcli is now following 1 more user\.$/
|
223
|
-
end
|
224
|
-
context "Twitter is down" do
|
225
|
-
it "should retry 3 times and then raise an error" do
|
226
|
-
stub_post("/1/friendships/create.json").
|
227
|
-
with(:body => {:screen_name => "sferik", :include_entities => "false"}).
|
228
|
-
to_return(:status => 502)
|
229
|
-
lambda do
|
230
|
-
@t.follow("users", "sferik")
|
231
|
-
end.should raise_error("Twitter is down or being upgraded.")
|
232
|
-
a_post("/1/friendships/create.json").
|
233
|
-
with(:body => {:screen_name => "sferik", :include_entities => "false"}).
|
234
|
-
should have_been_made.times(3)
|
235
|
-
end
|
236
|
-
end
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
end
|