t 0.8.3 → 0.9.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 +11 -9
- data/lib/t/authorizable.rb +27 -0
- data/lib/t/cli.rb +19 -35
- data/lib/t/list.rb +1 -1
- data/lib/t/printable.rb +51 -26
- data/lib/t/search.rb +44 -6
- data/lib/t/stream.rb +91 -0
- data/lib/t/version.rb +2 -2
- data/spec/cli_spec.rb +6 -10
- data/spec/list_spec.rb +1 -2
- data/spec/search_spec.rb +104 -33
- data/t.gemspec +2 -0
- metadata +301 -266
data/README.md
CHANGED
@@ -121,6 +121,9 @@ follows you:
|
|
121
121
|
### Output the last 200 tweets in your timeline to a CSV file
|
122
122
|
t timeline -n 200 --csv > timeline.csv
|
123
123
|
|
124
|
+
### Start streaming a real-time sample of all Tweets (Control-C to stop)
|
125
|
+
t stream all
|
126
|
+
|
124
127
|
### Count the number of employees who work for Twitter
|
125
128
|
t list members twitter team | wc -l
|
126
129
|
|
@@ -155,7 +158,7 @@ follows you:
|
|
155
158
|
like grep, cut, awk, bc, wc, and xargs for advanced text processing.
|
156
159
|
* Generate spreadsheets: Convert the output of any command to CSV format simply
|
157
160
|
by adding the `--csv` flag.
|
158
|
-
*
|
161
|
+
* 95% C0 Code Coverage: Well tested, with a 2.5:1 test-to-code ratio.
|
159
162
|
|
160
163
|
[search]: https://dev.twitter.com/docs/using-search
|
161
164
|
|
@@ -210,7 +213,7 @@ Here are some ways *you* can contribute:
|
|
210
213
|
* by writing code (**no patch is too small**: fix typos, add comments, clean up
|
211
214
|
inconsistent whitespace)
|
212
215
|
* by refactoring code
|
213
|
-
* by
|
216
|
+
* by fixing [issues][]
|
214
217
|
* by reviewing patches
|
215
218
|
|
216
219
|
[issues]: https://github.com/sferik/t/issues
|
@@ -218,11 +221,10 @@ Here are some ways *you* can contribute:
|
|
218
221
|
## Submitting an Issue
|
219
222
|
We use the [GitHub issue tracker][issues] to track bugs and features. Before
|
220
223
|
submitting a bug report or feature request, check to make sure it hasn't
|
221
|
-
already been submitted.
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
bug report should include a pull request with failing specs.
|
224
|
+
already been submitted. When submitting a bug report, please include a [Gist][]
|
225
|
+
that includes a stack trace and any details that may be necessary to reproduce
|
226
|
+
the bug, including your gem version, Ruby version, and operating system.
|
227
|
+
Ideally, a bug report should include a pull request with failing specs.
|
226
228
|
|
227
229
|
[gist]: https://gist.github.com/
|
228
230
|
|
@@ -235,8 +237,8 @@ bug report should include a pull request with failing specs.
|
|
235
237
|
6. Run `bundle exec rake spec`. If your specs fail, return to step 5.
|
236
238
|
7. Run `open coverage/index.html`. If your changes are not completely covered
|
237
239
|
by your tests, return to step 3.
|
238
|
-
|
239
|
-
|
240
|
+
8. Add, commit, and push your changes.
|
241
|
+
9. [Submit a pull request.][pr]
|
240
242
|
|
241
243
|
[fork]: http://help.github.com/fork-a-repo/
|
242
244
|
[branch]: http://learn.github.com/p/branching.html
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module T
|
2
|
+
module Authorizable
|
3
|
+
|
4
|
+
def consumer
|
5
|
+
OAuth::Consumer.new(
|
6
|
+
options['consumer-key'],
|
7
|
+
options['consumer-secret'],
|
8
|
+
:site => base_url
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
def generate_authorize_url(request_token)
|
13
|
+
request = consumer.create_signed_request(:get, consumer.authorize_path, request_token, pin_auth_parameters)
|
14
|
+
params = request['Authorization'].sub(/^OAuth\s+/, '').split(/,\s+/).map do |param|
|
15
|
+
key, value = param.split('=')
|
16
|
+
value =~ /"(.*?)"/
|
17
|
+
"#{key}=#{CGI::escape($1)}"
|
18
|
+
end.join('&')
|
19
|
+
"#{base_url}#{request.path}?#{params}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def pin_auth_parameters
|
23
|
+
{:oauth_callback => 'oob'}
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
data/lib/t/cli.rb
CHANGED
@@ -10,6 +10,7 @@ require 'geokit'
|
|
10
10
|
require 'launchy'
|
11
11
|
require 'oauth'
|
12
12
|
require 'open-uri'
|
13
|
+
require 't/authorizable'
|
13
14
|
require 't/collectable'
|
14
15
|
require 't/core_ext/string'
|
15
16
|
require 't/delete'
|
@@ -19,6 +20,7 @@ require 't/rcfile'
|
|
19
20
|
require 't/requestable'
|
20
21
|
require 't/search'
|
21
22
|
require 't/set'
|
23
|
+
require 't/stream'
|
22
24
|
require 't/version'
|
23
25
|
require 'thor'
|
24
26
|
require 'time'
|
@@ -35,6 +37,7 @@ module T
|
|
35
37
|
include ActionView::Helpers::DateHelper
|
36
38
|
include ActionView::Helpers::NumberHelper
|
37
39
|
include ActionView::Helpers::TextHelper
|
40
|
+
include T::Authorizable
|
38
41
|
include T::Collectable
|
39
42
|
include T::Printable
|
40
43
|
include T::Requestable
|
@@ -142,7 +145,7 @@ module T
|
|
142
145
|
elsif options['long']
|
143
146
|
array = direct_messages.map do |direct_message|
|
144
147
|
created_at = direct_message.created_at > 6.months.ago ? direct_message.created_at.strftime("%b %e %H:%M") : direct_message.created_at.strftime("%b %e %Y")
|
145
|
-
[direct_message.id, created_at, "@#{direct_message.sender.screen_name}", direct_message.text.gsub(/\n+/, ' ')]
|
148
|
+
[direct_message.id, created_at, "@#{direct_message.sender.screen_name}", HTMLEntities.new.decode(direct_message.text).gsub(/\n+/, ' ')]
|
146
149
|
end
|
147
150
|
if STDOUT.tty?
|
148
151
|
headings = ["ID", "Posted at", "Screen name", "Text"]
|
@@ -176,7 +179,7 @@ module T
|
|
176
179
|
elsif options['long']
|
177
180
|
array = direct_messages.map do |direct_message|
|
178
181
|
created_at = direct_message.created_at > 6.months.ago ? direct_message.created_at.strftime("%b %e %H:%M") : direct_message.created_at.strftime("%b %e %Y")
|
179
|
-
[direct_message.id, created_at, "@#{direct_message.recipient.screen_name}", direct_message.text.gsub(/\n+/, ' ')]
|
182
|
+
[direct_message.id, created_at, "@#{direct_message.recipient.screen_name}", HTMLEntities.new.decode(direct_message.text).gsub(/\n+/, ' ')]
|
180
183
|
end
|
181
184
|
if STDOUT.tty?
|
182
185
|
headings = ["ID", "Posted at", "Screen name", "Text"]
|
@@ -199,7 +202,7 @@ module T
|
|
199
202
|
method_option "followers", :aliases => "-f", :type => :boolean, :default => false, :desc => "Sort by number of followers."
|
200
203
|
method_option "friends", :aliases => "-e", :type => :boolean, :default => false, :desc => "Sort by number of friends."
|
201
204
|
method_option "id", :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify user via ID instead of screen name."
|
202
|
-
method_option "listed", :aliases => "-
|
205
|
+
method_option "listed", :aliases => "-d", :type => :boolean, :default => false, :desc => "Sort by number of list memberships."
|
203
206
|
method_option "long", :aliases => "-l", :type => :boolean, :default => false, :desc => "Output in long format."
|
204
207
|
method_option "posted", :aliases => "-p", :type => :boolean, :default => false, :desc => "Sort by the time when Twitter account was posted."
|
205
208
|
method_option "reverse", :aliases => "-r", :type => :boolean, :default => false, :desc => "Reverse the order of the sort."
|
@@ -361,7 +364,7 @@ module T
|
|
361
364
|
method_option "followers", :aliases => "-f", :type => :boolean, :default => false, :desc => "Sort by number of followers."
|
362
365
|
method_option "friends", :aliases => "-e", :type => :boolean, :default => false, :desc => "Sort by number of friends."
|
363
366
|
method_option "id", :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify user via ID instead of screen name."
|
364
|
-
method_option "listed", :aliases => "-
|
367
|
+
method_option "listed", :aliases => "-d", :type => :boolean, :default => false, :desc => "Sort by number of list memberships."
|
365
368
|
method_option "long", :aliases => "-l", :type => :boolean, :default => false, :desc => "Output in long format."
|
366
369
|
method_option "posted", :aliases => "-p", :type => :boolean, :default => false, :desc => "Sort by the time when Twitter account was posted."
|
367
370
|
method_option "reverse", :aliases => "-r", :type => :boolean, :default => false, :desc => "Reverse the order of the sort."
|
@@ -392,7 +395,7 @@ module T
|
|
392
395
|
method_option "followers", :aliases => "-f", :type => :boolean, :default => false, :desc => "Sort by number of followers."
|
393
396
|
method_option "friends", :aliases => "-e", :type => :boolean, :default => false, :desc => "Sort by number of friends."
|
394
397
|
method_option "id", :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify user via ID instead of screen name."
|
395
|
-
method_option "listed", :aliases => "-
|
398
|
+
method_option "listed", :aliases => "-d", :type => :boolean, :default => false, :desc => "Sort by number of list memberships."
|
396
399
|
method_option "long", :aliases => "-l", :type => :boolean, :default => false, :desc => "Output in long format."
|
397
400
|
method_option "posted", :aliases => "-p", :type => :boolean, :default => false, :desc => "Sort by the time when Twitter account was posted."
|
398
401
|
method_option "reverse", :aliases => "-r", :type => :boolean, :default => false, :desc => "Reverse the order of the sort."
|
@@ -423,7 +426,7 @@ module T
|
|
423
426
|
method_option "followers", :aliases => "-f", :type => :boolean, :default => false, :desc => "Sort by number of followers."
|
424
427
|
method_option "friends", :aliases => "-e", :type => :boolean, :default => false, :desc => "Sort by number of friends."
|
425
428
|
method_option "id", :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify user via ID instead of screen name."
|
426
|
-
method_option "listed", :aliases => "-
|
429
|
+
method_option "listed", :aliases => "-d", :type => :boolean, :default => false, :desc => "Sort by number of list memberships."
|
427
430
|
method_option "long", :aliases => "-l", :type => :boolean, :default => false, :desc => "Output in long format."
|
428
431
|
method_option "posted", :aliases => "-p", :type => :boolean, :default => false, :desc => "Sort by the time when Twitter account was posted."
|
429
432
|
method_option "reverse", :aliases => "-r", :type => :boolean, :default => false, :desc => "Reverse the order of the sort."
|
@@ -458,7 +461,7 @@ module T
|
|
458
461
|
method_option "followers", :aliases => "-f", :type => :boolean, :default => false, :desc => "Sort by number of followers."
|
459
462
|
method_option "friends", :aliases => "-e", :type => :boolean, :default => false, :desc => "Sort by number of friends."
|
460
463
|
method_option "id", :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify user via ID instead of screen name."
|
461
|
-
method_option "listed", :aliases => "-
|
464
|
+
method_option "listed", :aliases => "-d", :type => :boolean, :default => false, :desc => "Sort by number of list memberships."
|
462
465
|
method_option "long", :aliases => "-l", :type => :boolean, :default => false, :desc => "Output in long format."
|
463
466
|
method_option "posted", :aliases => "-p", :type => :boolean, :default => false, :desc => "Sort by the time when Twitter account was posted."
|
464
467
|
method_option "reverse", :aliases => "-r", :type => :boolean, :default => false, :desc => "Reverse the order of the sort."
|
@@ -636,11 +639,11 @@ module T
|
|
636
639
|
end
|
637
640
|
if options['csv']
|
638
641
|
say ["ID", "Text", "Screen name", "Posted at", "Location", "Retweets", "Source", "URL"].to_csv
|
639
|
-
say [status.id, status.text, status.user.screen_name, status.created_at.utc.strftime("%Y-%m-%d %H:%M:%S %z"), location, status.retweet_count, strip_tags(status.source), "https://twitter.com/#{status.user.screen_name}/status/#{status.id}"].to_csv
|
642
|
+
say [status.id, HTMLEntities.new.decode(status.text), status.user.screen_name, status.created_at.utc.strftime("%Y-%m-%d %H:%M:%S %z"), location, status.retweet_count, strip_tags(status.source), "https://twitter.com/#{status.user.screen_name}/status/#{status.id}"].to_csv
|
640
643
|
else
|
641
644
|
array = []
|
642
645
|
array << ["ID", status.id.to_s]
|
643
|
-
array << ["Text", status.text.gsub(/\n+/, ' ')]
|
646
|
+
array << ["Text", HTMLEntities.new.decode(status.text).gsub(/\n+/, ' ')]
|
644
647
|
array << ["Screen name", "@#{status.user.screen_name}"]
|
645
648
|
posted_at = status.created_at > 6.months.ago ? status.created_at.strftime("%b %e %H:%M") : status.created_at.strftime("%b %e %Y")
|
646
649
|
array << ["Posted at", posted_at]
|
@@ -658,7 +661,7 @@ module T
|
|
658
661
|
method_option "followers", :aliases => "-f", :type => :boolean, :default => false, :desc => "Sort by number of followers."
|
659
662
|
method_option "friends", :aliases => "-e", :type => :boolean, :default => false, :desc => "Sort by number of friends."
|
660
663
|
method_option "id", :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify user via ID instead of screen name."
|
661
|
-
method_option "listed", :aliases => "-
|
664
|
+
method_option "listed", :aliases => "-d", :type => :boolean, :default => false, :desc => "Sort by number of list memberships."
|
662
665
|
method_option "long", :aliases => "-l", :type => :boolean, :default => false, :desc => "Output in long format."
|
663
666
|
method_option "number", :aliases => "-n", :type => :numeric, :default => DEFAULT_NUM_RESULTS, :desc => "Limit the number of results."
|
664
667
|
method_option "posted", :aliases => "-p", :type => :boolean, :default => false, :desc => "Sort by the time when Twitter account was posted."
|
@@ -790,7 +793,7 @@ module T
|
|
790
793
|
method_option "followers", :aliases => "-f", :type => :boolean, :default => false, :desc => "Sort by number of followers."
|
791
794
|
method_option "friends", :aliases => "-e", :type => :boolean, :default => false, :desc => "Sort by number of friends."
|
792
795
|
method_option "id", :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify input as Twitter user IDs instead of screen names."
|
793
|
-
method_option "listed", :aliases => "-
|
796
|
+
method_option "listed", :aliases => "-d", :type => :boolean, :default => false, :desc => "Sort by number of list memberships."
|
794
797
|
method_option "long", :aliases => "-l", :type => :boolean, :default => false, :desc => "Output in long format."
|
795
798
|
method_option "posted", :aliases => "-p", :type => :boolean, :default => false, :desc => "Sort by the time when Twitter account was posted."
|
796
799
|
method_option "reverse", :aliases => "-r", :type => :boolean, :default => false, :desc => "Reverse the order of the sort."
|
@@ -826,7 +829,7 @@ module T
|
|
826
829
|
user = client.user(user, :include_entities => false)
|
827
830
|
if options['csv']
|
828
831
|
say ["ID", "Verified", "Name", "Screen name", "Bio", "Location", "Following", "Last update", "Lasted updated at", "Since", "Tweets", "Favorites", "Listed", "Following", "Followers", "URL"].to_csv
|
829
|
-
say [user.id, user.verified?, user.name, user.screen_name, user.description, user.location, user.following?, user.status.text, user.status.created_at.utc.strftime("%Y-%m-%d %H:%M:%S %z"), 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.url].to_csv
|
832
|
+
say [user.id, user.verified?, user.name, user.screen_name, user.description, user.location, user.following?, HTMLEntities.new.decode(user.status.text), user.status.created_at.utc.strftime("%Y-%m-%d %H:%M:%S %z"), 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.url].to_csv
|
830
833
|
else
|
831
834
|
array = []
|
832
835
|
name_label = user.verified ? "Name (Verified)" : "Name"
|
@@ -836,7 +839,7 @@ module T
|
|
836
839
|
array << ["Location", user.location] unless user.location.nil?
|
837
840
|
status = user.following ? "Following" : "Not following"
|
838
841
|
array << ["Status", status]
|
839
|
-
array << ["Last update", "#{user.status.text.gsub(/\n+/, ' ')} (#{time_ago_in_words(user.status.created_at)} ago)"] unless user.status.nil?
|
842
|
+
array << ["Last update", "#{HTMLEntities.new.decode(user.status.text).gsub(/\n+/, ' ')} (#{time_ago_in_words(user.status.created_at)} ago)"] unless user.status.nil?
|
840
843
|
created_at = user.created_at > 6.months.ago ? user.created_at.strftime("%b %e %H:%M") : user.created_at.strftime("%b %e %Y")
|
841
844
|
array << ["Since", created_at]
|
842
845
|
array << ["Tweets", number_with_delimiter(user.statuses_count)]
|
@@ -862,25 +865,10 @@ module T
|
|
862
865
|
desc "set SUBCOMMAND ...ARGS", "Change various account settings."
|
863
866
|
subcommand 'set', T::Set
|
864
867
|
|
865
|
-
|
866
|
-
|
867
|
-
def consumer
|
868
|
-
OAuth::Consumer.new(
|
869
|
-
options['consumer-key'],
|
870
|
-
options['consumer-secret'],
|
871
|
-
:site => base_url
|
872
|
-
)
|
873
|
-
end
|
868
|
+
desc "stream SUBCOMMAND ...ARGS", "Commands for streaming Tweets."
|
869
|
+
subcommand 'stream', T::Stream
|
874
870
|
|
875
|
-
|
876
|
-
request = consumer.create_signed_request(:get, consumer.authorize_path, request_token, pin_auth_parameters)
|
877
|
-
params = request['Authorization'].sub(/^OAuth\s+/, '').split(/,\s+/).map do |param|
|
878
|
-
key, value = param.split('=')
|
879
|
-
value =~ /"(.*?)"/
|
880
|
-
"#{key}=#{CGI::escape($1)}"
|
881
|
-
end.join('&')
|
882
|
-
"#{base_url}#{request.path}?#{params}"
|
883
|
-
end
|
871
|
+
private
|
884
872
|
|
885
873
|
def location
|
886
874
|
return @location if @location
|
@@ -890,9 +878,5 @@ module T
|
|
890
878
|
@location = Geokit::Geocoders::MultiGeocoder.geocode(ip_address)
|
891
879
|
end
|
892
880
|
|
893
|
-
def pin_auth_parameters
|
894
|
-
{:oauth_callback => 'oob'}
|
895
|
-
end
|
896
|
-
|
897
881
|
end
|
898
882
|
end
|
data/lib/t/list.rb
CHANGED
@@ -107,7 +107,7 @@ module T
|
|
107
107
|
method_option "followers", :aliases => "-f", :type => :boolean, :default => false, :desc => "Sort by total number of followers."
|
108
108
|
method_option "friends", :aliases => "-e", :type => :boolean, :default => false, :desc => "Sort by total number of friends."
|
109
109
|
method_option "id", :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify user via ID instead of screen name."
|
110
|
-
method_option "listed", :aliases => "-
|
110
|
+
method_option "listed", :aliases => "-d", :type => :boolean, :default => false, :desc => "Sort by number of list memberships."
|
111
111
|
method_option "long", :aliases => "-l", :type => :boolean, :default => false, :desc => "Output in long format."
|
112
112
|
method_option "posted", :aliases => "-p", :type => :boolean, :default => false, :desc => "Sort by the time when Twitter account was posted."
|
113
113
|
method_option "reverse", :aliases => "-r", :type => :boolean, :default => false, :desc => "Reverse the order of the sort."
|
data/lib/t/printable.rb
CHANGED
@@ -3,6 +3,7 @@ require 'csv'
|
|
3
3
|
# 'fastercsv' required on Ruby versions < 1.9
|
4
4
|
require 'fastercsv' unless Array.new.respond_to?(:to_csv)
|
5
5
|
require 'highline'
|
6
|
+
require 'htmlentities'
|
6
7
|
require 'thor/shell/color'
|
7
8
|
|
8
9
|
module T
|
@@ -14,6 +15,36 @@ module T
|
|
14
15
|
|
15
16
|
private
|
16
17
|
|
18
|
+
def build_long_list(list)
|
19
|
+
created_at = list.created_at > 6.months.ago ? list.created_at.strftime("%b %e %H:%M") : list.created_at.strftime("%b %e %Y")
|
20
|
+
[list.id, created_at, list.full_name, number_with_delimiter(list.member_count), number_with_delimiter(list.subscriber_count), list.mode, list.description]
|
21
|
+
end
|
22
|
+
|
23
|
+
def build_long_status(status)
|
24
|
+
created_at = status.created_at > 6.months.ago ? status.created_at.strftime("%b %e %H:%M") : status.created_at.strftime("%b %e %Y")
|
25
|
+
[status.id, created_at, "@#{status.user.screen_name}", HTMLEntities.new.decode(status.text).gsub(/\n+/, ' ')]
|
26
|
+
end
|
27
|
+
|
28
|
+
def build_long_user(user)
|
29
|
+
created_at = user.created_at > 6.months.ago ? user.created_at.strftime("%b %e %H:%M") : user.created_at.strftime("%b %e %Y")
|
30
|
+
[user.id, 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]
|
31
|
+
end
|
32
|
+
|
33
|
+
def print_csv_list(list)
|
34
|
+
created_at = list.created_at.utc.strftime("%Y-%m-%d %H:%M:%S %z")
|
35
|
+
say [list.id, created_at, list.user.screen_name, list.slug, list.member_count, list.subscriber_count, list.mode, list.description].to_csv
|
36
|
+
end
|
37
|
+
|
38
|
+
def print_csv_status(status)
|
39
|
+
created_at = status.created_at.utc.strftime("%Y-%m-%d %H:%M:%S %z")
|
40
|
+
say [status.id, created_at, status.user.screen_name, HTMLEntities.new.decode(status.text)].to_csv
|
41
|
+
end
|
42
|
+
|
43
|
+
def print_csv_user(user)
|
44
|
+
created_at = user.created_at.utc.strftime("%Y-%m-%d %H:%M:%S %z")
|
45
|
+
say [user.id, created_at, user.statuses_count, user.favourites_count, user.listed_count, user.friends_count, user.followers_count, user.screen_name, user.name].to_csv
|
46
|
+
end
|
47
|
+
|
17
48
|
def print_in_columns(array)
|
18
49
|
cols = HighLine::SystemExtensions.terminal_size[0]
|
19
50
|
width = (array.map{|el| el.to_s.size}.max || 0) + 2
|
@@ -39,12 +70,11 @@ module T
|
|
39
70
|
if options['csv']
|
40
71
|
say ["ID", "Created at", "Screen name", "Slug", "Members", "Subscribers", "Mode", "Description"].to_csv unless lists.empty?
|
41
72
|
lists.each do |list|
|
42
|
-
|
73
|
+
print_csv_list(list)
|
43
74
|
end
|
44
75
|
elsif options['long']
|
45
76
|
array = lists.map do |list|
|
46
|
-
|
47
|
-
[list.id, created_at, list.full_name, number_with_delimiter(list.member_count), number_with_delimiter(list.subscriber_count), list.mode, list.description]
|
77
|
+
build_long_list(list)
|
48
78
|
end
|
49
79
|
if STDOUT.tty?
|
50
80
|
headings = ["ID", "Created at", "Slug", "Members", "Subscribers", "Mode", "Description"]
|
@@ -64,17 +94,27 @@ module T
|
|
64
94
|
end
|
65
95
|
end
|
66
96
|
|
97
|
+
def print_status(status)
|
98
|
+
if STDOUT.tty? && !options['no-color']
|
99
|
+
say(" #{Thor::Shell::Color::BOLD}@#{status.user.screen_name}", :yellow)
|
100
|
+
print_wrapped(HTMLEntities.new.decode(status.text), :indent => 3)
|
101
|
+
else
|
102
|
+
say(" @#{status.user.screen_name}")
|
103
|
+
print_wrapped(HTMLEntities.new.decode(status.text), :indent => 3)
|
104
|
+
end
|
105
|
+
say
|
106
|
+
end
|
107
|
+
|
67
108
|
def print_statuses(statuses)
|
68
|
-
statuses.reverse! if options['reverse']
|
109
|
+
statuses.reverse! if options['reverse'] || options['stream']
|
69
110
|
if options['csv']
|
70
111
|
say ["ID", "Posted at", "Screen name", "Text"].to_csv unless statuses.empty?
|
71
112
|
statuses.each do |status|
|
72
|
-
|
113
|
+
print_csv_status(status)
|
73
114
|
end
|
74
115
|
elsif options['long']
|
75
116
|
array = statuses.map do |status|
|
76
|
-
|
77
|
-
[status.id, created_at, "@#{status.user.screen_name}", status.text.gsub(/\n+/, ' ')]
|
117
|
+
build_long_status(status)
|
78
118
|
end
|
79
119
|
if STDOUT.tty?
|
80
120
|
headings = ["ID", "Posted at", "Screen name", "Text"]
|
@@ -84,22 +124,8 @@ module T
|
|
84
124
|
print_table(array)
|
85
125
|
end
|
86
126
|
else
|
87
|
-
|
88
|
-
|
89
|
-
statuses.each do |status|
|
90
|
-
say(" #{Thor::Shell::Color::BOLD}@#{status.user.screen_name}", :yellow)
|
91
|
-
print_wrapped(status.text, :indent => 3)
|
92
|
-
say(" #{Thor::Shell::Color::BOLD}#{time_ago_in_words(status.created_at)} ago", :black)
|
93
|
-
say
|
94
|
-
end
|
95
|
-
else
|
96
|
-
say unless statuses.empty?
|
97
|
-
statuses.each do |status|
|
98
|
-
say(" @#{status.user.screen_name}")
|
99
|
-
print_wrapped(status.text, :indent => 3)
|
100
|
-
say(" #{time_ago_in_words(status.created_at)} ago")
|
101
|
-
say
|
102
|
-
end
|
127
|
+
statuses.each do |status|
|
128
|
+
print_status(status)
|
103
129
|
end
|
104
130
|
end
|
105
131
|
end
|
@@ -123,12 +149,11 @@ module T
|
|
123
149
|
if options['csv']
|
124
150
|
say ["ID", "Since", "Tweets", "Favorites", "Listed", "Following", "Followers", "Screen name", "Name"].to_csv unless users.empty?
|
125
151
|
users.each do |user|
|
126
|
-
|
152
|
+
print_csv_user(user)
|
127
153
|
end
|
128
154
|
elsif options['long']
|
129
155
|
array = users.map do |user|
|
130
|
-
|
131
|
-
[user.id, 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]
|
156
|
+
build_long_user(user)
|
132
157
|
end
|
133
158
|
if STDOUT.tty?
|
134
159
|
headings = ["ID", "Since", "Tweets", "Favorites", "Listed", "Following", "Followers", "Screen name", "Name"]
|
data/lib/t/search.rb
CHANGED
@@ -2,6 +2,7 @@ require 'action_view'
|
|
2
2
|
require 'csv'
|
3
3
|
# 'fastercsv' required on Ruby versions < 1.9
|
4
4
|
require 'fastercsv' unless Array.new.respond_to?(:to_csv)
|
5
|
+
require 'htmlentities'
|
5
6
|
require 'retryable'
|
6
7
|
require 't/collectable'
|
7
8
|
require 't/printable'
|
@@ -37,12 +38,12 @@ module T
|
|
37
38
|
if options['csv']
|
38
39
|
say ["ID", "Posted at", "Screen name", "Text"].to_csv unless statuses.empty?
|
39
40
|
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
|
+
say [status.id, status.created_at.utc.strftime("%Y-%m-%d %H:%M:%S %z"), status.from_user, HTMLEntities.new.decode(status.text)].to_csv
|
41
42
|
end
|
42
43
|
elsif options['long']
|
43
44
|
array = statuses.map do |status|
|
44
45
|
created_at = status.created_at > 6.months.ago ? status.created_at.strftime("%b %e %H:%M") : status.created_at.strftime("%b %e %Y")
|
45
|
-
[status.id, created_at, "@#{status.from_user}", status.text.gsub(/\n+/, ' ')]
|
46
|
+
[status.id, created_at, "@#{status.from_user}", HTMLEntities.new.decode(status.text).gsub(/\n+/, ' ')]
|
46
47
|
end
|
47
48
|
if STDOUT.tty?
|
48
49
|
headings = ["ID", "Posted at", "Screen name", "Text"]
|
@@ -52,13 +53,21 @@ module T
|
|
52
53
|
print_table(array)
|
53
54
|
end
|
54
55
|
else
|
56
|
+
say unless statuses.empty?
|
55
57
|
statuses.each do |status|
|
56
|
-
|
58
|
+
if STDOUT.tty? && !options['no-color']
|
59
|
+
say(" #{Thor::Shell::Color::BOLD}@#{status.from_user}", :yellow)
|
60
|
+
print_wrapped(HTMLEntities.new.decode(status.text), :indent => 3)
|
61
|
+
else
|
62
|
+
say(" @#{status.from_user}")
|
63
|
+
print_wrapped(HTMLEntities.new.decode(status.text), :indent => 3)
|
64
|
+
end
|
65
|
+
say
|
57
66
|
end
|
58
67
|
end
|
59
68
|
end
|
60
69
|
|
61
|
-
desc "favorites QUERY", "Returns Tweets you've favorited that
|
70
|
+
desc "favorites QUERY", "Returns Tweets you've favorited that match a specified query."
|
62
71
|
method_option "csv", :aliases => "-c", :type => :boolean, :default => false, :desc => "Output in CSV format."
|
63
72
|
method_option "long", :aliases => "-l", :type => :boolean, :default => false, :desc => "Output in long format."
|
64
73
|
def favorites(query)
|
@@ -76,7 +85,36 @@ module T
|
|
76
85
|
end
|
77
86
|
map %w(faves) => :favorites
|
78
87
|
|
79
|
-
desc "
|
88
|
+
desc "list [USER/]LIST QUERY", "Returns Tweets on a list that match specified query."
|
89
|
+
method_option "csv", :aliases => "-c", :type => :boolean, :default => false, :desc => "Output in CSV format."
|
90
|
+
method_option "id", :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify user via ID instead of screen name."
|
91
|
+
method_option "long", :aliases => "-l", :type => :boolean, :default => false, :desc => "Output in long format."
|
92
|
+
def list(list, query)
|
93
|
+
owner, list = list.split('/')
|
94
|
+
if list.nil?
|
95
|
+
list = owner
|
96
|
+
owner = @rcfile.active_profile[0]
|
97
|
+
else
|
98
|
+
owner = if options['id']
|
99
|
+
owner.to_i
|
100
|
+
else
|
101
|
+
owner.strip_ats
|
102
|
+
end
|
103
|
+
end
|
104
|
+
opts = {:count => MAX_NUM_RESULTS}
|
105
|
+
statuses = collect_with_max_id do |max_id|
|
106
|
+
opts[:max_id] = max_id unless max_id.nil?
|
107
|
+
retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
108
|
+
client.list_timeline(owner, list, opts)
|
109
|
+
end
|
110
|
+
end.flatten.compact
|
111
|
+
statuses = statuses.select do |status|
|
112
|
+
/#{query}/i.match(status.text)
|
113
|
+
end
|
114
|
+
print_statuses(statuses)
|
115
|
+
end
|
116
|
+
|
117
|
+
desc "mentions QUERY", "Returns Tweets mentioning you that match a specified query."
|
80
118
|
method_option "csv", :aliases => "-c", :type => :boolean, :default => false, :desc => "Output in CSV format."
|
81
119
|
method_option "long", :aliases => "-l", :type => :boolean, :default => false, :desc => "Output in long format."
|
82
120
|
def mentions(query)
|
@@ -94,7 +132,7 @@ module T
|
|
94
132
|
end
|
95
133
|
map %w(replies) => :mentions
|
96
134
|
|
97
|
-
desc "retweets QUERY", "Returns Tweets you've retweeted that
|
135
|
+
desc "retweets QUERY", "Returns Tweets you've retweeted that match a specified query."
|
98
136
|
method_option "csv", :aliases => "-c", :type => :boolean, :default => false, :desc => "Output in CSV format."
|
99
137
|
method_option "long", :aliases => "-l", :type => :boolean, :default => false, :desc => "Output in long format."
|
100
138
|
def retweets(query)
|