t 0.1.0 → 0.2.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.
@@ -0,0 +1,112 @@
1
+ require 't/core_ext/string'
2
+ require 't/rcfile'
3
+ require 'thor'
4
+ require 'twitter'
5
+
6
+ module T
7
+ class CLI
8
+ class Delete < Thor
9
+ DEFAULT_HOST = 'api.twitter.com'
10
+ DEFAULT_PROTOCOL = 'https'
11
+
12
+ check_unknown_options!
13
+
14
+ def initialize(*)
15
+ super
16
+ @rcfile = RCFile.instance
17
+ end
18
+
19
+ desc "block SCREEN_NAME", "Unblock a user."
20
+ def block(screen_name)
21
+ screen_name = screen_name.strip_at
22
+ user = client.unblock(screen_name, :include_entities => false)
23
+ say "@#{@rcfile.default_profile[0]} unblocked @#{user.screen_name}."
24
+ say
25
+ say "Run `#{$0} block #{user.screen_name}` to block."
26
+ end
27
+
28
+ desc "dm", "Delete the last Direct Message sent."
29
+ def dm
30
+ direct_message = client.direct_messages_sent(:count => 1, :include_entities => false).first
31
+ if direct_message
32
+ unless parent_options['force']
33
+ return unless yes? "Are you sure you want to permanently delete the direct message to @#{direct_message.recipient.screen_name}: \"#{direct_message.text}\"?"
34
+ end
35
+ direct_message = client.direct_message_destroy(direct_message.id, :include_entities => false)
36
+ say "@#{direct_message.sender.screen_name} deleted the direct message sent to @#{direct_message.recipient.screen_name}: \"#{direct_message.text}\""
37
+ else
38
+ raise Thor::Error, "Direct Message not found"
39
+ end
40
+ end
41
+ map %w(m) => :dm
42
+
43
+ desc "favorite", "Deletes the last favorite."
44
+ def favorite
45
+ status = client.favorites(:count => 1, :include_entities => false).first
46
+ if status
47
+ unless parent_options['force']
48
+ return unless yes? "Are you sure you want to delete the favorite of @#{status.user.screen_name}'s latest status: \"#{status.text}\"?"
49
+ end
50
+ client.unfavorite(status.id, :include_entities => false)
51
+ say "@#{@rcfile.default_profile[0]} unfavorited @#{status.user.screen_name}'s latest status: \"#{status.text}\""
52
+ say
53
+ say "Run `#{$0} favorite #{status.user.screen_name}` to favorite."
54
+ else
55
+ raise Thor::Error, "Tweet not found"
56
+ end
57
+ end
58
+ map %w(fave) => :favorite
59
+
60
+ desc "list LIST_NAME", "Delete a list."
61
+ def list(list_name)
62
+ unless parent_options['force']
63
+ return unless yes? "Are you sure you want to permanently delete the list \"#{list_name}\"?"
64
+ end
65
+ status = client.list_destroy(list_name)
66
+ say "@#{@rcfile.default_profile[0]} deleted the list \"#{list_name}\"."
67
+ end
68
+
69
+ desc "status", "Delete a Tweet."
70
+ def status
71
+ user = client.user(:include_entities => false)
72
+ if user.status
73
+ unless parent_options['force']
74
+ return unless yes? "Are you sure you want to permanently delete @#{@rcfile.default_profile[0]}'s latest status: \"#{user.status.text}\"?"
75
+ end
76
+ status = client.status_destroy(user.status.id, :include_entities => false, :trim_user => true)
77
+ say "@#{@rcfile.default_profile[0]} deleted the status: \"#{status.text}\""
78
+ else
79
+ raise Thor::Error, "Tweet not found"
80
+ end
81
+ end
82
+ map %w(post tweet update) => :status
83
+
84
+ private
85
+
86
+ def base_url
87
+ "#{protocol}://#{host}"
88
+ end
89
+
90
+ def client
91
+ return @client if @client
92
+ @rcfile.path = parent_options['profile'] if parent_options['profile']
93
+ @client = Twitter::Client.new(
94
+ :endpoint => base_url,
95
+ :consumer_key => @rcfile.default_consumer_key,
96
+ :consumer_secret => @rcfile.default_consumer_secret,
97
+ :oauth_token => @rcfile.default_token,
98
+ :oauth_token_secret => @rcfile.default_secret
99
+ )
100
+ end
101
+
102
+ def host
103
+ parent_options['host'] || DEFAULT_HOST
104
+ end
105
+
106
+ def protocol
107
+ parent_options['no_ssl'] ? 'http' : DEFAULT_PROTOCOL
108
+ end
109
+
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,66 @@
1
+ require 't/core_ext/string'
2
+ require 't/rcfile'
3
+ require 'thor'
4
+ require 'twitter'
5
+
6
+ module T
7
+ class CLI
8
+ class Follow < Thor
9
+ DEFAULT_HOST = 'api.twitter.com'
10
+ DEFAULT_PROTOCOL = 'https'
11
+
12
+ check_unknown_options!
13
+
14
+ def initialize(*)
15
+ super
16
+ @rcfile = RCFile.instance
17
+ end
18
+
19
+ desc "users SCREEN_NAME [SCREEN_NAME...]", "Allows you to start following users."
20
+ def users(screen_name, *screen_names)
21
+ screen_names.unshift(screen_name)
22
+ users = screen_names.map do |screen_name|
23
+ screen_name = screen_name.strip_at
24
+ user = client.follow(screen_name, :include_entities => false)
25
+ say "@#{@rcfile.default_profile[0]} is now following @#{user.screen_name}."
26
+ user
27
+ end
28
+ number = users.length
29
+ say "@#{@rcfile.default_profile[0]} is now following #{number} more #{number == 1 ? 'user' : 'users'}."
30
+ say
31
+ say "Run `#{$0} unfollow users #{screen_names.join(' ')}` to stop."
32
+ end
33
+
34
+ desc "all SUBCOMMAND ...ARGS", "Follow all users."
35
+ require 't/cli/follow/all'
36
+ subcommand 'all', CLI::Follow::All
37
+
38
+ private
39
+
40
+ def base_url
41
+ "#{protocol}://#{host}"
42
+ end
43
+
44
+ def client
45
+ return @client if @client
46
+ @rcfile.path = parent_options['profile'] if parent_options['profile']
47
+ @client = Twitter::Client.new(
48
+ :endpoint => base_url,
49
+ :consumer_key => @rcfile.default_consumer_key,
50
+ :consumer_secret => @rcfile.default_consumer_secret,
51
+ :oauth_token => @rcfile.default_token,
52
+ :oauth_token_secret => @rcfile.default_secret
53
+ )
54
+ end
55
+
56
+ def host
57
+ parent_options['host'] || DEFAULT_HOST
58
+ end
59
+
60
+ def protocol
61
+ parent_options['no_ssl'] ? 'http' : DEFAULT_PROTOCOL
62
+ end
63
+
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,99 @@
1
+ require 't/rcfile'
2
+ require 'thor'
3
+ require 'twitter'
4
+
5
+ module T
6
+ class CLI
7
+ class Follow
8
+ class All < Thor
9
+ DEFAULT_HOST = 'api.twitter.com'
10
+ DEFAULT_PROTOCOL = 'https'
11
+
12
+ check_unknown_options!
13
+
14
+ def initialize(*)
15
+ super
16
+ @rcfile = RCFile.instance
17
+ end
18
+
19
+ desc "followers", "Follow all followers."
20
+ def followers
21
+ follower_ids = []
22
+ cursor = -1
23
+ until cursor == 0
24
+ followers = client.follower_ids(:cursor => cursor)
25
+ follower_ids += followers.ids
26
+ cursor = followers.next_cursor
27
+ end
28
+ friend_ids = []
29
+ cursor = -1
30
+ until cursor == 0
31
+ friends = client.friend_ids(:cursor => cursor)
32
+ friend_ids += friends.ids
33
+ cursor = friends.next_cursor
34
+ end
35
+ follow_ids = (follower_ids - friend_ids)
36
+ number = follow_ids.length
37
+ return say "@#{@rcfile.default_profile[0]} is already following all of his or her followers." if number.zero?
38
+ return unless yes? "Are you sure you want to follow #{number} #{number == 1 ? 'user' : 'users'}?"
39
+ screen_names = follow_ids.map do |follow_id|
40
+ user = client.follow(follow_id, :include_entities => false)
41
+ say "@#{@rcfile.default_profile[0]} is now following @#{user.screen_name}."
42
+ user.screen_name
43
+ end
44
+ say "@#{@rcfile.default_profile[0]} is now following #{number} more #{number == 1 ? 'user' : 'users'}."
45
+ say
46
+ say "Run `#{$0} unfollow users #{screen_names.join(' ')}` to stop."
47
+ end
48
+
49
+ desc "listed LIST_NAME", "Follow all members of a list."
50
+ def listed(list_name)
51
+ list_member_collection = []
52
+ cursor = -1
53
+ until cursor == 0
54
+ list_members = client.list_members(list_name, :cursor => cursor, :skip_status => true, :include_entities => false)
55
+ list_member_collection += list_members.users
56
+ cursor = list_members.next_cursor
57
+ end
58
+ number = list_member_collection.length
59
+ return say "@#{@rcfile.default_profile[0]} is already following all list members." if number.zero?
60
+ return unless yes? "Are you sure you want to follow #{number} #{number == 1 ? 'user' : 'users'}?"
61
+ list_member_collection.each do |list_member|
62
+ user = client.follow(list_member.id, :include_entities => false)
63
+ say "@#{@rcfile.default_profile[0]} is now following @#{user.screen_name}."
64
+ end
65
+ say "@#{@rcfile.default_profile[0]} is now following #{number} more #{number == 1 ? 'user' : 'users'}."
66
+ say
67
+ say "Run `#{$0} unfollow all listed #{list_name}` to stop."
68
+ end
69
+
70
+ private
71
+
72
+ def base_url
73
+ "#{protocol}://#{host}"
74
+ end
75
+
76
+ def client
77
+ return @client if @client
78
+ @rcfile.path = parent_options['profile'] if parent_options['profile']
79
+ @client = Twitter::Client.new(
80
+ :endpoint => base_url,
81
+ :consumer_key => @rcfile.default_consumer_key,
82
+ :consumer_secret => @rcfile.default_consumer_secret,
83
+ :oauth_token => @rcfile.default_token,
84
+ :oauth_token_secret => @rcfile.default_secret
85
+ )
86
+ end
87
+
88
+ def host
89
+ parent_options['host'] || DEFAULT_HOST
90
+ end
91
+
92
+ def protocol
93
+ parent_options['no_ssl'] ? 'http' : DEFAULT_PROTOCOL
94
+ end
95
+
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,108 @@
1
+ require 'action_view'
2
+ require 't/rcfile'
3
+ require 'thor'
4
+ require 'twitter'
5
+
6
+ module T
7
+ class CLI
8
+ class List < Thor
9
+ include ActionView::Helpers::DateHelper
10
+
11
+ DEFAULT_HOST = 'api.twitter.com'
12
+ DEFAULT_PROTOCOL = 'https'
13
+
14
+ check_unknown_options!
15
+
16
+ def initialize(*)
17
+ super
18
+ @rcfile = RCFile.instance
19
+ end
20
+
21
+ desc "create LIST_NAME [DESCRIPTION]", "Create a new list."
22
+ method_option :private, :aliases => "-p", :type => :boolean
23
+ def create(list_name, description="")
24
+ hash = description.blank? ? {} : {:description => description}
25
+ hash.merge!(:mode => 'private') if options['private']
26
+ client.list_create(list_name, hash)
27
+ say "@#{@rcfile.default_profile[0]} created the list \"#{list_name}\"."
28
+ end
29
+
30
+ desc "timeline LIST_NAME", "Show tweet timeline for members of the specified list."
31
+ method_option :number, :aliases => "-n", :type => :numeric, :default => 20
32
+ method_option :reverse, :aliases => "-r", :type => :boolean, :default => false
33
+ def timeline(list_name)
34
+ hash = {:include_entities => false}
35
+ hash.merge!(:per_page => options['number']) if options['number']
36
+ timeline = client.list_timeline(list_name, hash)
37
+ timeline.reverse! if options['reverse']
38
+ run_pager
39
+ timeline.map do |status|
40
+ say "#{status.user.screen_name.rjust(20)}: #{status.text} (#{time_ago_in_words(status.created_at)} ago)"
41
+ end
42
+ end
43
+ map %w(tl) => :timeline
44
+
45
+ desc "add SUBCOMMAND ...ARGS", "Add users to a list."
46
+ require 't/cli/list/add'
47
+ subcommand 'add', CLI::List::Add
48
+
49
+ desc "remove SUBCOMMAND ...ARGS", "Remove users from a list."
50
+ require 't/cli/list/remove'
51
+ subcommand 'remove', CLI::List::Remove
52
+
53
+ private
54
+
55
+ def base_url
56
+ "#{protocol}://#{host}"
57
+ end
58
+
59
+ def client
60
+ return @client if @client
61
+ @rcfile.path = parent_options['profile'] if parent_options['profile']
62
+ @client = Twitter::Client.new(
63
+ :endpoint => base_url,
64
+ :consumer_key => @rcfile.default_consumer_key,
65
+ :consumer_secret => @rcfile.default_consumer_secret,
66
+ :oauth_token => @rcfile.default_token,
67
+ :oauth_token_secret => @rcfile.default_secret
68
+ )
69
+ end
70
+
71
+ def host
72
+ parent_options['host'] || DEFAULT_HOST
73
+ end
74
+
75
+ def protocol
76
+ parent_options['no_ssl'] ? 'http' : DEFAULT_PROTOCOL
77
+ end
78
+
79
+ def run_pager
80
+ return if RUBY_PLATFORM =~ /win32/
81
+ return if ENV["T_ENV"] == "test"
82
+ return unless STDOUT.tty?
83
+
84
+ read, write = IO.pipe
85
+
86
+ unless Kernel.fork # Child process
87
+ STDOUT.reopen(write)
88
+ STDERR.reopen(write) if STDERR.tty?
89
+ read.close
90
+ write.close
91
+ return
92
+ end
93
+
94
+ # Parent process, become pager
95
+ STDIN.reopen(read)
96
+ read.close
97
+ write.close
98
+
99
+ ENV['LESS'] = 'FSRX' # Don't page if the input is short enough
100
+
101
+ Kernel.select [STDIN] # Wait until we have input before we start the pager
102
+ pager = ENV['PAGER'] || 'less'
103
+ exec pager rescue exec "/bin/sh", "-c", pager
104
+ end
105
+
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,64 @@
1
+ require 't/core_ext/string'
2
+ require 't/rcfile'
3
+ require 'thor'
4
+ require 'twitter'
5
+
6
+ module T
7
+ class CLI
8
+ class List
9
+ class Add < Thor
10
+ DEFAULT_HOST = 'api.twitter.com'
11
+ DEFAULT_PROTOCOL = 'https'
12
+
13
+ check_unknown_options!
14
+
15
+ def initialize(*)
16
+ super
17
+ @rcfile = RCFile.instance
18
+ end
19
+
20
+ desc "users LIST_NAME SCREEN_NAME [SCREEN_NAME...]", "Add users to a list."
21
+ def users(list_name, screen_name, *screen_names)
22
+ screen_names.unshift(screen_name)
23
+ screen_names.map!{|screen_name| screen_name.strip_at}
24
+ client.list_add_members(list_name, screen_names)
25
+ number = screen_names.length
26
+ say "@#{@rcfile.default_profile[0]} added #{number} #{number == 1 ? 'user' : 'users'} to the list \"#{list_name}\"."
27
+ say
28
+ say "Run `#{$0} list remove users #{list_name} #{screen_names.join(' ')}` to undo."
29
+ end
30
+
31
+ desc "all SUBCOMMAND ...ARGS", "Add all users to a list."
32
+ require 't/cli/list/add/all'
33
+ subcommand 'all', CLI::List::Add::All
34
+
35
+ private
36
+
37
+ def base_url
38
+ "#{protocol}://#{host}"
39
+ end
40
+
41
+ def client
42
+ return @client if @client
43
+ @rcfile.path = parent_options['profile'] if parent_options['profile']
44
+ @client = Twitter::Client.new(
45
+ :endpoint => base_url,
46
+ :consumer_key => @rcfile.default_consumer_key,
47
+ :consumer_secret => @rcfile.default_consumer_secret,
48
+ :oauth_token => @rcfile.default_token,
49
+ :oauth_token_secret => @rcfile.default_secret
50
+ )
51
+ end
52
+
53
+ def host
54
+ parent_options['host'] || DEFAULT_HOST
55
+ end
56
+
57
+ def protocol
58
+ parent_options['no_ssl'] ? 'http' : DEFAULT_PROTOCOL
59
+ end
60
+
61
+ end
62
+ end
63
+ end
64
+ end