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 CHANGED
@@ -1,4 +1,4 @@
1
- # Twitter CLI [![Build Status](https://secure.travis-ci.org/sferik/t.png?branch=master)][travis] [![Dependency Status](https://gemnasium.com/sferik/t.png?travis)][gemnasium]
1
+ # Twitter CLI [![Build Status](https://secure.travis-ci.org/sferik/t.png?branch=master)][travis] [![Dependency Status](https://gemnasium.com/sferik/t.png?travis)][gemnasium] [![Click here to make a donation to T](http://www.pledgie.com/campaigns/17330.png)][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
  ![History](https://github.com/sferik/t/raw/master/screenshots/history.png)
199
200
 
200
201
  ## Contributing
201
- In the spirit of [free software][fsf], **everyone** is encouraged to help
202
+ In the spirit of [free software][free-sw], **everyone** is encouraged to help
202
203
  improve this project.
203
204
 
204
- [fsf]: http://www.fsf.org/licensing/essays/free-sw.html
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
@@ -1,5 +1,3 @@
1
- #!/usr/bin/env rake
2
-
3
1
  require 'bundler'
4
2
  Bundler::GemHelper.install_tasks
5
3
 
data/lib/t.rb CHANGED
@@ -1 +1,16 @@
1
+ require 'active_support/string_inquirer'
1
2
  require 't/cli'
3
+
4
+ module T
5
+ class << self
6
+
7
+ def env
8
+ @env
9
+ end
10
+
11
+ def env=(environment)
12
+ @env = ActiveSupport::StringInquirer.new(environment)
13
+ end
14
+
15
+ end
16
+ end
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, :banner => "Disable colorization in output"
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 ["ID", "Posted at", "Screen name", "Text"].to_csv unless direct_messages.empty?
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.created_at.utc.strftime("%Y-%m-%d %H:%M:%S %z"), direct_message.sender.screen_name, direct_message.text].to_csv
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
- 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")
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 ["ID", "Posted at", "Screen name", "Text"].to_csv unless direct_messages.empty?
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.created_at.utc.strftime("%Y-%m-%d %H:%M:%S %z"), direct_message.recipient.screen_name, direct_message.text].to_csv
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
- 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")
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.user.screen_name}/status/#{status.id}", :dry_run => options['display-url'])
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.user.screen_name)
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.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
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.user.screen_name}"]
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.user.screen_name}/status/#{status.id}"]
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
- if STDOUT.tty?
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 ["WOEID", "Parent ID", "Type", "Name", "Country"].to_csv unless places.empty?
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
- if STDOUT.tty?
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
- if STDOUT.tty?
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.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
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 << [name_label, user.name] unless user.name.nil?
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
- status = user.following ? "Following" : "Not following"
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
- created_at = user.created_at > 6.months.ago ? user.created_at.strftime("%b %e %H:%M") : user.created_at.strftime("%b %e %Y")
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 = yield cursor
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 = yield max_id
18
- return collection unless !array.nil?
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
- retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
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.user.screen_name}'s status: \"#{status.text}\" from your favorites? [y/N]"
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.user.screen_name}'s status: \"#{status.text}\""
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.user.screen_name}'s status: \"#{status.text}\"? [y/N]"
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.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
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
- 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]
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
- status = list.following ? "Following" : "Not following"
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
- created_at = if Time.parse(list.created_at.to_s) > 6.months.ago
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
- created_at = if Time.parse(status.created_at.to_s) > 6.months.ago
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
- created_at = if user.created_at > 6.months.ago
39
- Time.parse(user.created_at.to_s).strftime("%b %e %H:%M")
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
- user.created_at.strftime("%b %e %Y")
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
- created_at = Time.parse(list.created_at.to_s).utc.strftime("%Y-%m-%d %H:%M:%S %z")
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
- created_at = Time.parse(status.created_at.to_s).utc.strftime("%Y-%m-%d %H:%M:%S %z")
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
- created_at = Time.parse(user.created_at.to_s).utc.strftime("%Y-%m-%d %H:%M:%S %z")
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 list_headings.to_csv unless lists.empty?
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
- if STDOUT.tty?
101
- array.unshift(list_headings) unless lists.empty?
102
- print_table(array, :truncate => true)
103
- else
104
- print_table(array)
105
- end
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
- if STDOUT.tty?
108
- print_in_columns(lists.map(&:full_name))
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.user.screen_name}", [:bold, :yellow])
108
+ say(" @#{status.from_user}", [:bold, :yellow])
120
109
  else
121
- say(" @#{status.user.screen_name}")
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 status_headings.to_csv unless statuses.empty?
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
- if STDOUT.tty?
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 user_headings.to_csv unless users.empty?
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
- if STDOUT.tty?
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
- if STDOUT.tty?
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