t 0.9.7 → 0.9.8

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/lib/t.rb CHANGED
@@ -1,6 +1,6 @@
1
- require 'time'
2
1
  require 'active_support/string_inquirer'
3
2
  require 't/cli'
3
+ require 'time'
4
4
 
5
5
  module T
6
6
  class << self
@@ -1,9 +1,17 @@
1
- require 'oauth'
2
-
3
1
  module T
4
2
  module Authorizable
5
3
 
4
+ DEFAULT_HOST = 'api.twitter.com'
5
+ DEFAULT_PROTOCOL = 'https'
6
+
7
+ private
8
+
9
+ def base_url
10
+ "#{protocol}://#{host}"
11
+ end
12
+
6
13
  def consumer
14
+ require 'oauth'
7
15
  OAuth::Consumer.new(
8
16
  options['consumer-key'],
9
17
  options['consumer-secret'],
@@ -1,31 +1,18 @@
1
- require 'active_support/core_ext/array/grouping'
2
- require 'active_support/core_ext/date/calculations'
3
- require 'active_support/core_ext/integer/time'
4
- require 'active_support/core_ext/numeric/time'
5
- require 't/format_helpers'
6
- require 'csv'
7
- # 'fastercsv' required on Ruby versions < 1.9
8
- require 'fastercsv' unless Array.new.respond_to?(:to_csv)
9
- require 'open-uri'
10
- require 'retryable'
11
- require 't/authorizable'
12
- require 't/collectable'
13
- require 't/core_ext/string'
14
- require 't/delete'
15
- require 't/list'
16
- require 't/printable'
17
- require 't/rcfile'
18
- require 't/requestable'
19
- require 't/search'
20
- require 't/set'
21
- require 't/stream'
22
- require 't/version'
23
1
  require 'thor'
24
- require 'time'
25
- require 'twitter'
26
- require 'yaml'
27
2
 
28
3
  module T
4
+ autoload :Authorizable, 't/authorizable'
5
+ autoload :Collectable, 't/collectable'
6
+ autoload :Delete, 't/delete'
7
+ autoload :FormatHelpers, 't/format_helpers'
8
+ autoload :List, 't/list'
9
+ autoload :Printable, 't/printable'
10
+ autoload :RCFile, 't/rcfile'
11
+ autoload :Requestable, 't/requestable'
12
+ autoload :Search, 't/search'
13
+ autoload :Set, 't/set'
14
+ autoload :Stream, 't/stream'
15
+ autoload :Version, 't/version'
29
16
  class CLI < Thor
30
17
  include T::Authorizable
31
18
  include T::Collectable
@@ -105,11 +92,15 @@ module T
105
92
  method_option "id", :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify input as Twitter user IDs instead of screen names."
106
93
  def block(user, *users)
107
94
  users.unshift(user)
95
+ require 't/core_ext/string'
108
96
  if options['id']
109
97
  users.map!(&:to_i)
110
98
  else
111
99
  users.map!(&:strip_ats)
112
100
  end
101
+ require 't/core_ext/enumerable'
102
+ require 'retryable'
103
+ require 'twitter'
113
104
  users = users.threaded_map do |user|
114
105
  retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
115
106
  client.block(user)
@@ -132,10 +123,13 @@ module T
132
123
  client.direct_messages(opts)
133
124
  end
134
125
  direct_messages.reverse! if options['reverse']
126
+ require 'htmlentities'
135
127
  if options['csv']
128
+ require 'csv'
129
+ require 'fastercsv' unless Array.new.respond_to?(:to_csv)
136
130
  say DIRECT_MESSAGE_HEADINGS.to_csv unless direct_messages.empty?
137
131
  direct_messages.each do |direct_message|
138
- say [direct_message.id, csv_formatted_time(direct_message), direct_message.sender.screen_name, direct_message.text].to_csv
132
+ say [direct_message.id, csv_formatted_time(direct_message), direct_message.sender.screen_name, HTMLEntities.new.decode(direct_message.text)].to_csv
139
133
  end
140
134
  elsif options['long']
141
135
  array = direct_messages.map do |direct_message|
@@ -162,10 +156,13 @@ module T
162
156
  client.direct_messages_sent(opts)
163
157
  end
164
158
  direct_messages.reverse! if options['reverse']
159
+ require 'htmlentities'
165
160
  if options['csv']
161
+ require 'csv'
162
+ require 'fastercsv' unless Array.new.respond_to?(:to_csv)
166
163
  say DIRECT_MESSAGE_HEADINGS.to_csv unless direct_messages.empty?
167
164
  direct_messages.each do |direct_message|
168
- say [direct_message.id, csv_formatted_time(direct_message), direct_message.recipient.screen_name, direct_message.text].to_csv
165
+ say [direct_message.id, csv_formatted_time(direct_message), direct_message.recipient.screen_name, HTMLEntities.new.decode(direct_message.text)].to_csv
169
166
  end
170
167
  elsif options['long']
171
168
  array = direct_messages.map do |direct_message|
@@ -195,6 +192,7 @@ module T
195
192
  method_option "unsorted", :aliases => "-u", :type => :boolean, :default => false, :desc => "Output is not sorted."
196
193
  def groupies(user=nil)
197
194
  if user
195
+ require 't/core_ext/string'
198
196
  user = if options['id']
199
197
  user.to_i
200
198
  else
@@ -208,6 +206,10 @@ module T
208
206
  client.friend_ids(user, :cursor => cursor)
209
207
  end
210
208
  disciple_ids = (follower_ids - following_ids)
209
+ require 'active_support/core_ext/array/grouping'
210
+ require 't/core_ext/enumerable'
211
+ require 'retryable'
212
+ require 'twitter'
211
213
  users = disciple_ids.in_groups_of(MAX_USERS_PER_REQUEST, false).threaded_map do |disciple_id_group|
212
214
  retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
213
215
  client.users(disciple_id_group)
@@ -220,6 +222,7 @@ module T
220
222
  desc "dm USER MESSAGE", "Sends that person a Direct Message."
221
223
  method_option "id", :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify user via ID instead of screen name."
222
224
  def dm(user, message)
225
+ require 't/core_ext/string'
223
226
  user = if options['id']
224
227
  user.to_i
225
228
  else
@@ -238,6 +241,7 @@ module T
238
241
  list = owner
239
242
  owner = @rcfile.active_profile[0]
240
243
  else
244
+ require 't/core_ext/string'
241
245
  owner = if options['id']
242
246
  client.user(owner.to_i).screen_name
243
247
  else
@@ -247,6 +251,7 @@ module T
247
251
  if user.nil?
248
252
  user = @rcfile.active_profile[0]
249
253
  else
254
+ require 't/core_ext/string'
250
255
  user = if options['id']
251
256
  user = client.user(user.to_i).screen_name
252
257
  else
@@ -265,6 +270,7 @@ module T
265
270
  desc "does_follow USER [USER]", "Find out whether one user follows another."
266
271
  method_option "id", :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify user via ID instead of screen name."
267
272
  def does_follow(user1, user2=nil)
273
+ require 't/core_ext/string'
268
274
  user1 = if options['id']
269
275
  client.user(user1.to_i).screen_name
270
276
  else
@@ -292,6 +298,9 @@ module T
292
298
  def favorite(status_id, *status_ids)
293
299
  status_ids.unshift(status_id)
294
300
  status_ids.map!(&:to_i)
301
+ require 't/core_ext/enumerable'
302
+ require 'retryable'
303
+ require 'twitter'
295
304
  favorites = status_ids.threaded_map do |status_id|
296
305
  retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
297
306
  client.favorite(status_id)
@@ -312,6 +321,7 @@ module T
312
321
  method_option "reverse", :aliases => "-r", :type => :boolean, :default => false, :desc => "Reverse the order of the sort."
313
322
  def favorites(user=nil)
314
323
  if user
324
+ require 't/core_ext/string'
315
325
  user = if options['id']
316
326
  user.to_i
317
327
  else
@@ -330,11 +340,15 @@ module T
330
340
  method_option "id", :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify input as Twitter user IDs instead of screen names."
331
341
  def follow(user, *users)
332
342
  users.unshift(user)
343
+ require 't/core_ext/string'
333
344
  if options['id']
334
345
  users.map!(&:to_i)
335
346
  else
336
347
  users.map!(&:strip_ats)
337
348
  end
349
+ require 't/core_ext/enumerable'
350
+ require 'retryable'
351
+ require 'twitter'
338
352
  users = users.threaded_map do |user|
339
353
  retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
340
354
  client.follow(user)
@@ -360,6 +374,7 @@ module T
360
374
  method_option "unsorted", :aliases => "-u", :type => :boolean, :default => false, :desc => "Output is not sorted."
361
375
  def followings(user=nil)
362
376
  if user
377
+ require 't/core_ext/string'
363
378
  user = if options['id']
364
379
  user.to_i
365
380
  else
@@ -369,6 +384,10 @@ module T
369
384
  following_ids = collect_with_cursor do |cursor|
370
385
  client.friend_ids(user, :cursor => cursor)
371
386
  end
387
+ require 'active_support/core_ext/array/grouping'
388
+ require 't/core_ext/enumerable'
389
+ require 'retryable'
390
+ require 'twitter'
372
391
  users = following_ids.in_groups_of(MAX_USERS_PER_REQUEST, false).threaded_map do |following_id_group|
373
392
  retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
374
393
  client.users(following_id_group)
@@ -391,6 +410,7 @@ module T
391
410
  method_option "unsorted", :aliases => "-u", :type => :boolean, :default => false, :desc => "Output is not sorted."
392
411
  def followers(user=nil)
393
412
  if user
413
+ require 't/core_ext/string'
394
414
  user = if options['id']
395
415
  user.to_i
396
416
  else
@@ -400,6 +420,10 @@ module T
400
420
  follower_ids = collect_with_cursor do |cursor|
401
421
  client.follower_ids(user, :cursor => cursor)
402
422
  end
423
+ require 'active_support/core_ext/array/grouping'
424
+ require 't/core_ext/enumerable'
425
+ require 'retryable'
426
+ require 'twitter'
403
427
  users = follower_ids.in_groups_of(MAX_USERS_PER_REQUEST, false).threaded_map do |follower_id_group|
404
428
  retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
405
429
  client.users(follower_id_group)
@@ -422,6 +446,7 @@ module T
422
446
  method_option "unsorted", :aliases => "-u", :type => :boolean, :default => false, :desc => "Output is not sorted."
423
447
  def friends(user=nil)
424
448
  if user
449
+ require 't/core_ext/string'
425
450
  user = if options['id']
426
451
  user.to_i
427
452
  else
@@ -435,6 +460,10 @@ module T
435
460
  client.follower_ids(user, :cursor => cursor)
436
461
  end
437
462
  friend_ids = (following_ids & follower_ids)
463
+ require 'active_support/core_ext/array/grouping'
464
+ require 't/core_ext/enumerable'
465
+ require 'retryable'
466
+ require 'twitter'
438
467
  users = friend_ids.in_groups_of(MAX_USERS_PER_REQUEST, false).threaded_map do |friend_id_group|
439
468
  retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
440
469
  client.users(friend_id_group)
@@ -457,6 +486,7 @@ module T
457
486
  method_option "unsorted", :aliases => "-u", :type => :boolean, :default => false, :desc => "Output is not sorted."
458
487
  def leaders(user=nil)
459
488
  if user
489
+ require 't/core_ext/string'
460
490
  user = if options['id']
461
491
  user.to_i
462
492
  else
@@ -470,6 +500,10 @@ module T
470
500
  client.follower_ids(user, :cursor => cursor)
471
501
  end
472
502
  leader_ids = (following_ids - follower_ids)
503
+ require 'active_support/core_ext/array/grouping'
504
+ require 't/core_ext/enumerable'
505
+ require 'retryable'
506
+ require 'twitter'
473
507
  users = leader_ids.in_groups_of(MAX_USERS_PER_REQUEST, false).threaded_map do |leader_id_group|
474
508
  retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
475
509
  client.users(leader_id_group)
@@ -490,6 +524,7 @@ module T
490
524
  method_option "unsorted", :aliases => "-u", :type => :boolean, :default => false, :desc => "Output is not sorted."
491
525
  def lists(user=nil)
492
526
  if user
527
+ require 't/core_ext/string'
493
528
  user = if options['id']
494
529
  user.to_i
495
530
  else
@@ -534,6 +569,7 @@ module T
534
569
  status = client.status(user.to_i, :include_my_retweet => false)
535
570
  Launchy.open("https://twitter.com/#{status.from_user}/status/#{status.id}", :dry_run => options['display-url'])
536
571
  else
572
+ require 't/core_ext/string'
537
573
  Launchy.open("https://twitter.com/#{user.strip_ats}", :dry_run => options['display-url'])
538
574
  end
539
575
  end
@@ -543,13 +579,15 @@ module T
543
579
  def rate_limit
544
580
  rate_limit_status = client.rate_limit_status
545
581
  if options['csv']
582
+ require 'csv'
583
+ require 'fastercsv' unless Array.new.respond_to?(:to_csv)
546
584
  say ["Hourly limit", "Remaining hits", "Reset time"].to_csv
547
585
  say [rate_limit_status.hourly_limit, rate_limit_status.remaining_hits, csv_formatted_time(rate_limit_status, :reset_time)].to_csv
548
586
  else
549
587
  array = []
550
588
  array << ["Hourly limit", number_with_delimiter(rate_limit_status.hourly_limit)]
551
589
  array << ["Remaining hits", number_with_delimiter(rate_limit_status.remaining_hits)]
552
- array << ["Reset time", "#{ls_formatted_time(rate_limit_status, :reset_time)} (#{distance_of_time_in_words_to_now(rate_limit_status.reset_time)} from now)"]
590
+ array << ["Reset time", "#{ls_formatted_time(rate_limit_status, :reset_time)} (#{time_from_now_in_words(rate_limit_status.reset_time)} from now)"]
553
591
  print_table(array)
554
592
  end
555
593
  end
@@ -569,6 +607,7 @@ module T
569
607
  users += Twitter::Extractor.extract_mentioned_screen_names(status.full_text)
570
608
  users.uniq!
571
609
  end
610
+ require 't/core_ext/string'
572
611
  users.map!(&:prepend_at)
573
612
  opts = {:in_reply_to_status_id => status.id, :trim_user => true}
574
613
  opts.merge!(:lat => location.lat, :long => location.lng) if options['location']
@@ -582,11 +621,15 @@ module T
582
621
  method_option "id", :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify input as Twitter user IDs instead of screen names."
583
622
  def report_spam(user, *users)
584
623
  users.unshift(user)
624
+ require 't/core_ext/string'
585
625
  if options['id']
586
626
  users.map!(&:to_i)
587
627
  else
588
628
  users.map!(&:strip_ats)
589
629
  end
630
+ require 't/core_ext/enumerable'
631
+ require 'retryable'
632
+ require 'twitter'
590
633
  users = users.threaded_map do |user|
591
634
  retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
592
635
  client.report_spam(user)
@@ -601,6 +644,9 @@ module T
601
644
  def retweet(status_id, *status_ids)
602
645
  status_ids.unshift(status_id)
603
646
  status_ids.map!(&:to_i)
647
+ require 't/core_ext/enumerable'
648
+ require 'retryable'
649
+ require 'twitter'
604
650
  retweets = status_ids.threaded_map do |status_id|
605
651
  retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
606
652
  client.retweet(status_id, :trim_user => true)
@@ -621,6 +667,7 @@ module T
621
667
  method_option "reverse", :aliases => "-r", :type => :boolean, :default => false, :desc => "Reverse the order of the sort."
622
668
  def retweets(user=nil)
623
669
  if user
670
+ require 't/core_ext/string'
624
671
  user = if options['id']
625
672
  user.to_i
626
673
  else
@@ -661,7 +708,10 @@ module T
661
708
  elsif status.geo
662
709
  reverse_geocode(status.geo)
663
710
  end
711
+ require 'htmlentities'
664
712
  if options['csv']
713
+ require 'csv'
714
+ require 'fastercsv' unless Array.new.respond_to?(:to_csv)
665
715
  say ["ID", "Text", "Screen name", "Posted at", "Location", "Retweets", "Source", "URL"].to_csv
666
716
  say [status.id, HTMLEntities.new.decode(status.full_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
667
717
  else
@@ -693,6 +743,7 @@ module T
693
743
  method_option "unsorted", :aliases => "-u", :type => :boolean, :default => false, :desc => "Output is not sorted."
694
744
  def suggest(user=nil)
695
745
  if user
746
+ require 't/core_ext/string'
696
747
  user = if options['id']
697
748
  user.to_i
698
749
  else
@@ -713,6 +764,7 @@ module T
713
764
  def timeline(user=nil)
714
765
  count = options['number'] || DEFAULT_NUM_RESULTS
715
766
  if user
767
+ require 't/core_ext/string'
716
768
  user = if options['id']
717
769
  user.to_i
718
770
  else
@@ -749,6 +801,8 @@ module T
749
801
  places = places.sort_by{|places| places.name.downcase} unless options['unsorted']
750
802
  places.reverse! if options['reverse']
751
803
  if options['csv']
804
+ require 'csv'
805
+ require 'fastercsv' unless Array.new.respond_to?(:to_csv)
752
806
  say TREND_HEADINGS.to_csv unless places.empty?
753
807
  places.each do |place|
754
808
  say [place.woeid, place.parent_id, place.place_type, place.name, place.country].to_csv
@@ -769,11 +823,15 @@ module T
769
823
  method_option "id", :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify input as Twitter user IDs instead of screen names."
770
824
  def unfollow(user, *users)
771
825
  users.unshift(user)
826
+ require 't/core_ext/string'
772
827
  if options['id']
773
828
  users.map!(&:to_i)
774
829
  else
775
830
  users.map!(&:strip_ats)
776
831
  end
832
+ require 't/core_ext/enumerable'
833
+ require 'retryable'
834
+ require 'twitter'
777
835
  users = users.threaded_map do |user|
778
836
  retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
779
837
  client.unfollow(user)
@@ -811,6 +869,7 @@ module T
811
869
  method_option "unsorted", :aliases => "-u", :type => :boolean, :default => false, :desc => "Output is not sorted."
812
870
  def users(user, *users)
813
871
  users.unshift(user)
872
+ require 't/core_ext/string'
814
873
  if options['id']
815
874
  users.map!(&:to_i)
816
875
  else
@@ -831,13 +890,17 @@ module T
831
890
  method_option "csv", :aliases => "-c", :type => :boolean, :default => false, :desc => "Output in CSV format."
832
891
  method_option "id", :aliases => "-i", :type => "boolean", :default => false, :desc => "Specify user via ID instead of screen name."
833
892
  def whois(user)
893
+ require 't/core_ext/string'
834
894
  user = if options['id']
835
895
  user.to_i
836
896
  else
837
897
  user.strip_ats
838
898
  end
839
899
  user = client.user(user)
900
+ require 'htmlentities'
840
901
  if options['csv']
902
+ require 'csv'
903
+ require 'fastercsv' unless Array.new.respond_to?(:to_csv)
841
904
  say ["ID", "Verified", "Name", "Screen name", "Bio", "Location", "Following", "Last update", "Lasted updated at", "Since", "Tweets", "Favorites", "Listed", "Following", "Followers", "URL"].to_csv
842
905
  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
843
906
  else
@@ -880,6 +943,7 @@ module T
880
943
  def location
881
944
  return @location if @location
882
945
  require 'geokit'
946
+ require 'open-uri'
883
947
  ip_address = Kernel::open("http://checkip.dyndns.org/") do |body|
884
948
  /(?:\d{1,3}\.){3}\d{1,3}/.match(body.read)[0]
885
949
  end
@@ -1,5 +1,3 @@
1
- require 'retryable'
2
-
3
1
  module T
4
2
  module Collectable
5
3
 
@@ -10,6 +8,8 @@ module T
10
8
  end
11
9
 
12
10
  def collect_with_cursor(collection=[], cursor=-1, &block)
11
+ require 'retryable'
12
+ require 'twitter'
13
13
  object = retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
14
14
  yield cursor
15
15
  end
@@ -18,6 +18,8 @@ module T
18
18
  end
19
19
 
20
20
  def collect_with_max_id(collection=[], max_id=nil, &block)
21
+ require 'retryable'
22
+ require 'twitter'
21
23
  array = retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
22
24
  yield max_id
23
25
  end
@@ -33,8 +35,9 @@ module T
33
35
  opts[:max_id] = max_id unless max_id.nil?
34
36
  opts[key] = number unless number >= MAX_NUM_RESULTS
35
37
  if number > 0
36
- number -= MAX_NUM_RESULTS
37
- yield opts
38
+ statuses = yield opts
39
+ number -= statuses.length
40
+ statuses
38
41
  end
39
42
  end.flatten.compact
40
43
  end