twat 0.5.3 → 0.5.4
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/.rvmrc +1 -1
- data/TODO +8 -0
- data/lib/twat.rb +5 -1
- data/lib/twat/actions.rb +0 -207
- data/lib/twat/actions/add.rb +35 -0
- data/lib/twat/actions/delete.rb +14 -0
- data/lib/twat/actions/follow.rb +135 -0
- data/lib/twat/actions/follow_user.rb +11 -0
- data/lib/twat/actions/setoption.rb +14 -0
- data/lib/twat/actions/show.rb +12 -0
- data/lib/twat/actions/tweet.rb +14 -0
- data/lib/twat/actions/updateconfig.rb +9 -0
- data/lib/twat/actions/user_feed.rb +17 -0
- data/lib/twat/actions/version.rb +9 -0
- metadata +17 -7
data/.rvmrc
CHANGED
@@ -1 +1 @@
|
|
1
|
-
rvm
|
1
|
+
rvm 1.9.3
|
data/TODO
CHANGED
@@ -53,3 +53,11 @@ etc etc)
|
|
53
53
|
|
54
54
|
into a wrapper for each service so that twat can natively support
|
55
55
|
facebook, g+ etc etc as I get around to writing the new modules.
|
56
|
+
|
57
|
+
READLINE SHIT
|
58
|
+
=============
|
59
|
+
|
60
|
+
Would be pretty sweet to be able to change color after too many chars
|
61
|
+
entered, be able to puts a tweet while user is entering text, etc.
|
62
|
+
|
63
|
+
Look into it (and create another feature branch that's destined to rot)
|
data/lib/twat.rb
CHANGED
@@ -10,6 +10,10 @@ require 'oauth'
|
|
10
10
|
require "twat/#{filename}"
|
11
11
|
end
|
12
12
|
|
13
|
+
%w[follow tweet add delete follow_user updateconfig setoption show user_feed version].each do |filename|
|
14
|
+
require "twat/actions/#{filename}"
|
15
|
+
end
|
16
|
+
|
13
17
|
class String
|
14
18
|
# TODO - It'd be nice to implement the colors support here, maybe even only
|
15
19
|
# mix this in if it's enabled?
|
@@ -45,7 +49,7 @@ end
|
|
45
49
|
module Twat
|
46
50
|
VERSION_MAJOR = 0
|
47
51
|
VERSION_MINOR = 5
|
48
|
-
VERSION_PATCH =
|
52
|
+
VERSION_PATCH = 4
|
49
53
|
|
50
54
|
VERSION = "#{VERSION_MAJOR}.#{VERSION_MINOR}.#{VERSION_PATCH}"
|
51
55
|
class Twat
|
data/lib/twat/actions.rb
CHANGED
@@ -2,218 +2,11 @@ module Twat
|
|
2
2
|
OAUTH_TOKENS = [ :oauth_token, :oauth_token_secret ]
|
3
3
|
CONSUMER_TOKENS = [ :consumer_key, :consumer_secret ]
|
4
4
|
|
5
|
-
class NoSuchTweet < Exception; end
|
6
|
-
|
7
|
-
class TweetStack
|
8
|
-
# A circularly linked list representing all of the tweets printed thus far,
|
9
|
-
# for the purposes of retrieving them after being printed
|
10
|
-
def initialize
|
11
|
-
@stack = {}
|
12
|
-
@_next = 0
|
13
|
-
end
|
14
|
-
|
15
|
-
def [] k
|
16
|
-
@stack[k]
|
17
|
-
end
|
18
|
-
|
19
|
-
def << v
|
20
|
-
@stack[nxt] = v
|
21
|
-
end
|
22
|
-
|
23
|
-
def include? k
|
24
|
-
@stack.keys.include?(k)
|
25
|
-
end
|
26
|
-
|
27
|
-
def last
|
28
|
-
# I see the irony
|
29
|
-
@_next
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
|
34
|
-
def nxt
|
35
|
-
if @_next == 99
|
36
|
-
@_next = 0
|
37
|
-
else
|
38
|
-
@_next += 1
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
43
5
|
|
44
6
|
class Actions
|
45
7
|
|
46
8
|
attr_accessor :config, :opts, :failcount
|
47
9
|
|
48
|
-
def tweet
|
49
|
-
twitter_auth
|
50
|
-
|
51
|
-
raise TweetTooLong if opts.msg.length > 140
|
52
|
-
|
53
|
-
Twitter.update(opts.msg)
|
54
|
-
#puts opts.msg
|
55
|
-
end
|
56
|
-
|
57
|
-
# Add is somewhat of a special case, everything else hangs off config for
|
58
|
-
# it's magic, However we're forced to do it manually here- config doesn't
|
59
|
-
# know anything about it yet
|
60
|
-
def add
|
61
|
-
endpoint = Endpoint.new(opts[:endpoint])
|
62
|
-
v = endpoint.consumer_info.map do |key, value|
|
63
|
-
value
|
64
|
-
end
|
65
|
-
|
66
|
-
oauth_options = { :site => endpoint.url }
|
67
|
-
oauth_options.merge!(endpoint.oauth_options)
|
68
|
-
|
69
|
-
oauth = OAuth::Consumer.new( v[0], v[1], oauth_options )
|
70
|
-
token_request = oauth.get_request_token()
|
71
|
-
puts "Please authenticate the application at #{token_request.authorize_url}, then enter pin"
|
72
|
-
pin = STDIN.gets.chomp
|
73
|
-
begin
|
74
|
-
access_token = token_request.get_access_token(oauth_verifier: pin)
|
75
|
-
account_settings = {
|
76
|
-
oauth_token: access_token.token,
|
77
|
-
oauth_token_secret: access_token.secret,
|
78
|
-
endpoint: opts[:endpoint]
|
79
|
-
}
|
80
|
-
config.accounts[opts[:account]] = account_settings
|
81
|
-
config.save!
|
82
|
-
rescue OAuth::Unauthorized
|
83
|
-
puts "Couldn't authenticate you, did you enter the pin correctly?"
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def delete
|
88
|
-
if config.accounts.delete(opts[:account])
|
89
|
-
config.save!
|
90
|
-
puts "Successfully deleted"
|
91
|
-
else
|
92
|
-
puts "No such account"
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
def follow_user
|
97
|
-
twitter_auth
|
98
|
-
|
99
|
-
Twitter.follow(opts[:user])
|
100
|
-
end
|
101
|
-
|
102
|
-
def setoption
|
103
|
-
k, v = opts[:optval].split("=")
|
104
|
-
raise RequiresOptVal unless v
|
105
|
-
options = Options.new
|
106
|
-
options.send(:"#{k}=", v)
|
107
|
-
|
108
|
-
puts "Successfully set #{k} as #{v}"
|
109
|
-
end
|
110
|
-
|
111
|
-
def updateconfig
|
112
|
-
config.update!
|
113
|
-
end
|
114
|
-
|
115
|
-
def show
|
116
|
-
twitter_auth
|
117
|
-
Twitter.home_timeline(:count => opts[:count]).reverse.each do |tweet|
|
118
|
-
format(tweet)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
private
|
123
|
-
|
124
|
-
# The handling of the shared variable in the follow code makes a shitton
|
125
|
-
# more sense in the context of a class (ala the subcommands branch). For
|
126
|
-
# now the kludginess must be tolerated
|
127
|
-
|
128
|
-
# @return last_id
|
129
|
-
def process_followed(tweets)
|
130
|
-
last_id = nil
|
131
|
-
tweets.reverse.each do |tweet|
|
132
|
-
id = @tweetstack << tweet
|
133
|
-
beep if config.beep? && tweet.text.mentions?(config.account_name)
|
134
|
-
format(tweet, @tweetstack.last)
|
135
|
-
last_id = tweet.id
|
136
|
-
end
|
137
|
-
|
138
|
-
return last_id
|
139
|
-
end
|
140
|
-
|
141
|
-
def handle_input(inp)
|
142
|
-
case inp
|
143
|
-
when /[rR][tT] ([0-9]{1,2})/
|
144
|
-
begin
|
145
|
-
retweet($1.to_i)
|
146
|
-
rescue NoSuchTweet
|
147
|
-
puts "No such tweet".red
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
def retweet(idx)
|
153
|
-
raise NoSuchTweet unless @tweetstack.include?(idx)
|
154
|
-
Twitter.retweet(@tweetstack[idx].id)
|
155
|
-
end
|
156
|
-
|
157
|
-
public
|
158
|
-
|
159
|
-
def follow
|
160
|
-
# I can't see any way to poll the server for updates, so in the meantime
|
161
|
-
# we will have to retrieve a few tweets from the timeline, and then poll
|
162
|
-
# occasionally :/
|
163
|
-
twitter_auth
|
164
|
-
failcount = 0
|
165
|
-
@tweetstack = TweetStack.new
|
166
|
-
|
167
|
-
# Get 5 tweets
|
168
|
-
tweets = Twitter.home_timeline(:count => 5)
|
169
|
-
while true do
|
170
|
-
begin
|
171
|
-
last_id = process_followed(tweets) if tweets.any?
|
172
|
-
config.polling_interval.times do
|
173
|
-
handle_input(STDIN.read_nonblock(128).chop) rescue nil
|
174
|
-
sleep 1
|
175
|
-
end
|
176
|
-
tweets = Twitter.home_timeline(:since_id => last_id)
|
177
|
-
failcount = 0
|
178
|
-
rescue Interrupt
|
179
|
-
break
|
180
|
-
rescue Twitter::ServiceUnavailable
|
181
|
-
if failcount > 2
|
182
|
-
puts "3 consecutive failures, giving up"
|
183
|
-
else
|
184
|
-
sleeptime = 60 * (failcount + 1)
|
185
|
-
print "(__-){".red
|
186
|
-
puts ": the fail whale has been rolled out, sleeping for #{sleeptime} seconds"
|
187
|
-
sleep sleeptime
|
188
|
-
failcount += 1
|
189
|
-
end
|
190
|
-
rescue Errno::ECONNRESET
|
191
|
-
rescue Errno::ETIMEDOUT
|
192
|
-
if failcount > 2
|
193
|
-
puts "3 consecutive failures, giving up"
|
194
|
-
else
|
195
|
-
failcount += 1
|
196
|
-
end
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
def user_feed
|
202
|
-
twitter_auth
|
203
|
-
|
204
|
-
begin
|
205
|
-
Twitter.user_timeline(opts[:user], :count => opts[:count]).each do |tweet|
|
206
|
-
format(tweet)
|
207
|
-
end
|
208
|
-
rescue Twitter::NotFound
|
209
|
-
puts "#{opts[:user].bold.red} doesn't appear to be a valid user"
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
def version
|
214
|
-
puts "twat: #{VERSION_MAJOR}.#{VERSION_MINOR}.#{VERSION_PATCH}"
|
215
|
-
end
|
216
|
-
|
217
10
|
def method_missing(sym, *args, &block)
|
218
11
|
raise NoSuchCommand
|
219
12
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Twat
|
2
|
+
class Actions
|
3
|
+
|
4
|
+
# Add is somewhat of a special case, everything else hangs off config for
|
5
|
+
# it's magic, However we're forced to do it manually here- config doesn't
|
6
|
+
# know anything about it yet
|
7
|
+
def add
|
8
|
+
endpoint = Endpoint.new(opts[:endpoint])
|
9
|
+
v = endpoint.consumer_info.map do |key, value|
|
10
|
+
value
|
11
|
+
end
|
12
|
+
|
13
|
+
oauth_options = { :site => endpoint.url }
|
14
|
+
oauth_options.merge!(endpoint.oauth_options)
|
15
|
+
|
16
|
+
oauth = OAuth::Consumer.new( v[0], v[1], oauth_options )
|
17
|
+
token_request = oauth.get_request_token()
|
18
|
+
puts "Please authenticate the application at #{token_request.authorize_url}, then enter pin"
|
19
|
+
pin = STDIN.gets.chomp
|
20
|
+
begin
|
21
|
+
access_token = token_request.get_access_token(oauth_verifier: pin)
|
22
|
+
account_settings = {
|
23
|
+
oauth_token: access_token.token,
|
24
|
+
oauth_token_secret: access_token.secret,
|
25
|
+
endpoint: opts[:endpoint]
|
26
|
+
}
|
27
|
+
config.accounts[opts[:account]] = account_settings
|
28
|
+
config.save!
|
29
|
+
rescue OAuth::Unauthorized
|
30
|
+
puts "Couldn't authenticate you, did you enter the pin correctly?"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
module Twat
|
2
|
+
|
3
|
+
class NoSuchTweet < Exception; end
|
4
|
+
|
5
|
+
class TweetStack
|
6
|
+
# A circularly linked list representing all of the tweets printed thus far,
|
7
|
+
# for the purposes of retrieving them after being printed
|
8
|
+
def initialize
|
9
|
+
@stack = {}
|
10
|
+
@_next = 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def [] k
|
14
|
+
@stack[k]
|
15
|
+
end
|
16
|
+
|
17
|
+
def << v
|
18
|
+
@stack[nxt] = v
|
19
|
+
end
|
20
|
+
|
21
|
+
def include? k
|
22
|
+
@stack.keys.include?(k)
|
23
|
+
end
|
24
|
+
|
25
|
+
def last
|
26
|
+
# I see the irony
|
27
|
+
@_next
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def nxt
|
33
|
+
if @_next == 99
|
34
|
+
@_next = 1
|
35
|
+
else
|
36
|
+
@_next += 1
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
class Actions
|
44
|
+
|
45
|
+
def follow
|
46
|
+
# I can't see any way to poll the server for updates, so in the meantime
|
47
|
+
# we will have to retrieve a few tweets from the timeline, and then poll
|
48
|
+
# occasionally :/
|
49
|
+
twitter_auth
|
50
|
+
failcount = 0
|
51
|
+
@tweetstack = TweetStack.new
|
52
|
+
|
53
|
+
# Get 5 tweets
|
54
|
+
tweets = Twitter.home_timeline(:count => 5)
|
55
|
+
while true do
|
56
|
+
begin
|
57
|
+
last_id = process_followed(tweets) if tweets.any?
|
58
|
+
config.polling_interval.times do
|
59
|
+
begin
|
60
|
+
handle_input(STDIN.read_nonblock(128).chop)
|
61
|
+
rescue Errno::EAGAIN
|
62
|
+
nil
|
63
|
+
rescue TweetTooLong
|
64
|
+
puts "Too long".red
|
65
|
+
end
|
66
|
+
sleep 1
|
67
|
+
end
|
68
|
+
tweets = Twitter.home_timeline(:since_id => last_id)
|
69
|
+
failcount = 0
|
70
|
+
rescue Interrupt
|
71
|
+
break
|
72
|
+
rescue Twitter::ServiceUnavailable
|
73
|
+
if failcount > 2
|
74
|
+
puts "3 consecutive failures, giving up"
|
75
|
+
else
|
76
|
+
sleeptime = 60 * (failcount + 1)
|
77
|
+
print "(__-){".red
|
78
|
+
puts ": the fail whale has been rolled out, sleeping for #{sleeptime} seconds"
|
79
|
+
sleep sleeptime
|
80
|
+
failcount += 1
|
81
|
+
end
|
82
|
+
rescue Errno::ECONNRESET
|
83
|
+
rescue Errno::ETIMEDOUT
|
84
|
+
if failcount > 2
|
85
|
+
puts "3 consecutive failures, giving up"
|
86
|
+
else
|
87
|
+
failcount += 1
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
# The handling of the shared variable in the follow code makes a shitton
|
96
|
+
# more sense in the context of a class (ala the subcommands branch). For
|
97
|
+
# now the kludginess must be tolerated
|
98
|
+
|
99
|
+
# @return last_id
|
100
|
+
def process_followed(tweets)
|
101
|
+
last_id = nil
|
102
|
+
tweets.reverse.each do |tweet|
|
103
|
+
id = @tweetstack << tweet
|
104
|
+
beep if config.beep? && tweet.text.mentions?(config.account_name)
|
105
|
+
format(tweet, @tweetstack.last)
|
106
|
+
last_id = tweet.id
|
107
|
+
end
|
108
|
+
|
109
|
+
return last_id
|
110
|
+
end
|
111
|
+
|
112
|
+
def handle_input(inp)
|
113
|
+
case inp
|
114
|
+
when /[rR][tT] ([0-9]{1,2})/
|
115
|
+
begin
|
116
|
+
retweet($1.to_i)
|
117
|
+
rescue NoSuchTweet
|
118
|
+
puts "No such tweet".red
|
119
|
+
end
|
120
|
+
else
|
121
|
+
# Assume they want to tweet something
|
122
|
+
raise TweetTooLong if inp.length > 140
|
123
|
+
|
124
|
+
Twitter.update(inp)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def retweet(idx)
|
129
|
+
raise NoSuchTweet unless @tweetstack.include?(idx)
|
130
|
+
Twitter.retweet(@tweetstack[idx].id)
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Twat
|
2
|
+
class Actions
|
3
|
+
|
4
|
+
def user_feed
|
5
|
+
twitter_auth
|
6
|
+
|
7
|
+
begin
|
8
|
+
Twitter.user_timeline(opts[:user], :count => opts[:count]).each do |tweet|
|
9
|
+
format(tweet)
|
10
|
+
end
|
11
|
+
rescue Twitter::NotFound
|
12
|
+
puts "#{opts[:user].bold.red} doesn't appear to be a valid user"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: twat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-02-
|
12
|
+
date: 2012-02-11 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: twitter
|
16
|
-
requirement: &
|
16
|
+
requirement: &13247260 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *13247260
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: oauth
|
27
|
-
requirement: &
|
27
|
+
requirement: &13246620 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *13246620
|
36
36
|
description: Command line tool for tweeting and whatnot
|
37
37
|
email:
|
38
38
|
- richo@psych0tik.net
|
@@ -50,6 +50,16 @@ files:
|
|
50
50
|
- bin/twat
|
51
51
|
- lib/twat.rb
|
52
52
|
- lib/twat/actions.rb
|
53
|
+
- lib/twat/actions/add.rb
|
54
|
+
- lib/twat/actions/delete.rb
|
55
|
+
- lib/twat/actions/follow.rb
|
56
|
+
- lib/twat/actions/follow_user.rb
|
57
|
+
- lib/twat/actions/setoption.rb
|
58
|
+
- lib/twat/actions/show.rb
|
59
|
+
- lib/twat/actions/tweet.rb
|
60
|
+
- lib/twat/actions/updateconfig.rb
|
61
|
+
- lib/twat/actions/user_feed.rb
|
62
|
+
- lib/twat/actions/version.rb
|
53
63
|
- lib/twat/argparse.rb
|
54
64
|
- lib/twat/config.rb
|
55
65
|
- lib/twat/endpoint.rb
|
@@ -81,7 +91,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
81
91
|
version: '0'
|
82
92
|
requirements: []
|
83
93
|
rubyforge_project:
|
84
|
-
rubygems_version: 1.8.
|
94
|
+
rubygems_version: 1.8.6
|
85
95
|
signing_key:
|
86
96
|
specification_version: 3
|
87
97
|
summary: Command line tool for tweeting and whatnot
|