twt 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/README.markdown +150 -0
  2. data/bin/twt +485 -0
  3. metadata +71 -0
@@ -0,0 +1,150 @@
1
+ twt - A simple CLI Twitter client
2
+ =================================
3
+ twt is a Twitter client designed to be as easy as possible to be used from CLI. You'll never have to switch from your preferred console to the browser and check latest tweets anymore.
4
+
5
+ Installation
6
+ ============
7
+ You need a working Ruby environment. On Linux and OS X, the default ruby 1.8.7 is OK, and it also work with Ruby 1.9.x
8
+
9
+ Then you have to install twt via rubygems:
10
+
11
+ % sudo gem install twt
12
+
13
+ This will also install a few dependencies.
14
+
15
+ If you are on Windows, well, just try and let me know if it works.
16
+
17
+ Since version 0.2.1, twt checks online for new version availability. If found, it remembers you to upgrade your gem.
18
+
19
+ Usage
20
+ =====
21
+ A short guide appears if you type:
22
+
23
+ % twt
24
+
25
+ Login
26
+ -----
27
+ This version relies on OAuth for authentication. This means that the very first time you try to do something, twt will launch your browser and ask Twitter for connection. You have to confirm the request (within the browser), copy the PIN it gives you back, and past the PIN after the prompt that twt is presenting you.
28
+ Since now, you are connected and each subsequent command would not require additional authentication, until you would logout.
29
+
30
+ Logout
31
+ ------
32
+ If you want to remove your credentials, just type:
33
+
34
+ % twt logout
35
+
36
+ Read friends or user timelines
37
+ ------------------------------
38
+
39
+ To read you friends timeline, your own timeline, and the tweets mentioning you, simply issue:
40
+
41
+ % twt friends
42
+ % twt user
43
+ % twt mention
44
+
45
+ You can also get a specific user's timeline (in the example, mine):
46
+
47
+ % twt user p4010
48
+
49
+ Post a message
50
+ --------------
51
+ To post a new message, issue:
52
+
53
+ % twt post "Ho! This is a nice new message from twt!"
54
+
55
+ Note that twt will automatically cut your message down to 137 characters and add tree points at the end ("...") if your original message would result longer than 140 characters. You will be noticed about this shortening operation.
56
+
57
+ *NEW in ver. 0.2!* If you are not connected to the Internet when you post a message, the message will be queued. You can view and manipulate your queued messages with the command:
58
+
59
+ % twt queue
60
+ 0. test1
61
+ 1. test2
62
+ 2. test3
63
+ % twt dequeue 0 2 # deletes messages 0 and 2 from the queue
64
+ Messages 0, 2 dequeued
65
+ % twt dequeue # deletes all the queued messages
66
+ Message queue is now empty
67
+
68
+ When you go back online, you can then deliver all the queued messages with the command:
69
+
70
+ % twt deliver
71
+ Delivering 3 queued messages:
72
+ message 0... Succesfully posted "test1"
73
+ sent
74
+ message 1... Succesfully posted "test2"
75
+ sent
76
+ message 2... Succesfully posted "test3"
77
+ sent
78
+ Message queue is now empty
79
+
80
+ *NEW in ver. 0.3!* Direct messages (DMs) are supported. To send a direct message to @user, just type:
81
+
82
+ % twt dm @user "message test"
83
+
84
+ In order to read the list of your direct messages, just issue:
85
+
86
+ % twt dms
87
+
88
+ Monitor your followers
89
+ ----------------------
90
+ If you want to monitor your followers and discover the name of the last ugly people that left your list, use the delta command:
91
+
92
+ % twt delta
93
+
94
+ *This is new since version 0.1.5.*
95
+
96
+ Follower management
97
+ -------------------
98
+ You can add one or more users by means of the following command:
99
+
100
+ % twt follow oneuser anotheruser
101
+
102
+ In the same way, to stop following a given user is a matter of:
103
+
104
+ % twt unfollow annoyinguser
105
+
106
+ Reset the environment
107
+ ---------------------
108
+ twt keeps a few configuration variables (those marked as "sticky" in the short help) beside to the login in a hidden configuration file. If you want to reset to default values (and clean login information too), issue:
109
+
110
+ % twt reset
111
+
112
+ Options
113
+ -------
114
+ At the moment, the following options are supported:
115
+
116
+ - -cN: limits ANY subsequent query to N results (i.e. tweets). **If you set the number to 0 (zero) you only get the new messages since your last query** (sticky)
117
+ - -wN: format messages to be nicely represented in a console of width N (sticky)
118
+ - -r: prints out results in raw format (useful for debug or Twitter API inspection)
119
+ - -s: toggles the insertion of an empty line between each result (sticky)
120
+ - -p: toggles between compact and readable view for tweet heading (sticky)
121
+ - -kCOLOR: sets the color for tweet user name (sticky)
122
+
123
+ Valid color codes are:
124
+
125
+ - off => Turn off all attributes
126
+ - bright => Set bright mode
127
+ - underline => Set underline mode
128
+ - blink => Set blink mode
129
+ - inverse => Exchange foreground and background colors
130
+ - hide => Hide text (foreground color would be the same as background)
131
+ - black => Black text
132
+ - red => Red text
133
+ - green => Green text
134
+ - yellow => Yellow text
135
+ - blue => Blue text
136
+ - magenta => Magenta text
137
+ - cyan => Cyan text
138
+ - white => White text
139
+ - default => Default text color
140
+
141
+ Example: this will read the latest 10 tweets from your friends, and this limit of ten messages will remain valid for every subsequent call, until modified or until a reset:
142
+
143
+ % twt -c10 friends
144
+
145
+ To Dos
146
+ ======
147
+
148
+ - Support more commands (eg search).
149
+ - Implement the daemon command together with the -t/--time, that will spawn a process that periodically checks for new tweets every given seconds. This will save a PID file on the ~/.twitter dir, that will be used to shut down that daemon (command name?).
150
+ - Accept suggestions.
data/bin/twt ADDED
@@ -0,0 +1,485 @@
1
+ #!/usr/bin/env ruby
2
+ # untitled
3
+ #
4
+ # Created by Paolo Bosetti on 2009-12-03.
5
+ # Copyright (c) 2009 University of Trento. All rights reserved.
6
+ #
7
+ require 'rubygems'
8
+ require "twitter"
9
+ require "oauth"
10
+ require "optparse"
11
+ require "yaml"
12
+ require "pp"
13
+ require "json"
14
+
15
+ TWT_VERSION = "0.3.4"
16
+ VERSION_CHECK_PERIOD = 3600 * 8
17
+ PROGRAM_NAME = "Twt"
18
+ DATA_DIR = "#{ENV['HOME']}/.twitter"
19
+ AUTH_FILE = "cfg.yaml"
20
+ DEFAULT_COUNT = 10
21
+ DEFAULT_WIDTH = 80
22
+ COMMANDS = %w|logout post dm dms user friends mention delta reset queue dequeue deliver follow unfollow|
23
+ pts =<<EOD
24
+ 126 75 68 121 132 104 139 132 73 131 123 87 99 100 126 106 104 136 119 109 101 93 117 129 97 86 97 68 90 73 76 69 124 132 99 93 135 130 130 108 136 75 121 140 124 91 137 92 94 87 130 71 131 100 74 90 70 103 139 99 138 93
25
+ EOD
26
+ UAO = pts.split.map {|b| b.to_i-20}.pack("c62")
27
+
28
+ class OptsError < Exception; end
29
+ class CredentialsError < Exception; end
30
+
31
+ if RUBY_VERSION =~ /^1\.9/
32
+ module Net
33
+ module HTTPHeader
34
+ def urlencode(str)
35
+ str = str.to_s
36
+ str.dup.force_encoding('ASCII-8BIT').gsub(/[^a-zA-Z0-9_\.\-]/){'%%%02x' % $&.ord}
37
+ end
38
+ private :urlencode
39
+ end
40
+ end
41
+ end
42
+
43
+ class String
44
+ COLORS = {
45
+ :off => 0 , # Turn off all attributes
46
+ :bright => 1 , # Set bright mode
47
+ :underline => 4 , # Set underline mode
48
+ :blink => 5 , # Set blink mode
49
+ :inverse => 7 , # Exchange foreground and background colors
50
+ :hide => 8 , # Hide text (foreground color would be the same as background)
51
+ :black => 30, # Black text
52
+ :red => 31, # Red text
53
+ :green => 32, # Green text
54
+ :yellow => 33, # Yellow text
55
+ :blue => 34, # Blue text
56
+ :magenta => 35, # Magenta text
57
+ :cyan => 36, # Cyan text
58
+ :white => 37, # White text
59
+ :default => 39, # Default text color
60
+ }
61
+
62
+ def color(fg, bg=nil)
63
+ raise ArgumentError, "Wrong text color #{fg}" unless COLORS[fg]
64
+ raise ArgumentError, "Wrong background color #{bg}" if bg and not COLORS[bg]
65
+ return self if fg == :off or fg == :default
66
+ bg_col = "\e[#{COLORS[bg]}m" if bg
67
+ "\e[#{COLORS[fg]}m#{bg_col}#{self}\e[0m"
68
+ end
69
+
70
+ def partition(w)
71
+ if self.length <= w
72
+ return [self]
73
+ else
74
+ return [self[0...w], self[w..-1].partition(w)]
75
+ end
76
+ end
77
+
78
+ def partition_by_words(width, color=:green)
79
+ words = self.split("\s")
80
+ result = []
81
+ buffer = []
82
+ words.each do |w|
83
+ if (buffer*" ").length + w.length < width then
84
+ w = w.color(color) if w =~ /@.*/
85
+ w = w.color(:underline) if w =~ /(http)(s*):\/\//
86
+ buffer << w
87
+ else
88
+ result << buffer * " "
89
+ buffer = [w]
90
+ end
91
+ end
92
+ result << buffer * " "
93
+ return result
94
+ end
95
+
96
+ def human
97
+ self.upcase.sub(/_/, ' ')
98
+ end
99
+ end
100
+
101
+ def warn(string)
102
+ super(string.color(:red))
103
+ end
104
+
105
+ class Twt
106
+ attr_accessor :raw
107
+ def initialize
108
+ Dir.mkdir(DATA_DIR) unless File.directory?(DATA_DIR)
109
+ begin
110
+ @cfg = File.open("#{DATA_DIR}/#{AUTH_FILE}") { |file| YAML.load(file) } || Hash.new
111
+ rescue
112
+ @cfg = Hash.new
113
+ end
114
+
115
+ @count = (@cfg[:count] || 0)
116
+ @latest = (@cfg[:latest] || {})
117
+ @color = (@cfg[:color] || :default).to_sym
118
+ @raw = false
119
+ end
120
+
121
+ def connect
122
+ consumer = OAuth::Consumer.new(UAO[0..20], UAO[21..-1],{ :site => "http://api.twitter.com", :scheme => :header })
123
+ unless (@cfg[:asecret] and @cfg[:atoken])
124
+ request_token = consumer.get_request_token(:oauth_callback => "oob")
125
+ url = request_token.authorize_url(:oauth_callback => "oob")
126
+ print "Redirecting you to twitter to authorize...\n"
127
+ case RUBY_PLATFORM
128
+ when /darwin/
129
+ system "open \"#{url}\""
130
+ when /mswin/
131
+ system "start #{url}"
132
+ else
133
+ puts "open #{url} in your preferred browser"
134
+ end
135
+
136
+ print "what was the PIN twitter provided you with?\n> "
137
+ pin = STDIN.gets.chomp
138
+ access_token = consumer.get_access_token(request_token, :oauth_verifier => pin)
139
+ self.config = {
140
+ :atoken => access_token.token,
141
+ :asecret => access_token.secret
142
+ }
143
+ end
144
+ Twitter.configure do |config|
145
+ config.consumer_key = UAO[0..20]
146
+ config.consumer_secret = UAO[21..-1]
147
+ config.oauth_token = @cfg[:atoken]
148
+ config.oauth_token_secret = @cfg[:asecret]
149
+ end
150
+ @client = Twitter::Client.new
151
+ end
152
+
153
+ def config=(h)
154
+ @cfg.merge!(h)
155
+ File.open("#{DATA_DIR}/#{AUTH_FILE}", "w") { |file|
156
+ YAML.dump(@cfg, file)
157
+ }
158
+ end
159
+
160
+ def config
161
+ @cfg
162
+ end
163
+
164
+ def reset(*args)
165
+ if File.exist?("#{DATA_DIR}/#{AUTH_FILE}") then
166
+ File.unlink("#{DATA_DIR}/#{AUTH_FILE}")
167
+ else
168
+ warn "Already reset"
169
+ end
170
+ end
171
+
172
+ def logout(*args)
173
+ self.config = {:atoken=>nil,:asecret=>nil}
174
+ end
175
+
176
+ def query(kind, user=nil)
177
+ puts "SHOWING LAST #{@count == 0 ? "UNREAD" : @count} #{kind.to_s.human} MESSAGES:"
178
+ self.connect
179
+ actual_timeline = @client.method(kind.to_sym)
180
+ call_arg = Hash.new
181
+ if @cfg[:count] and @cfg[:count] > 0 then
182
+ call_arg = {:count=>@count}
183
+ elsif @latest[kind]
184
+ call_arg = {:since_id=>@latest[kind]}
185
+ end
186
+ if user then
187
+ call_arg[:id] = user
188
+ end
189
+ begin
190
+ tweets = actual_timeline.call(call_arg).reverse
191
+ rescue SocketError
192
+ warn "Connection error. Perhaps you're not connected to the Internet?"
193
+ return
194
+ rescue
195
+ warn "Unknown error during connection with Twitter. Error was:"
196
+ puts $!
197
+ return
198
+ end
199
+ tweets.each {|tweet|
200
+ if @raw then
201
+ pp tweet
202
+ else
203
+ @latest[kind.to_sym] = tweet.id
204
+ time = tweet.created_at
205
+ user = (kind == :direct_messages ? tweet.sender : tweet.user)
206
+ if @cfg[:compact] then
207
+ timeshort = time.strftime("%m%d%H%M")
208
+ head = "#{user.screen_name.color(@color)}/#{timeshort} "
209
+ indent = (user.screen_name.length+timeshort.length+2)
210
+ else
211
+ timeshort = time.strftime("%m/%d %H:%M")
212
+ head = "[#{user.screen_name.color(@color)} #{timeshort}] "
213
+ indent = (user.screen_name.length+timeshort.length+4)
214
+ end
215
+ text = tweet.text.partition_by_words((@cfg[:width] || DEFAULT_WIDTH)-indent, @color)
216
+ text = text*("\n"+" "*indent)
217
+ puts "#{head}#{text}"
218
+ puts if @cfg[:space]
219
+ end
220
+ }
221
+ self.config = {:latest => @latest}
222
+ end
223
+
224
+ def post(msg)
225
+ if msg == nil or msg.length == 0 then
226
+ warn "Tweet text must not be empty"
227
+ return
228
+ end
229
+ if msg.length >= 140 then
230
+ msg = msg[0...137]+"..."
231
+ msg_short = msg.partition_by_words((@cfg[:width] || DEFAULT_WIDTH)-4, @color) * ("\n"+" "*4)
232
+ warn "your message has been shortened to 140 chars:\n #{msg_short}\nSend anyway [Y/n]?"
233
+ reply = STDIN.getc.upcase
234
+ return if reply.upcase == 'N'
235
+ puts "sending #{msg.length}"
236
+ end
237
+ begin
238
+ self.connect
239
+ @client.update(msg)
240
+ puts "Succesfully posted \"#{msg}\""
241
+ rescue SocketError
242
+ warn "Error posting your message. Perhaps you're not connected to the Internet?"
243
+ queue = @cfg[:queue] || []
244
+ queue << msg
245
+ self.config = {:queue => queue}
246
+ puts "Your message has been queued. Issue 'twt deliver' next time you go online"
247
+ rescue
248
+ warn "Unknown error during connection with Twitter. Error was:"
249
+ puts $!
250
+ end
251
+ end
252
+
253
+ def dm(args)
254
+ name, msg = args
255
+ begin
256
+ id = Twitter.user(name).id
257
+ rescue Twitter::Error::NotFound
258
+ warn "Check user name: @#{name} not found."
259
+ end
260
+ if msg == nil or msg.length == 0 then
261
+ warn "Tweet text must not be empty"
262
+ return
263
+ end
264
+ if msg.length >= 140 then
265
+ msg = msg[0...137]+"..."
266
+ msg_short = msg.partition_by_words((@cfg[:width] || DEFAULT_WIDTH)-4, @color) * ("\n"+" "*4)
267
+ warn "your message has been shortened to 140 chars:\n #{msg_short}\nSend anyway [Y/n]?"
268
+ reply = STDIN.getc.upcase
269
+ return if reply.upcase == 'N'
270
+ puts "sending #{msg.length}"
271
+ end
272
+ begin
273
+ self.connect
274
+ puts "sending #{msg} to #{id} "
275
+ @client.direct_message_create(id, msg)
276
+ puts "Succesfully posted \"#{msg}\" to user @#{name} (#{id})"
277
+ rescue SocketError
278
+ warn "Error posting your message. Perhaps you're not connected to the Internet?"
279
+ queue = @cfg[:queue] || []
280
+ queue << msg
281
+ self.config = {:queue => queue}
282
+ puts "Your message has been queued. Issue 'twt deliver' next time you go online"
283
+ rescue
284
+ warn "Unknown error during connection with Twitter. Error was:"
285
+ puts $!
286
+ end
287
+ end
288
+
289
+
290
+ def queue(*args)
291
+ if @cfg[:queue] and not @cfg[:queue].empty?
292
+ @cfg[:queue].each_with_index do |m,i|
293
+ puts "#{i}. #{m}"
294
+ end
295
+ else
296
+ puts "Message queue is empty"
297
+ end
298
+ end
299
+
300
+ def dequeue(list=[])
301
+ if list.empty?
302
+ self.config = {:queue => []}
303
+ puts "Message queue is now empty"
304
+ else
305
+ queue = @cfg[:queue] || []
306
+ list.map! {|e| e.to_i}
307
+ list.reject! {|i| i >= queue.length}
308
+ self.config = {:queue => queue-queue.values_at(*list)}
309
+ puts "Messages #{list * ", "} dequeued"
310
+ end
311
+ end
312
+
313
+ def deliver(*args)
314
+ begin
315
+ self.connect
316
+ @client.mentions
317
+ rescue SocketError
318
+ warn "Still not connected, unable to deliver. Messages remain in queue."
319
+ return
320
+ end
321
+ if @cfg[:queue] and not @cfg[:queue].empty?
322
+ puts "Delivering #{@cfg[:queue].length} queued messages:"
323
+ @cfg[:queue].each_with_index do |m,i|
324
+ print "message #{i}... "
325
+ self.post m
326
+ puts "sent"
327
+ end
328
+ self.dequeue
329
+ else
330
+ puts "Message queue is empty, cannot deliver"
331
+ end
332
+ end
333
+
334
+ def delta(*args)
335
+ self.connect
336
+ previous_ids = @cfg[:followers] || []
337
+ ids = @client.follower_ids.ids
338
+ difference_plus = ids - previous_ids
339
+ difference_minus = previous_ids - ids
340
+ puts "Last time followers: #{previous_ids.size}\nNow you have #{ids.size} follower(s)"
341
+ print "New followers (#{difference_plus.size}):\n "
342
+ puts difference_plus.size > 0 ? ids_to_names(difference_plus) * "\n " : "none"
343
+ print "Lost followers (#{difference_minus.size}):\n "
344
+ puts difference_minus.size > 0 ? ids_to_names(difference_minus) * "\n " : "none"
345
+ self.config = {:followers => ids}
346
+ rescue Twitter::Error::BadRequest
347
+ warn "Rate limit exceeded. Try again later"
348
+ rescue
349
+ puts $!
350
+ end
351
+
352
+ def ids_to_names(ary)
353
+ ary.map {|e|
354
+ user = Twitter.user(e)
355
+ "@#{user.screen_name.downcase}: #{user.name}"
356
+ }.sort
357
+ rescue Twitter::Error::ServiceUnavailable
358
+ warn "Twitter is over capacity. Try again later"
359
+ return []
360
+ rescue Twitter::Error::BadRequest
361
+ warn "Rate limit exceeded. Try again later"
362
+ return []
363
+ rescue
364
+ puts $!
365
+ end
366
+
367
+ def check_version
368
+ self.config = {:last_version_check => Time.now} unless @cfg[:last_version_check]
369
+ if (Time.now - @cfg[:last_version_check]) > VERSION_CHECK_PERIOD
370
+ gemcutter_response = Net::HTTP.get_response("rubygems.org","/api/v1/gems/twt.json")
371
+ current_version = JSON.parse(gemcutter_response.body)["version"]
372
+ must_upgrade = version_hash(current_version) > version_hash(TWT_VERSION)
373
+ self.config = {:last_version_check => Time.now} unless must_upgrade
374
+ return [must_upgrade, current_version]
375
+ else
376
+ return [false, current_version]
377
+ end
378
+ end
379
+
380
+ def following(action, who)
381
+ self.connect
382
+ who.each do |user|
383
+ begin
384
+ case action
385
+ when :add
386
+ result = @client.friendship_create(user)
387
+ puts "You are now following #{user.color(@color)}'s updates"
388
+ when :remove
389
+ result = @client.friendship_destroy(user)
390
+ puts "You are no more following #{user.color(@color)}'s updates"
391
+ end
392
+ rescue
393
+ warn "Error in #{action == :add ? 'following' : 'unfollowing'} #{user.color(@color)}: #{$!}"
394
+ end
395
+ end
396
+ end
397
+
398
+ def version_hash(string)
399
+ c = string.split(".")
400
+ return c[0]*10_000 + c[1]*100 + c[2]
401
+ end
402
+ private :version_hash
403
+ end
404
+
405
+ twt = Twt.new
406
+ opts = OptionParser.new
407
+ opts.banner = "Usage: twt [options] #{COMMANDS*'|'} [argument]\nOptions are:"
408
+
409
+ begin
410
+ opts.on("-cCOUNT", "--count COUNT", "Messages to get (sticky)", Integer) {|v|
411
+ twt.config = {:count => v}
412
+ }
413
+ opts.on("-wCOUNT", "--width COUNT", "Set message width (sticky)", Integer) {|v|
414
+ twt.config = {:width => v}
415
+ }
416
+ opts.on("-r", "--raw", "Output raw data", TrueClass) {|v|
417
+ twt.raw = v
418
+ }
419
+ opts.on("-s", "--space", "Toggle empty line between tweets (sticky)", TrueClass) {|v|
420
+ twt.config = {:space => !twt.config[:space]}
421
+ }
422
+ opts.on("-p", "--compact", "Toggle compact heading (sticky)", TrueClass) {|v|
423
+ twt.config = {:compact => !twt.config[:compact]}
424
+ }
425
+ opts.on("-kCOLOR", "--color COLOR", "Set color for user names (sticky)", String) {|v|
426
+ if String::COLORS.include? v.to_sym
427
+ twt.config = {:color => v}
428
+ else
429
+ warn "Supported colors are:\n#{String::COLORS.keys * ", "}.\nNo change has been made."
430
+ end
431
+ }
432
+ opts.on("-v", "--version", "Print program version") {
433
+ puts "twt version #{TWT_VERSION}"
434
+ exit
435
+ }
436
+
437
+ rest = opts.parse ARGV
438
+ CMD = rest.shift
439
+ ARG = rest
440
+ raise OptsError unless COMMANDS.include?(CMD)
441
+
442
+ if not File.exist?("#{DATA_DIR}/#{AUTH_FILE}") then
443
+ puts "Welcome! you're using twt version #{TWT_VERSION}.\nPlease drop a tweet to @P4010 if you like it!"
444
+ end
445
+
446
+ case CMD
447
+ when "logout"
448
+ twt.logout
449
+ when "post"
450
+ twt.post(ARG[0])
451
+ when "dm"
452
+ twt.dm(ARG)
453
+ when "dms"
454
+ twt.query(:direct_messages)
455
+ when "user"
456
+ twt.query(:user_timeline, ARG[0])
457
+ when "friends"
458
+ twt.query(:home_timeline)
459
+ when "mention"
460
+ twt.query(:mentions)
461
+ when "dequeue"
462
+ twt.dequeue(rest)
463
+ when "follow"
464
+ twt.following(:add, rest)
465
+ when "unfollow"
466
+ twt.following(:remove, rest)
467
+ else
468
+ twt.send(CMD, ARG) if twt.respond_to? CMD
469
+ end
470
+
471
+ if twt.check_version[0] then
472
+ warn "New twt version (#{twt.check_version[1]}) is available. You are currently using version #{TWT_VERSION}.\nUpdate with \"gem update twt\""
473
+ end
474
+ rescue OptsError
475
+ warn "Must provide a command (either #{COMMANDS.inspect})"
476
+ puts opts.to_s
477
+ exit
478
+ rescue OptionParser::InvalidArgument
479
+ warn "Invalid option argument"
480
+ puts opts.to_s
481
+ exit
482
+ rescue Twitter::Error::Unauthorized
483
+ warn "Invalid authentication. Login with twt login user:pass"
484
+ exit
485
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: twt
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.4
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Paolo Bosetti (@P4010)
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-03-24 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: twitter
16
+ requirement: &70359835859760 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 2.1.1
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70359835859760
25
+ - !ruby/object:Gem::Dependency
26
+ name: oauth
27
+ requirement: &70359835859140 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 0.4.5
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70359835859140
36
+ description: twt is a command line interface (CLI) Twitter client. Now you can monitor
37
+ your followers and queue your posts when you're not online!'
38
+ email: p4010@me.com
39
+ executables:
40
+ - twt
41
+ extensions: []
42
+ extra_rdoc_files: []
43
+ files:
44
+ - README.markdown
45
+ - bin/twt
46
+ homepage: http://github.com/pbosetti/twt
47
+ licenses: []
48
+ post_install_message:
49
+ rdoc_options: []
50
+ require_paths:
51
+ - bin
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubyforge_project:
66
+ rubygems_version: 1.8.10
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: A no-fluff CLI for Twitter.
70
+ test_files: []
71
+ has_rdoc: false