t 0.9.5 → 0.9.6
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 +5 -3
- data/Rakefile +0 -2
- data/lib/t.rb +15 -0
- data/lib/t/cli.rb +47 -59
- data/lib/t/collectable.rb +12 -8
- data/lib/t/delete.rb +4 -3
- data/lib/t/list.rb +3 -5
- data/lib/t/printable.rb +50 -81
- data/lib/t/search.rb +51 -62
- data/lib/t/stream.rb +15 -22
- data/lib/t/version.rb +1 -1
- data/spec/cli_spec.rb +198 -65
- data/spec/fixtures/rate_limit_status.json +1 -0
- data/spec/fixtures/status.json +1 -1
- data/spec/fixtures/status_no_attributes.json +1 -0
- data/spec/fixtures/status_no_country.json +1 -0
- data/spec/fixtures/status_no_full_name.json +1 -0
- data/spec/fixtures/status_no_locality.json +1 -0
- data/spec/fixtures/status_no_street_address.json +1 -0
- data/spec/helper.rb +1 -0
- data/spec/list_spec.rb +9 -9
- data/spec/rcfile_spec.rb +1 -1
- data/spec/search_spec.rb +319 -49
- data/spec/t_spec.rb +31 -0
- data/t.gemspec +2 -3
- metadata +22 -24
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Twitter CLI [][travis] [][gemnasium]
|
1
|
+
# Twitter CLI [][travis] [][gemnasium] [][pledgie]
|
2
2
|
### A command-line power tool for Twitter.
|
3
3
|
|
4
4
|
The CLI takes syntactic cues from the [Twitter SMS commands][sms], however it
|
@@ -6,6 +6,7 @@ offers vastly more commands and capabilities than are available via SMS.
|
|
6
6
|
|
7
7
|
[travis]: http://travis-ci.org/sferik/t
|
8
8
|
[gemnasium]: https://gemnasium.com/sferik/t
|
9
|
+
[pledgie]: http://www.pledgie.com/campaigns/17330
|
9
10
|
[gem]: https://rubygems.org/gems/twitter
|
10
11
|
[sms]: https://support.twitter.com/articles/14020-twitter-sms-command
|
11
12
|
|
@@ -198,10 +199,10 @@ the original code.
|
|
198
199
|

