t 0.4.0 → 0.5.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/.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
|