t 0.6.4 → 0.7.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/README.md +19 -6
- data/lib/t/cli.rb +489 -191
- data/lib/t/core_ext/string.rb +4 -0
- data/lib/t/delete.rb +38 -23
- data/lib/t/list.rb +117 -46
- data/lib/t/printable.rb +56 -5
- data/lib/t/search.rb +35 -10
- data/lib/t/version.rb +2 -2
- data/spec/cli_spec.rb +1302 -163
- data/spec/delete_spec.rb +143 -125
- data/spec/fixtures/false.json +1 -0
- data/spec/fixtures/list.json +1 -1
- data/spec/fixtures/lists.json +1 -0
- data/spec/fixtures/locations.json +1 -0
- data/spec/fixtures/not_found.json +1 -0
- data/spec/fixtures/trends.json +1 -0
- data/spec/fixtures/true.json +1 -0
- data/spec/helper.rb +4 -0
- data/spec/list_spec.rb +204 -66
- data/spec/rcfile_spec.rb +7 -7
- data/spec/search_spec.rb +189 -6
- data/t.gemspec +3 -1
- metadata +48 -4
data/lib/t/core_ext/string.rb
CHANGED
data/lib/t/delete.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 't/core_ext/enumerable'
|
1
2
|
require 't/core_ext/string'
|
2
3
|
require 't/rcfile'
|
3
4
|
require 't/requestable'
|
@@ -14,69 +15,83 @@ module T
|
|
14
15
|
@rcfile = RCFile.instance
|
15
16
|
end
|
16
17
|
|
17
|
-
desc "block
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
desc "block USER [USER...]", "Unblock users."
|
19
|
+
method_option :id, :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify input as Twitter user IDs instead of screen names."
|
20
|
+
method_option :force, :aliases => "-f", :type => :boolean, :default => false
|
21
|
+
def block(user, *users)
|
22
|
+
users.unshift(user)
|
23
|
+
if options['id']
|
24
|
+
users.map!(&:to_i)
|
25
|
+
else
|
26
|
+
users.map!(&:strip_ats)
|
27
|
+
end
|
28
|
+
users = users.threaded_map do |user|
|
23
29
|
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
24
|
-
client.unblock(
|
30
|
+
client.unblock(user, :include_entities => false)
|
25
31
|
end
|
26
32
|
end
|
27
|
-
number =
|
33
|
+
number = users.length
|
28
34
|
say "@#{@rcfile.default_profile[0]} unblocked #{number} #{number == 1 ? 'user' : 'users'}."
|
29
35
|
say
|
30
|
-
say "Run `#{File.basename($0)} block #{
|
36
|
+
say "Run `#{File.basename($0)} block #{users.map{|user| "@#{user.screen_name}"}.join(' ')}` to block."
|
31
37
|
end
|
32
38
|
|
33
39
|
desc "dm [DIRECT_MESSAGE_ID] [DIRECT_MESSAGE_ID...]", "Delete the last Direct Message sent."
|
40
|
+
method_option :force, :aliases => "-f", :type => :boolean, :default => false
|
34
41
|
def dm(direct_message_id, *direct_message_ids)
|
35
42
|
direct_message_ids.unshift(direct_message_id)
|
36
|
-
direct_message_ids.map!(&:strip_commas)
|
43
|
+
direct_message_ids.map!(&:strip_commas)
|
37
44
|
direct_message_ids.each do |direct_message_id|
|
38
45
|
unless options['force']
|
39
|
-
direct_message = client.direct_message(direct_message_id, :include_entities => false)
|
46
|
+
direct_message = client.direct_message(direct_message_id.to_i, :include_entities => false)
|
40
47
|
return unless yes? "Are you sure you want to permanently delete the direct message to @#{direct_message.recipient.screen_name}: \"#{direct_message.text}\"? [y/N]"
|
41
48
|
end
|
42
|
-
direct_message = client.direct_message_destroy(direct_message_id, :include_entities => false)
|
49
|
+
direct_message = client.direct_message_destroy(direct_message_id.to_i, :include_entities => false)
|
43
50
|
say "@#{@rcfile.default_profile[0]} deleted the direct message sent to @#{direct_message.recipient.screen_name}: \"#{direct_message.text}\""
|
44
51
|
end
|
45
52
|
end
|
46
|
-
map %w(m) => :dm
|
53
|
+
map %w(d m) => :dm
|
47
54
|
|
48
55
|
desc "favorite STATUS_ID [STATUS_ID...]", "Delete favorites."
|
56
|
+
method_option :force, :aliases => "-f", :type => :boolean, :default => false
|
49
57
|
def favorite(status_id, *status_ids)
|
50
58
|
status_ids.unshift(status_id)
|
59
|
+
status_ids.map!(&:strip_commas)
|
51
60
|
status_ids.each do |status_id|
|
52
61
|
unless options['force']
|
53
|
-
status = client.status(status_id, :include_entities => false, :include_my_retweet => false, :trim_user => true)
|
62
|
+
status = client.status(status_id.to_i, :include_entities => false, :include_my_retweet => false, :trim_user => true)
|
54
63
|
return unless yes? "Are you sure you want to remove @#{status.user.screen_name}'s status: \"#{status.text}\" from your favorites? [y/N]"
|
55
64
|
end
|
56
|
-
status = client.unfavorite(status_id, :include_entities => false)
|
65
|
+
status = client.unfavorite(status_id.to_i, :include_entities => false)
|
57
66
|
say "@#{@rcfile.default_profile[0]} unfavorited @#{status.user.screen_name}'s status: \"#{status.text}\""
|
58
67
|
end
|
59
68
|
end
|
60
|
-
map %w(
|
69
|
+
map %w(fave favourite) => :favorite
|
61
70
|
|
62
|
-
desc "list
|
63
|
-
|
71
|
+
desc "list LIST", "Delete a list."
|
72
|
+
method_option :force, :aliases => "-f", :type => :boolean, :default => false
|
73
|
+
method_option :id, :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify list via ID instead of slug."
|
74
|
+
def list(list)
|
75
|
+
list = list.to_i if options['id']
|
76
|
+
list = client.list(list)
|
64
77
|
unless options['force']
|
65
|
-
return unless yes? "Are you sure you want to permanently delete the list \"#{
|
78
|
+
return unless yes? "Are you sure you want to permanently delete the list \"#{list.name}\"? [y/N]"
|
66
79
|
end
|
67
|
-
|
68
|
-
say "@#{@rcfile.default_profile[0]} deleted the list \"#{
|
80
|
+
list = client.list_destroy(list.id)
|
81
|
+
say "@#{@rcfile.default_profile[0]} deleted the list \"#{list.name}\"."
|
69
82
|
end
|
70
83
|
|
71
84
|
desc "status STATUS_ID [STATUS_ID...]", "Delete Tweets."
|
85
|
+
method_option :force, :aliases => "-f", :type => :boolean, :default => false
|
72
86
|
def status(status_id, *status_ids)
|
73
87
|
status_ids.unshift(status_id)
|
88
|
+
status_ids.map!(&:strip_commas)
|
74
89
|
status_ids.each do |status_id|
|
75
90
|
unless options['force']
|
76
|
-
status = client.status(status_id, :include_entities => false, :include_my_retweet => false, :trim_user => true)
|
91
|
+
status = client.status(status_id.to_i, :include_entities => false, :include_my_retweet => false, :trim_user => true)
|
77
92
|
return unless yes? "Are you sure you want to permanently delete @#{status.user.screen_name}'s status: \"#{status.text}\"? [y/N]"
|
78
93
|
end
|
79
|
-
status = client.status_destroy(status_id, :include_entities => false, :trim_user => true)
|
94
|
+
status = client.status_destroy(status_id.to_i, :include_entities => false, :trim_user => true)
|
80
95
|
say "@#{@rcfile.default_profile[0]} deleted the status: \"#{status.text}\""
|
81
96
|
end
|
82
97
|
end
|
data/lib/t/list.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require 'action_view'
|
2
2
|
require 'active_support/core_ext/array/grouping'
|
3
|
+
require 'csv'
|
4
|
+
# 'fastercsv' required on Ruby versions < 1.9
|
5
|
+
require 'fastercsv' unless Array.new.respond_to?(:to_csv)
|
3
6
|
require 'retryable'
|
4
7
|
require 't/collectable'
|
5
8
|
require 't/core_ext/enumerable'
|
@@ -28,83 +31,151 @@ module T
|
|
28
31
|
@rcfile = RCFile.instance
|
29
32
|
end
|
30
33
|
|
31
|
-
desc "add
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
34
|
+
desc "add LIST USER [USER...]", "Add members to a list."
|
35
|
+
method_option :id, :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify input as Twitter user IDs instead of screen names."
|
36
|
+
def add(list, user, *users)
|
37
|
+
users.unshift(user)
|
38
|
+
if options['id']
|
39
|
+
users.map!(&:to_i)
|
40
|
+
else
|
41
|
+
users.map!(&:strip_ats)
|
42
|
+
end
|
43
|
+
users.in_groups_of(MAX_USERS_PER_REQUEST, false).threaded_each do |user_id_group|
|
36
44
|
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
37
|
-
client.list_add_members(
|
45
|
+
client.list_add_members(list, user_id_group)
|
38
46
|
end
|
39
47
|
end
|
40
|
-
number =
|
41
|
-
say "@#{@rcfile.default_profile[0]} added #{number} #{number == 1 ? 'member' : 'members'} to the list \"#{
|
48
|
+
number = users.length
|
49
|
+
say "@#{@rcfile.default_profile[0]} added #{number} #{number == 1 ? 'member' : 'members'} to the list \"#{list}\"."
|
42
50
|
say
|
43
|
-
|
51
|
+
if options['id']
|
52
|
+
say "Run `#{File.basename($0)} list remove --id #{list} #{users.join(' ')}` to undo."
|
53
|
+
else
|
54
|
+
say "Run `#{File.basename($0)} list remove #{list} #{users.map{|user| "@#{user}"}.join(' ')}` to undo."
|
55
|
+
end
|
44
56
|
end
|
45
57
|
|
46
|
-
desc "create
|
58
|
+
desc "create LIST [DESCRIPTION]", "Create a new list."
|
47
59
|
method_option :private, :aliases => "-p", :type => :boolean
|
48
|
-
def create(
|
60
|
+
def create(list, description="")
|
49
61
|
opts = description.blank? ? {} : {:description => description}
|
50
62
|
opts.merge!(:mode => 'private') if options['private']
|
51
|
-
client.list_create(
|
52
|
-
say "@#{@rcfile.default_profile[0]} created the list \"#{
|
63
|
+
client.list_create(list, opts)
|
64
|
+
say "@#{@rcfile.default_profile[0]} created the list \"#{list}\"."
|
53
65
|
end
|
54
66
|
|
55
|
-
desc "
|
56
|
-
method_option :
|
67
|
+
desc "information [USER/]LIST", "Retrieves detailed information about a Twitter list."
|
68
|
+
method_option :csv, :aliases => "-c", :type => :boolean, :default => false, :desc => "Output in CSV format."
|
69
|
+
def information(list)
|
70
|
+
owner, list = list.split('/')
|
71
|
+
if list.nil?
|
72
|
+
list = owner
|
73
|
+
owner = @rcfile.default_profile[0]
|
74
|
+
else
|
75
|
+
owner = if options['id']
|
76
|
+
owner.to_i
|
77
|
+
else
|
78
|
+
owner.strip_ats
|
79
|
+
end
|
80
|
+
end
|
81
|
+
list = client.list(owner, list)
|
82
|
+
if options['csv']
|
83
|
+
say ["ID", "Description", "Slug", "Screen name", "Created at", "Members", "Subscribers", "Following", "Mode", "URL"].to_csv
|
84
|
+
say [list.id, list.description, list.slug, list.user.screen_name, list.created_at.utc.strftime("%Y-%m-%d %H:%M:%S %z"), list.member_count, list.subscriber_count, list.following?, list.mode, "https://twitter.com#{list.uri}"].to_csv
|
85
|
+
else
|
86
|
+
array = []
|
87
|
+
array << ["ID", list.id.to_s]
|
88
|
+
array << ["Description", list.description] unless list.description.nil?
|
89
|
+
array << ["Slug", list.slug]
|
90
|
+
array << ["Screen name", "@#{list.user.screen_name}"]
|
91
|
+
created_at = list.created_at > 6.months.ago ? list.created_at.strftime("%b %e %H:%M") : list.created_at.strftime("%b %e %Y")
|
92
|
+
array << ["Created at", created_at]
|
93
|
+
array << ["Members", number_with_delimiter(list.member_count)]
|
94
|
+
array << ["Subscribers", number_with_delimiter(list.subscriber_count)]
|
95
|
+
status = list.following ? "Following" : "Not following"
|
96
|
+
array << ["Status", status]
|
97
|
+
array << ["Mode", list.mode]
|
98
|
+
array << ["URL", "https://twitter.com#{list.uri}"]
|
99
|
+
print_table(array)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
map %w(detail) => :information
|
103
|
+
|
104
|
+
desc "members [USER/]LIST", "Returns the members of a Twitter list."
|
105
|
+
method_option :csv, :aliases => "-c", :type => :boolean, :default => false, :desc => "Output in CSV format."
|
57
106
|
method_option :favorites, :aliases => "-v", :type => :boolean, :default => false, :desc => "Sort by total number of favorites."
|
58
107
|
method_option :followers, :aliases => "-f", :type => :boolean, :default => false, :desc => "Sort by total number of followers."
|
59
|
-
method_option :friends, :aliases => "-
|
60
|
-
method_option :
|
61
|
-
method_option :
|
108
|
+
method_option :friends, :aliases => "-e", :type => :boolean, :default => false, :desc => "Sort by total number of friends."
|
109
|
+
method_option :id, :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify user via ID instead of screen name."
|
110
|
+
method_option :listed, :aliases => "-s", :type => :boolean, :default => false, :desc => "Sort by number of list memberships."
|
111
|
+
method_option :long, :aliases => "-l", :type => :boolean, :default => false, :desc => "Output in long format."
|
112
|
+
method_option :posted, :aliases => "-p", :type => :boolean, :default => false, :desc => "Sort by the time when Twitter account was posted."
|
62
113
|
method_option :reverse, :aliases => "-r", :type => :boolean, :default => false, :desc => "Reverse the order of the sort."
|
63
114
|
method_option :tweets, :aliases => "-t", :type => :boolean, :default => false, :desc => "Sort by total number of Tweets."
|
64
115
|
method_option :unsorted, :aliases => "-u", :type => :boolean, :default => false, :desc => "Output is not sorted."
|
65
|
-
def members(
|
66
|
-
list =
|
67
|
-
|
68
|
-
|
116
|
+
def members(list)
|
117
|
+
owner, list = list.split('/')
|
118
|
+
if list.nil?
|
119
|
+
list = owner
|
120
|
+
owner = @rcfile.default_profile[0]
|
121
|
+
else
|
122
|
+
owner = if options['id']
|
123
|
+
owner.to_i
|
124
|
+
else
|
125
|
+
owner.strip_ats
|
126
|
+
end
|
127
|
+
end
|
69
128
|
users = collect_with_cursor do |cursor|
|
70
129
|
client.list_members(owner, list, :cursor => cursor, :include_entities => false, :skip_status => true)
|
71
130
|
end
|
72
|
-
|
131
|
+
print_users(users)
|
73
132
|
end
|
74
133
|
|
75
|
-
desc "remove
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
134
|
+
desc "remove LIST USER [USER...]", "Remove members from a list."
|
135
|
+
method_option :id, :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify input as Twitter user IDs instead of screen names."
|
136
|
+
def remove(list, user, *users)
|
137
|
+
users.unshift(user)
|
138
|
+
if options['id']
|
139
|
+
users.map!(&:to_i)
|
140
|
+
else
|
141
|
+
users.map!(&:strip_ats)
|
142
|
+
end
|
143
|
+
users.in_groups_of(MAX_USERS_PER_REQUEST, false).threaded_each do |user_id_group|
|
80
144
|
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
81
|
-
client.list_remove_members(
|
145
|
+
client.list_remove_members(list, user_id_group)
|
82
146
|
end
|
83
147
|
end
|
84
|
-
number =
|
85
|
-
say "@#{@rcfile.default_profile[0]} removed #{number} #{number == 1 ? 'member' : 'members'} from the list \"#{
|
148
|
+
number = users.length
|
149
|
+
say "@#{@rcfile.default_profile[0]} removed #{number} #{number == 1 ? 'member' : 'members'} from the list \"#{list}\"."
|
86
150
|
say
|
87
|
-
|
151
|
+
if options['id']
|
152
|
+
say "Run `#{File.basename($0)} list add --id #{list} #{users.join(' ')}` to undo."
|
153
|
+
else
|
154
|
+
say "Run `#{File.basename($0)} list add #{list} #{users.map{|user| "@#{user}"}.join(' ')}` to undo."
|
155
|
+
end
|
88
156
|
end
|
89
157
|
|
90
|
-
desc "timeline [
|
91
|
-
method_option :
|
92
|
-
method_option :
|
93
|
-
method_option :
|
94
|
-
method_option :friends, :aliases => "-d", :type => :boolean, :default => false, :desc => "Sort by total number of friends."
|
95
|
-
method_option :listed, :aliases => "-i", :type => :boolean, :default => false, :desc => "Sort by number of list memberships."
|
96
|
-
method_option :long, :aliases => "-l", :type => :boolean, :default => false, :desc => "List in long format."
|
158
|
+
desc "timeline [USER/]LIST", "Show tweet timeline for members of the specified list."
|
159
|
+
method_option :csv, :aliases => "-c", :type => :boolean, :default => false, :desc => "Output in CSV format."
|
160
|
+
method_option :id, :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify user via ID instead of screen name."
|
161
|
+
method_option :long, :aliases => "-l", :type => :boolean, :default => false, :desc => "Output in long format."
|
97
162
|
method_option :number, :aliases => "-n", :type => :numeric, :default => DEFAULT_NUM_RESULTS, :desc => "Limit the number of results."
|
98
163
|
method_option :reverse, :aliases => "-r", :type => :boolean, :default => false, :desc => "Reverse the order of the sort."
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
164
|
+
def timeline(list)
|
165
|
+
owner, list = list.split('/')
|
166
|
+
if list.nil?
|
167
|
+
list = owner
|
168
|
+
owner = @rcfile.default_profile[0]
|
169
|
+
else
|
170
|
+
owner = if options['id']
|
171
|
+
owner.to_i
|
172
|
+
else
|
173
|
+
owner.strip_ats
|
174
|
+
end
|
175
|
+
end
|
105
176
|
per_page = options['number'] || DEFAULT_NUM_RESULTS
|
106
177
|
statuses = client.list_timeline(owner, list, :include_entities => false, :per_page => per_page)
|
107
|
-
|
178
|
+
print_statuses(statuses)
|
108
179
|
end
|
109
180
|
map %w(tl) => :timeline
|
110
181
|
|
data/lib/t/printable.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
require 'action_view'
|
2
|
+
require 'csv'
|
3
|
+
# 'fastercsv' required on Ruby versions < 1.9
|
4
|
+
require 'fastercsv' unless Array.new.respond_to?(:to_csv)
|
2
5
|
require 'highline'
|
3
6
|
|
4
7
|
module T
|
@@ -20,9 +23,52 @@ module T
|
|
20
23
|
puts
|
21
24
|
end
|
22
25
|
|
23
|
-
def
|
26
|
+
def print_lists(lists)
|
27
|
+
lists = lists.sort_by{|list| list.slug.downcase} unless options['unsorted']
|
28
|
+
if options['posted']
|
29
|
+
lists = lists.sort_by{|user| user.created_at}
|
30
|
+
elsif options['members']
|
31
|
+
lists = lists.sort_by{|user| user.member_count}
|
32
|
+
elsif options['mode']
|
33
|
+
lists = lists.sort_by{|user| user.mode}
|
34
|
+
elsif options['subscribers']
|
35
|
+
lists = lists.sort_by{|user| user.subscriber_count}
|
36
|
+
end
|
37
|
+
lists.reverse! if options['reverse']
|
38
|
+
if options['csv']
|
39
|
+
say ["ID", "Created at", "Screen name", "Slug", "Members", "Subscribers", "Mode", "Description"].to_csv unless lists.empty?
|
40
|
+
lists.each do |list|
|
41
|
+
say [list.id, list.created_at.utc.strftime("%Y-%m-%d %H:%M:%S %z"), list.user.screen_name, list.slug, list.member_count, list.subscriber_count, list.mode, list.description].to_csv
|
42
|
+
end
|
43
|
+
elsif options['long']
|
44
|
+
array = lists.map do |list|
|
45
|
+
created_at = list.created_at > 6.months.ago ? list.created_at.strftime("%b %e %H:%M") : list.created_at.strftime("%b %e %Y")
|
46
|
+
[list.id.to_s, created_at, list.full_name, number_with_delimiter(list.member_count), number_with_delimiter(list.subscriber_count), list.mode, list.description]
|
47
|
+
end
|
48
|
+
if STDOUT.tty?
|
49
|
+
headings = ["ID", "Created at", "Slug", "Members", "Subscribers", "Mode", "Description"]
|
50
|
+
array.unshift(headings) unless lists.empty?
|
51
|
+
end
|
52
|
+
print_table(array)
|
53
|
+
else
|
54
|
+
if STDOUT.tty?
|
55
|
+
print_in_columns(lists.map(&:full_name))
|
56
|
+
else
|
57
|
+
lists.each do |list|
|
58
|
+
say list.full_name
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def print_statuses(statuses)
|
24
65
|
statuses.reverse! if options['reverse']
|
25
|
-
if options['
|
66
|
+
if options['csv']
|
67
|
+
say ["ID", "Posted at", "Screen name", "Text"].to_csv unless statuses.empty?
|
68
|
+
statuses.each do |status|
|
69
|
+
say [status.id, status.created_at.utc.strftime("%Y-%m-%d %H:%M:%S %z"), status.user.screen_name, status.text].to_csv
|
70
|
+
end
|
71
|
+
elsif options['long']
|
26
72
|
array = statuses.map do |status|
|
27
73
|
created_at = status.created_at > 6.months.ago ? status.created_at.strftime("%b %e %H:%M") : status.created_at.strftime("%b %e %Y")
|
28
74
|
[status.id.to_s, created_at, "@#{status.user.screen_name}", status.text.gsub(/\n+/, ' ')]
|
@@ -39,9 +85,9 @@ module T
|
|
39
85
|
end
|
40
86
|
end
|
41
87
|
|
42
|
-
def
|
88
|
+
def print_users(users)
|
43
89
|
users = users.sort_by{|user| user.screen_name.downcase} unless options['unsorted']
|
44
|
-
if options['
|
90
|
+
if options['posted']
|
45
91
|
users = users.sort_by{|user| user.created_at}
|
46
92
|
elsif options['favorites']
|
47
93
|
users = users.sort_by{|user| user.favourites_count}
|
@@ -55,7 +101,12 @@ module T
|
|
55
101
|
users = users.sort_by{|user| user.statuses_count}
|
56
102
|
end
|
57
103
|
users.reverse! if options['reverse']
|
58
|
-
if options['
|
104
|
+
if options['csv']
|
105
|
+
say ["ID", "Since", "Tweets", "Favorites", "Listed", "Following", "Followers", "Screen name", "Name"].to_csv unless users.empty?
|
106
|
+
users.each do |user|
|
107
|
+
say [user.id, user.created_at.utc.strftime("%Y-%m-%d %H:%M:%S %z"), user.statuses_count, user.favourites_count, user.listed_count, user.friends_count, user.followers_count, user.screen_name, user.name].to_csv
|
108
|
+
end
|
109
|
+
elsif options['long']
|
59
110
|
array = users.map do |user|
|
60
111
|
created_at = user.created_at > 6.months.ago ? user.created_at.strftime("%b %e %H:%M") : user.created_at.strftime("%b %e %Y")
|
61
112
|
[user.id.to_s, created_at, number_with_delimiter(user.statuses_count), number_with_delimiter(user.favourites_count), number_with_delimiter(user.listed_count), number_with_delimiter(user.friends_count), number_with_delimiter(user.followers_count), "@#{user.screen_name}", user.name]
|
data/lib/t/search.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
require 'action_view'
|
2
|
+
require 'csv'
|
3
|
+
# 'fastercsv' required on Ruby versions < 1.9
|
4
|
+
require 'fastercsv' unless Array.new.respond_to?(:to_csv)
|
2
5
|
require 'retryable'
|
3
6
|
require 't/core_ext/enumerable'
|
4
7
|
require 't/printable'
|
@@ -25,11 +28,18 @@ module T
|
|
25
28
|
end
|
26
29
|
|
27
30
|
desc "all QUERY", "Returns the #{DEFAULT_NUM_RESULTS} most recent Tweets that match a specified query."
|
31
|
+
method_option :csv, :aliases => "-c", :type => :boolean, :default => false, :desc => "Output in CSV format."
|
32
|
+
method_option :long, :aliases => "-l", :type => :boolean, :default => false, :desc => "Output in long format."
|
28
33
|
method_option :number, :aliases => "-n", :type => :numeric, :default => DEFAULT_NUM_RESULTS
|
29
34
|
def all(query)
|
30
35
|
rpp = options['number'] || DEFAULT_NUM_RESULTS
|
31
36
|
statuses = client.search(query, :include_entities => false, :rpp => rpp)
|
32
|
-
if options['
|
37
|
+
if options['csv']
|
38
|
+
say ["ID", "Posted at", "Screen name", "Text"].to_csv unless statuses.empty?
|
39
|
+
statuses.each do |status|
|
40
|
+
say [status.id, status.created_at.utc.strftime("%Y-%m-%d %H:%M:%S %z"), status.from_user, status.text].to_csv
|
41
|
+
end
|
42
|
+
elsif options['long']
|
33
43
|
array = statuses.map do |status|
|
34
44
|
created_at = status.created_at > 6.months.ago ? status.created_at.strftime("%b %e %H:%M") : status.created_at.strftime("%b %e %Y")
|
35
45
|
[status.id.to_s, created_at, "@#{status.from_user}", status.text.gsub(/\n+/, ' ')]
|
@@ -47,6 +57,8 @@ module T
|
|
47
57
|
end
|
48
58
|
|
49
59
|
desc "favorites QUERY", "Returns Tweets you've favorited that mach a specified query."
|
60
|
+
method_option :csv, :aliases => "-c", :type => :boolean, :default => false, :desc => "Output in CSV format."
|
61
|
+
method_option :long, :aliases => "-l", :type => :boolean, :default => false, :desc => "Output in long format."
|
50
62
|
def favorites(query)
|
51
63
|
statuses = 1.upto(MAX_PAGES).threaded_map do |page|
|
52
64
|
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
@@ -55,11 +67,13 @@ module T
|
|
55
67
|
end
|
56
68
|
end
|
57
69
|
end.flatten.compact
|
58
|
-
|
70
|
+
print_statuses(statuses)
|
59
71
|
end
|
60
72
|
map %w(faves) => :favorites
|
61
73
|
|
62
74
|
desc "mentions QUERY", "Returns Tweets mentioning you that mach a specified query."
|
75
|
+
method_option :csv, :aliases => "-c", :type => :boolean, :default => false, :desc => "Output in CSV format."
|
76
|
+
method_option :long, :aliases => "-l", :type => :boolean, :default => false, :desc => "Output in long format."
|
63
77
|
def mentions(query)
|
64
78
|
statuses = 1.upto(MAX_PAGES).threaded_map do |page|
|
65
79
|
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
@@ -68,11 +82,13 @@ module T
|
|
68
82
|
end
|
69
83
|
end
|
70
84
|
end.flatten.compact
|
71
|
-
|
85
|
+
print_statuses(statuses)
|
72
86
|
end
|
73
87
|
map %w(replies) => :mentions
|
74
88
|
|
75
89
|
desc "retweets QUERY", "Returns Tweets you've retweeted that mach a specified query."
|
90
|
+
method_option :csv, :aliases => "-c", :type => :boolean, :default => false, :desc => "Output in CSV format."
|
91
|
+
method_option :long, :aliases => "-l", :type => :boolean, :default => false, :desc => "Output in long format."
|
76
92
|
def retweets(query)
|
77
93
|
statuses = 1.upto(MAX_PAGES).threaded_map do |page|
|
78
94
|
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
@@ -81,11 +97,13 @@ module T
|
|
81
97
|
end
|
82
98
|
end
|
83
99
|
end.flatten.compact
|
84
|
-
|
100
|
+
print_statuses(statuses)
|
85
101
|
end
|
86
102
|
map %w(rts) => :retweets
|
87
103
|
|
88
104
|
desc "timeline QUERY", "Returns Tweets in your timeline that match a specified query."
|
105
|
+
method_option :csv, :aliases => "-c", :type => :boolean, :default => false, :desc => "Output in CSV format."
|
106
|
+
method_option :long, :aliases => "-l", :type => :boolean, :default => false, :desc => "Output in long format."
|
89
107
|
def timeline(query)
|
90
108
|
statuses = 1.upto(MAX_PAGES).threaded_map do |page|
|
91
109
|
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
@@ -94,21 +112,28 @@ module T
|
|
94
112
|
end
|
95
113
|
end
|
96
114
|
end.flatten.compact
|
97
|
-
|
115
|
+
print_statuses(statuses)
|
98
116
|
end
|
99
117
|
map %w(tl) => :timeline
|
100
118
|
|
101
|
-
desc "user
|
102
|
-
|
103
|
-
|
119
|
+
desc "user USER QUERY", "Returns Tweets in a user's timeline that match a specified query."
|
120
|
+
method_option :csv, :aliases => "-c", :type => :boolean, :default => false, :desc => "Output in CSV format."
|
121
|
+
method_option :id, :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify user via ID instead of screen name."
|
122
|
+
method_option :long, :aliases => "-l", :type => :boolean, :default => false, :desc => "Output in long format."
|
123
|
+
def user(user, query)
|
124
|
+
user = if options['id']
|
125
|
+
user.to_i
|
126
|
+
else
|
127
|
+
user.strip_ats
|
128
|
+
end
|
104
129
|
statuses = 1.upto(MAX_PAGES).threaded_map do |page|
|
105
130
|
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
106
|
-
client.user_timeline(
|
131
|
+
client.user_timeline(user, :page => page, :count => MAX_NUM_RESULTS).select do |status|
|
107
132
|
/#{query}/i.match(status.text)
|
108
133
|
end
|
109
134
|
end
|
110
135
|
end.flatten.compact
|
111
|
-
|
136
|
+
print_statuses(statuses)
|
112
137
|
end
|
113
138
|
|
114
139
|
end
|