|
199
200
|
|
200
201
|
## Contributing
|
201
|
-
In the spirit of [free software][
|
202
|
+
In the spirit of [free software][free-sw], **everyone** is encouraged to help
|
202
203
|
improve this project.
|
203
204
|
|
204
|
-
[
|
205
|
+
[free-sw]: http://www.fsf.org/licensing/essays/free-sw.html
|
205
206
|
|
206
207
|
Here are some ways *you* can contribute:
|
207
208
|
|
@@ -215,6 +216,7 @@ Here are some ways *you* can contribute:
|
|
215
216
|
* by refactoring code
|
216
217
|
* by fixing [issues][]
|
217
218
|
* by reviewing patches
|
219
|
+
* [financially][pledgie]
|
218
220
|
|
219
221
|
[issues]: https://github.com/sferik/t/issues
|
220
222
|
|
data/Rakefile
CHANGED
data/lib/t.rb
CHANGED
data/lib/t/cli.rb
CHANGED
@@ -7,6 +7,7 @@ require 'csv'
|
|
7
7
|
# 'fastercsv' required on Ruby versions < 1.9
|
8
8
|
require 'fastercsv' unless Array.new.respond_to?(:to_csv)
|
9
9
|
require 'open-uri'
|
10
|
+
require 'retryable'
|
10
11
|
require 't/authorizable'
|
11
12
|
require 't/collectable'
|
12
13
|
require 't/core_ext/string'
|
@@ -41,7 +42,7 @@ module T
|
|
41
42
|
check_unknown_options!
|
42
43
|
|
43
44
|
option "host", :aliases => "-H", :type => :string, :default => DEFAULT_HOST, :desc => "Twitter API server"
|
44
|
-
option "no-color", :aliases => "-N", :type => :boolean, :
|
45
|
+
option "no-color", :aliases => "-N", :type => :boolean, :desc => "Disable colorization in output"
|
45
46
|
option "no-ssl", :aliases => "-U", :type => :boolean, :default => false, :desc => "Disable SSL"
|
46
47
|
option "profile", :aliases => "-P", :type => :string, :default => File.join(File.expand_path("~"), RCFile::FILE_NAME), :desc => "Path to RC file", :banner => "FILE"
|
47
48
|
|
@@ -62,8 +63,8 @@ module T
|
|
62
63
|
end
|
63
64
|
|
64
65
|
desc "authorize", "Allows an application to request user authorization"
|
65
|
-
method_option "consumer-key", :aliases => "-c", :required => true, :desc => "This can be found at https://dev.twitter.com/apps"
|
66
|
-
method_option "consumer-secret", :aliases => "-s", :required => true, :desc => "This can be found at https://dev.twitter.com/apps"
|
66
|
+
method_option "consumer-key", :aliases => "-c", :required => true, :desc => "This can be found at https://dev.twitter.com/apps", :banner => "KEY"
|
67
|
+
method_option "consumer-secret", :aliases => "-s", :required => true, :desc => "This can be found at https://dev.twitter.com/apps", :banner => "SECRET"
|
67
68
|
method_option "display-url", :aliases => "-d", :type => :boolean, :default => false, :desc => "Display the authorization URL instead of attempting to open it."
|
68
69
|
method_option "prompt", :aliases => "-p", :type => :boolean, :default => true
|
69
70
|
def authorize
|
@@ -132,22 +133,15 @@ module T
|
|
132
133
|
end
|
133
134
|
direct_messages.reverse! if options['reverse']
|
134
135
|
if options['csv']
|
135
|
-
say
|
136
|
+
say DIRECT_MESSAGE_HEADINGS.to_csv unless direct_messages.empty?
|
136
137
|
direct_messages.each do |direct_message|
|
137
|
-
say [direct_message.id, direct_message
|
138
|
+
say [direct_message.id, csv_formatted_time(direct_message), direct_message.sender.screen_name, direct_message.text].to_csv
|
138
139
|
end
|
139
140
|
elsif options['long']
|
140
141
|
array = direct_messages.map do |direct_message|
|
141
|
-
|
142
|
-
[direct_message.id, created_at, "@#{direct_message.sender.screen_name}", HTMLEntities.new.decode(direct_message.text).gsub(/\n+/, ' ')]
|
143
|
-
end
|
144
|
-
if STDOUT.tty?
|
145
|
-
headings = ["ID", "Posted at", "Screen name", "Text"]
|
146
|
-
array.unshift(headings) unless direct_messages.empty?
|
147
|
-
print_table(array, :truncate => true)
|
148
|
-
else
|
149
|
-
print_table(array)
|
142
|
+
[direct_message.id, ls_formatted_time(direct_message), "@#{direct_message.sender.screen_name}", HTMLEntities.new.decode(direct_message.text).gsub(/\n+/, ' ')]
|
150
143
|
end
|
144
|
+
print_table_with_headings(array, DIRECT_MESSAGE_HEADINGS)
|
151
145
|
else
|
152
146
|
direct_messages.each do |direct_message|
|
153
147
|
say "#{direct_message.sender.screen_name.rjust(MAX_SCREEN_NAME_SIZE)}: #{direct_message.text.gsub(/\n+/, ' ')} (#{time_ago_in_words(direct_message.created_at)} ago)"
|
@@ -168,22 +162,15 @@ module T
|
|
168
162
|
end
|
169
163
|
direct_messages.reverse! if options['reverse']
|
170
164
|
if options['csv']
|
171
|
-
say
|
165
|
+
say DIRECT_MESSAGE_HEADINGS.to_csv unless direct_messages.empty?
|
172
166
|
direct_messages.each do |direct_message|
|
173
|
-
say [direct_message.id, direct_message
|
167
|
+
say [direct_message.id, csv_formatted_time(direct_message), direct_message.recipient.screen_name, direct_message.text].to_csv
|
174
168
|
end
|
175
169
|
elsif options['long']
|
176
170
|
array = direct_messages.map do |direct_message|
|
177
|
-
|
178
|
-
[direct_message.id, created_at, "@#{direct_message.recipient.screen_name}", HTMLEntities.new.decode(direct_message.text).gsub(/\n+/, ' ')]
|
179
|
-
end
|
180
|
-
if STDOUT.tty?
|
181
|
-
headings = ["ID", "Posted at", "Screen name", "Text"]
|
182
|
-
array.unshift(headings) unless direct_messages.empty?
|
183
|
-
print_table(array, :truncate => true)
|
184
|
-
else
|
185
|
-
print_table(array)
|
171
|
+
[direct_message.id, ls_formatted_time(direct_message), "@#{direct_message.recipient.screen_name}", HTMLEntities.new.decode(direct_message.text).gsub(/\n+/, ' ')]
|
186
172
|
end
|
173
|
+
print_table_with_headings(array, DIRECT_MESSAGE_HEADINGS)
|
187
174
|
else
|
188
175
|
direct_messages.each do |direct_message|
|
189
176
|
say "#{direct_message.recipient.screen_name.rjust(MAX_SCREEN_NAME_SIZE)}: #{direct_message.text.gsub(/\n+/, ' ')} (#{time_ago_in_words(direct_message.created_at)} ago)"
|
@@ -512,6 +499,11 @@ module T
|
|
512
499
|
print_lists(lists)
|
513
500
|
end
|
514
501
|
|
502
|
+
desc "matrix", "Unfortunately, no one can be told what the Matrix is. You have to see it for yourself."
|
503
|
+
def matrix
|
504
|
+
T::Stream.new.matrix
|
505
|
+
end
|
506
|
+
|
515
507
|
desc "mentions", "Returns the #{DEFAULT_NUM_RESULTS} most recent Tweets mentioning you."
|
516
508
|
method_option "csv", :aliases => "-c", :type => :boolean, :default => false, :desc => "Output in CSV format."
|
517
509
|
method_option "long", :aliases => "-l", :type => :boolean, :default => false, :desc => "Output in long format."
|
@@ -537,19 +529,36 @@ module T
|
|
537
529
|
Launchy.open("https://twitter.com/#{user.screen_name}", :dry_run => options['display-url'])
|
538
530
|
elsif options['status']
|
539
531
|
status = client.status(user.to_i, :include_my_retweet => false)
|
540
|
-
Launchy.open("https://twitter.com/#{status.
|
532
|
+
Launchy.open("https://twitter.com/#{status.from_user}/status/#{status.id}", :dry_run => options['display-url'])
|
541
533
|
else
|
542
534
|
Launchy.open("https://twitter.com/#{user.strip_ats}", :dry_run => options['display-url'])
|
543
535
|
end
|
544
536
|
end
|
545
537
|
|
538
|
+
desc "rate_limit", "Returns information related to Twitter API rate limiting."
|
539
|
+
method_option "csv", :aliases => "-c", :type => :boolean, :default => false, :desc => "Output in CSV format."
|
540
|
+
def rate_limit
|
541
|
+
rate_limit_status = client.rate_limit_status
|
542
|
+
if options['csv']
|
543
|
+
say ["Hourly limit", "Remaining hits", "Reset time"].to_csv
|
544
|
+
say [rate_limit_status.hourly_limit, rate_limit_status.remaining_hits, csv_formatted_time(rate_limit_status, :reset_time)].to_csv
|
545
|
+
else
|
546
|
+
array = []
|
547
|
+
array << ["Hourly limit", number_with_delimiter(rate_limit_status.hourly_limit)]
|
548
|
+
array << ["Remaining hits", number_with_delimiter(rate_limit_status.remaining_hits)]
|
549
|
+
array << ["Reset time", ls_formatted_time(rate_limit_status, :reset_time)]
|
550
|
+
print_table(array)
|
551
|
+
end
|
552
|
+
end
|
553
|
+
map %w(ratelimit rl) => :rate_limit
|
554
|
+
|
546
555
|
desc "reply STATUS_ID MESSAGE", "Post your Tweet as a reply directed at another person."
|
547
556
|
method_option "all", :aliases => "-a", :type => "boolean", :default => false, :desc => "Reply to all users mentioned in the Tweet."
|
548
557
|
method_option "location", :aliases => "-l", :type => :boolean, :default => false
|
549
558
|
def reply(status_id, message)
|
550
559
|
status_id = status_id.strip_commas
|
551
560
|
status = client.status(status_id.to_i, :include_my_retweet => false)
|
552
|
-
users = Array(status.
|
561
|
+
users = Array(status.from_user)
|
553
562
|
if options['all']
|
554
563
|
# twitter-text requires $KCODE to be set to UTF8 on Ruby versions < 1.8
|
555
564
|
major, minor, patch = RUBY_VERSION.split('.')
|
@@ -653,18 +662,18 @@ module T
|
|
653
662
|
end
|
654
663
|
if options['csv']
|
655
664
|
say ["ID", "Text", "Screen name", "Posted at", "Location", "Retweets", "Source", "URL"].to_csv
|
656
|
-
say [status.id, HTMLEntities.new.decode(status.text), status.
|
665
|
+
say [status.id, HTMLEntities.new.decode(status.text), status.from_user, csv_formatted_time(status), location, status.retweet_count, strip_tags(status.source), "https://twitter.com/#{status.from_user}/status/#{status.id}"].to_csv
|
657
666
|
else
|
658
667
|
array = []
|
659
668
|
array << ["ID", status.id.to_s]
|
660
669
|
array << ["Text", HTMLEntities.new.decode(status.text).gsub(/\n+/, ' ')]
|
661
|
-
array << ["Screen name", "@#{status.
|
670
|
+
array << ["Screen name", "@#{status.from_user}"]
|
662
671
|
posted_at = status.created_at > 6.months.ago ? status.created_at.strftime("%b %e %H:%M") : status.created_at.strftime("%b %e %Y")
|
663
672
|
array << ["Posted at", posted_at]
|
664
673
|
array << ["Location", location] unless location.nil?
|
665
674
|
array << ["Retweets", number_with_delimiter(status.retweet_count)]
|
666
675
|
array << ["Source", strip_tags(status.source)]
|
667
|
-
array << ["URL", "https://twitter.com/#{status.
|
676
|
+
array << ["URL", "https://twitter.com/#{status.from_user}/status/#{status.id}"]
|
668
677
|
print_table(array)
|
669
678
|
end
|
670
679
|
end
|
@@ -727,13 +736,7 @@ module T
|
|
727
736
|
opts = {}
|
728
737
|
opts.merge!(:exclude => "hashtags") if options['exclude-hashtags']
|
729
738
|
trends = client.trends(woe_id, opts)
|
730
|
-
|
731
|
-
print_in_columns(trends.map(&:name))
|
732
|
-
else
|
733
|
-
trends.each do |trend|
|
734
|
-
say trend.name
|
735
|
-
end
|
736
|
-
end
|
739
|
+
print_attribute(trends, :name)
|
737
740
|
end
|
738
741
|
|
739
742
|
desc "trends_locations", "Returns the locations for which Twitter has trending topic information."
|
@@ -746,7 +749,7 @@ module T
|
|
746
749
|
places = places.sort_by{|places| places.name.downcase} unless options['unsorted']
|
747
750
|
places.reverse! if options['reverse']
|
748
751
|
if options['csv']
|
749
|
-
say
|
752
|
+
say TREND_HEADINGS.to_csv unless places.empty?
|
750
753
|
places.each do |place|
|
751
754
|
say [place.woeid, place.parent_id, place.place_type, place.name, place.country].to_csv
|
752
755
|
end
|
@@ -754,21 +757,9 @@ module T
|
|
754
757
|
array = places.map do |place|
|
755
758
|
[place.woeid, place.parent_id, place.place_type, place.name, place.country]
|
756
759
|
end
|
757
|
-
|
758
|
-
headings = ["WOEID", "Parent ID", "Type", "Name", "Country"]
|
759
|
-
array.unshift(headings) unless places.empty?
|
760
|
-
print_table(array, :truncate => true)
|
761
|
-
else
|
762
|
-
print_table(array)
|
763
|
-
end
|
760
|
+
print_table_with_headings(array, TREND_HEADINGS)
|
764
761
|
else
|
765
|
-
|
766
|
-
print_in_columns(places.map(&:name))
|
767
|
-
else
|
768
|
-
places.each do |place|
|
769
|
-
say place.name
|
770
|
-
end
|
771
|
-
end
|
762
|
+
print_attribute(places, :name)
|
772
763
|
end
|
773
764
|
end
|
774
765
|
map %w(locations trendlocations) => :trend_locations
|
@@ -847,19 +838,16 @@ module T
|
|
847
838
|
user = client.user(user)
|
848
839
|
if options['csv']
|
849
840
|
say ["ID", "Verified", "Name", "Screen name", "Bio", "Location", "Following", "Last update", "Lasted updated at", "Since", "Tweets", "Favorites", "Listed", "Following", "Followers", "URL"].to_csv
|
850
|
-
say [user.id, user.verified?, user.name, user.screen_name, user.description, user.location, user.following?, HTMLEntities.new.decode(user.status.text), user.status
|
841
|
+
say [user.id, user.verified?, user.name, user.screen_name, user.description, user.location, user.following?, HTMLEntities.new.decode(user.status.text), csv_formatted_time(user.status), csv_formatted_time(user), user.statuses_count, user.favourites_count, user.listed_count, user.friends_count, user.followers_count, user.url].to_csv
|
851
842
|
else
|
852
843
|
array = []
|
853
|
-
name_label = user.verified ? "Name (Verified)" : "Name"
|
854
844
|
array << ["ID", user.id.to_s]
|
855
|
-
array << [
|
845
|
+
array << [user.verified ? "Name (Verified)" : "Name", user.name] unless user.name.nil?
|
856
846
|
array << ["Bio", user.description.gsub(/\n+/, ' ')] unless user.description.nil?
|
857
847
|
array << ["Location", user.location] unless user.location.nil?
|
858
|
-
|
859
|
-
array << ["Status", status]
|
848
|
+
array << ["Status", user.following ? "Following" : "Not following"]
|
860
849
|
array << ["Last update", "#{HTMLEntities.new.decode(user.status.text).gsub(/\n+/, ' ')} (#{time_ago_in_words(user.status.created_at)} ago)"] unless user.status.nil?
|
861
|
-
|
862
|
-
array << ["Since", created_at]
|
850
|
+
array << ["Since", ls_formatted_time(user)]
|
863
851
|
array << ["Tweets", number_with_delimiter(user.statuses_count)]
|
864
852
|
array << ["Favorites", number_with_delimiter(user.favourites_count)]
|
865
853
|
array << ["Listed", number_with_delimiter(user.listed_count)]
|
data/lib/t/collectable.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'retryable'
|
2
|
+
|
1
3
|
module T
|
2
4
|
module Collectable
|
3
5
|
|
@@ -8,16 +10,20 @@ module T
|
|
8
10
|
end
|
9
11
|
|
10
12
|
def collect_with_cursor(collection=[], cursor=-1, &block)
|
11
|
-
object =
|
13
|
+
object = retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
14
|
+
yield cursor
|
15
|
+
end
|
12
16
|
collection += object.collection
|
13
|
-
object.last? ? collection : collect_with_cursor(collection, object.next_cursor, &block)
|
17
|
+
object.last? ? collection.flatten : collect_with_cursor(collection, object.next_cursor, &block)
|
14
18
|
end
|
15
19
|
|
16
20
|
def collect_with_max_id(collection=[], max_id=nil, &block)
|
17
|
-
array =
|
18
|
-
|
21
|
+
array = retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
|
22
|
+
yield max_id
|
23
|
+
end
|
24
|
+
return collection if array.nil?
|
19
25
|
collection += array
|
20
|
-
array.empty? ? collection : collect_with_max_id(collection, array.last.id - 1, &block)
|
26
|
+
array.empty? ? collection.flatten : collect_with_max_id(collection, array.last.id - 1, &block)
|
21
27
|
end
|
22
28
|
|
23
29
|
def collect_with_number(number, key, &block)
|
@@ -28,9 +34,7 @@ module T
|
|
28
34
|
opts[key] = number unless number >= MAX_NUM_RESULTS
|
29
35
|
if number > 0
|
30
36
|
number -= MAX_NUM_RESULTS
|
31
|
-
|
32
|
-
yield opts
|
33
|
-
end
|
37
|
+
yield opts
|
34
38
|
end
|
35
39
|
end.flatten.compact
|
36
40
|
end
|
data/lib/t/delete.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'retryable'
|
1
2
|
require 't/core_ext/enumerable'
|
2
3
|
require 't/core_ext/string'
|
3
4
|
require 't/rcfile'
|
@@ -60,10 +61,10 @@ module T
|
|
60
61
|
status_ids.each do |status_id|
|
61
62
|
unless options['force']
|
62
63
|
status = client.status(status_id.to_i, :include_my_retweet => false, :trim_user => true)
|
63
|
-
return unless yes? "Are you sure you want to remove @#{status.
|
64
|
+
return unless yes? "Are you sure you want to remove @#{status.from_user}'s status: \"#{status.text}\" from your favorites? [y/N]"
|
64
65
|
end
|
65
66
|
status = client.unfavorite(status_id.to_i)
|
66
|
-
say "@#{@rcfile.active_profile[0]} unfavorited @#{status.
|
67
|
+
say "@#{@rcfile.active_profile[0]} unfavorited @#{status.from_user}'s status: \"#{status.text}\""
|
67
68
|
end
|
68
69
|
end
|
69
70
|
map %w(fave favourite) => :favorite
|
@@ -89,7 +90,7 @@ module T
|
|
89
90
|
status_ids.each do |status_id|
|
90
91
|
unless options['force']
|
91
92
|
status = client.status(status_id.to_i, :include_my_retweet => false, :trim_user => true)
|
92
|
-
return unless yes? "Are you sure you want to permanently delete @#{status.
|
93
|
+
return unless yes? "Are you sure you want to permanently delete @#{status.from_user}'s status: \"#{status.text}\"? [y/N]"
|
93
94
|
end
|
94
95
|
status = client.status_destroy(status_id.to_i, :trim_user => true)
|
95
96
|
say "@#{@rcfile.active_profile[0]} deleted the status: \"#{status.text}\""
|
data/lib/t/list.rb
CHANGED
@@ -81,19 +81,17 @@ module T
|
|
81
81
|
list = client.list(owner, list)
|
82
82
|
if options['csv']
|
83
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
|
84
|
+
say [list.id, list.description, list.slug, list.user.screen_name, csv_formatted_time(list), list.member_count, list.subscriber_count, list.following?, list.mode, "https://twitter.com#{list.uri}"].to_csv
|
85
85
|
else
|
86
86
|
array = []
|
87
87
|
array << ["ID", list.id.to_s]
|
88
88
|
array << ["Description", list.description] unless list.description.nil?
|
89
89
|
array << ["Slug", list.slug]
|
90
90
|
array << ["Screen name", "@#{list.user.screen_name}"]
|
91
|
-
|
92
|
-
array << ["Created at", created_at]
|
91
|
+
array << ["Created at", ls_formatted_time(list)]
|
93
92
|
array << ["Members", number_with_delimiter(list.member_count)]
|
94
93
|
array << ["Subscribers", number_with_delimiter(list.subscriber_count)]
|
95
|
-
|
96
|
-
array << ["Status", status]
|
94
|
+
array << ["Status", list.following ? "Following" : "Not following"]
|
97
95
|
array << ["Mode", list.mode]
|
98
96
|
array << ["URL", "https://twitter.com#{list.uri}"]
|
99
97
|
print_table(array)
|
data/lib/t/printable.rb
CHANGED
@@ -2,7 +2,6 @@ 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 'highline'
|
6
5
|
require 'htmlentities'
|
7
6
|
require 'thor/shell/color'
|
8
7
|
require 'time'
|
@@ -10,6 +9,12 @@ require 'time'
|
|
10
9
|
module T
|
11
10
|
module Printable
|
12
11
|
MAX_SCREEN_NAME_SIZE = 20
|
12
|
+
DIRECT_MESSAGE_HEADINGS = ["ID", "Posted at", "Screen name", "Text"]
|
13
|
+
LIST_HEADINGS =["ID", "Created at", "Screen name", "Slug", "Members", "Subscribers", "Mode", "Description"]
|
14
|
+
STATUS_HEADINGS = ["ID", "Posted at", "Screen name", "Text"]
|
15
|
+
TREND_HEADINGS = ["WOEID", "Parent ID", "Type", "Name", "Country"]
|
16
|
+
USER_HEADINGS = ["ID", "Since", "Tweets", "Favorites", "Listed", "Following", "Followers", "Screen name", "Name"]
|
17
|
+
|
13
18
|
include ActionView::Helpers::NumberHelper
|
14
19
|
|
15
20
|
def self.included(base)
|
@@ -17,63 +22,39 @@ module T
|
|
17
22
|
private
|
18
23
|
|
19
24
|
def build_long_list(list)
|
20
|
-
|
21
|
-
list.created_at.strftime("%b %e %H:%M")
|
22
|
-
else
|
23
|
-
list.created_at.strftime("%b %e %Y")
|
24
|
-
end
|
25
|
-
[list.id, created_at, "@#{list.user.screen_name}", list.slug, number_with_delimiter(list.member_count), number_with_delimiter(list.subscriber_count), list.mode, list.description]
|
25
|
+
[list.id, ls_formatted_time(list), "@#{list.user.screen_name}", list.slug, number_with_delimiter(list.member_count), number_with_delimiter(list.subscriber_count), list.mode, list.description]
|
26
26
|
end
|
27
27
|
|
28
28
|
def build_long_status(status)
|
29
|
-
|
30
|
-
Time.parse(status.created_at.to_s).strftime("%b %e %H:%M")
|
31
|
-
else
|
32
|
-
Time.parse(status.created_at.to_s).strftime("%b %e %Y")
|
33
|
-
end
|
34
|
-
[status.id, created_at, "@#{status.user.screen_name}", HTMLEntities.new.decode(status.text).gsub(/\n+/, ' ')]
|
29
|
+
[status.id, ls_formatted_time(status), "@#{status.from_user}", HTMLEntities.new.decode(status.text).gsub(/\n+/, ' ')]
|
35
30
|
end
|
36
31
|
|
37
32
|
def build_long_user(user)
|
38
|
-
|
39
|
-
|
33
|
+
[user.id, ls_formatted_time(user), 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]
|
34
|
+
end
|
35
|
+
|
36
|
+
def csv_formatted_time(object, key=:created_at)
|
37
|
+
Time.parse(object.send(key.to_sym).to_s).utc.strftime("%Y-%m-%d %H:%M:%S %z")
|
38
|
+
end
|
39
|
+
|
40
|
+
def ls_formatted_time(object, key=:created_at)
|
41
|
+
if object.send(key.to_sym) > 6.months.ago
|
42
|
+
Time.parse(object.send(key.to_sym).to_s).strftime("%b %e %H:%M")
|
40
43
|
else
|
41
|
-
|
44
|
+
Time.parse(object.send(key.to_sym).to_s).strftime("%b %e %Y")
|
42
45
|
end
|
43
|
-
[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]
|
44
46
|
end
|
45
47
|
|
46
48
|
def print_csv_list(list)
|
47
|
-
|
48
|
-
say [list.id, created_at, list.user.screen_name, list.slug, list.member_count, list.subscriber_count, list.mode, list.description].to_csv
|
49
|
+
say [list.id, csv_formatted_time(list), list.user.screen_name, list.slug, list.member_count, list.subscriber_count, list.mode, list.description].to_csv
|
49
50
|
end
|
50
51
|
|
51
52
|
def print_csv_status(status)
|
52
|
-
|
53
|
-
say [status.id, created_at, status.user.screen_name, HTMLEntities.new.decode(status.text)].to_csv
|
53
|
+
say [status.id, csv_formatted_time(status), status.from_user, HTMLEntities.new.decode(status.text)].to_csv
|
54
54
|
end
|
55
55
|
|
56
56
|
def print_csv_user(user)
|
57
|
-
|
58
|
-
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
|
59
|
-
end
|
60
|
-
|
61
|
-
def print_in_columns(array)
|
62
|
-
cols = HighLine::SystemExtensions.terminal_size[0]
|
63
|
-
width = (array.map{|el| el.to_s.size}.max || 0) + 2
|
64
|
-
array.each_with_index do |value, index|
|
65
|
-
puts if (((index) % (cols / width))).zero? && !index.zero?
|
66
|
-
printf("%-#{width}s", value)
|
67
|
-
end
|
68
|
-
puts
|
69
|
-
end
|
70
|
-
|
71
|
-
def list_headings
|
72
|
-
["ID", "Created at", "Screen name", "Slug", "Members", "Subscribers", "Mode", "Description"]
|
73
|
-
end
|
74
|
-
|
75
|
-
def status_headings
|
76
|
-
["ID", "Posted at", "Screen name", "Text"]
|
57
|
+
say [user.id, csv_formatted_time(user), user.statuses_count, user.favourites_count, user.listed_count, user.friends_count, user.followers_count, user.screen_name, user.name].to_csv
|
77
58
|
end
|
78
59
|
|
79
60
|
def print_lists(lists)
|
@@ -89,7 +70,7 @@ module T
|
|
89
70
|
end
|
90
71
|
lists.reverse! if options['reverse']
|
91
72
|
if options['csv']
|
92
|
-
say
|
73
|
+
say LIST_HEADINGS.to_csv unless lists.empty?
|
93
74
|
lists.each do |list|
|
94
75
|
print_csv_list(list)
|
95
76
|
end
|
@@ -97,28 +78,36 @@ module T
|
|
97
78
|
array = lists.map do |list|
|
98
79
|
build_long_list(list)
|
99
80
|
end
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
81
|
+
print_table_with_headings(array, LIST_HEADINGS)
|
82
|
+
else
|
83
|
+
print_attribute(lists, :full_name)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def print_attribute(array, attribute)
|
88
|
+
if STDOUT.tty?
|
89
|
+
print_in_columns(array.map(&attribute.to_sym))
|
106
90
|
else
|
107
|
-
|
108
|
-
|
109
|
-
else
|
110
|
-
lists.each do |list|
|
111
|
-
say list.full_name
|
112
|
-
end
|
91
|
+
array.each do |element|
|
92
|
+
say element.send(attribute.to_sym)
|
113
93
|
end
|
114
94
|
end
|
115
95
|
end
|
116
96
|
|
97
|
+
def print_table_with_headings(array, headings)
|
98
|
+
if STDOUT.tty?
|
99
|
+
array.unshift(headings) unless array.flatten.empty?
|
100
|
+
print_table(array, :truncate => true)
|
101
|
+
else
|
102
|
+
print_table(array)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
117
106
|
def print_status(status)
|
118
107
|
if STDOUT.tty? && !options['no-color']
|
119
|
-
say(" @#{status.
|
108
|
+
say(" @#{status.from_user}", [:bold, :yellow])
|
120
109
|
else
|
121
|
-
say(" @#{status.
|
110
|
+
say(" @#{status.from_user}")
|
122
111
|
end
|
123
112
|
print_wrapped(HTMLEntities.new.decode(status.text), :indent => 3)
|
124
113
|
say
|
@@ -127,7 +116,7 @@ module T
|
|
127
116
|
def print_statuses(statuses)
|
128
117
|
statuses.reverse! if options['reverse'] || options['stream']
|
129
118
|
if options['csv']
|
130
|
-
say
|
119
|
+
say STATUS_HEADINGS.to_csv unless statuses.empty?
|
131
120
|
statuses.each do |status|
|
132
121
|
print_csv_status(status)
|
133
122
|
end
|
@@ -135,12 +124,7 @@ module T
|
|
135
124
|
array = statuses.map do |status|
|
136
125
|
build_long_status(status)
|
137
126
|
end
|
138
|
-
|
139
|
-
array.unshift(status_headings) unless statuses.empty?
|
140
|
-
print_table(array, :truncate => true)
|
141
|
-
else
|
142
|
-
print_table(array)
|
143
|
-
end
|
127
|
+
print_table_with_headings(array, STATUS_HEADINGS)
|
144
128
|
else
|
145
129
|
statuses.each do |status|
|
146
130
|
print_status(status)
|
@@ -148,10 +132,6 @@ module T
|
|
148
132
|
end
|
149
133
|
end
|
150
134
|
|
151
|
-
def user_headings
|
152
|
-
["ID", "Since", "Tweets", "Favorites", "Listed", "Following", "Followers", "Screen name", "Name"]
|
153
|
-
end
|
154
|
-
|
155
135
|
def print_users(users)
|
156
136
|
users = users.sort_by{|user| user.screen_name.downcase} unless options['unsorted']
|
157
137
|
if options['posted']
|
@@ -169,7 +149,7 @@ module T
|
|
169
149
|
end
|
170
150
|
users.reverse! if options['reverse']
|
171
151
|
if options['csv']
|
172
|
-
say
|
152
|
+
say USER_HEADINGS.to_csv unless users.empty?
|
173
153
|
users.each do |user|
|
174
154
|
print_csv_user(user)
|
175
155
|
end
|
@@ -177,20 +157,9 @@ module T
|
|
177
157
|
array = users.map do |user|
|
178
158
|
build_long_user(user)
|
179
159
|
end
|
180
|
-
|
181
|
-
array.unshift(user_headings) unless users.empty?
|
182
|
-
print_table(array, :truncate => true)
|
183
|
-
else
|
184
|
-
print_table(array)
|
185
|
-
end
|
160
|
+
print_table_with_headings(array, USER_HEADINGS)
|
186
161
|
else
|
187
|
-
|
188
|
-
print_in_columns(users.map{|user| "@#{user.screen_name}"})
|
189
|
-
else
|
190
|
-
users.each do |user|
|
191
|
-
say "@#{user.screen_name}"
|
192
|
-
end
|
193
|
-
end
|
162
|
+
print_attribute(users, :screen_name)
|
194
163
|
end
|
195
164
|
end
|
196
165
|
|