Skip to content

Instantly share code, notes, and snippets.

@takkkun
Created December 11, 2009 19:50
Show Gist options
  • Save takkkun/254459 to your computer and use it in GitHub Desktop.
Save takkkun/254459 to your computer and use it in GitHub Desktop.
require 'optparse'
require 'stringio'
require 'rubygems'
require 'twitter'
module Twsh
class Logout < StandardError; end
class TwshError < StandardError; end
class Shell
class << self
def login(argv, env)
new argv, env
end
end
def initialize(argv, env)
username = nil
password = nil
OptionParser.new do |opt|
opt.on('-u VAL') {|v| username = v}
opt.on('-p VAL') {|v| password = v}
opt.parse! argv
end
fail if username.nil? || password.nil?
@client = Twitter::Base.new Twitter::HTTPAuth.new username, password
input = Input.new self
logged_in = true
while logged_in
begin
output = execute input.read
puts output if output
rescue Logout
logged_in = false
rescue Interrupt
puts
logged_in = false
rescue TwshError => e
puts e.message
end
end
end
attr_reader :client
def execute(argv)
return if argv.empty?
command = argv.shift
Command.new(self).execute command, argv
end
end
class Command
@@commands = {}
class << self
def setup
fail unless block_given?
yield new
end
end
def initialize(twsh = nil)
@twsh = twsh
end
def on(*commands, &process)
fail unless block_given?
commands.each {|command| @@commands[command] = process}
end
def execute(command, argv)
process = @@commands[command]
if process
args = []
args << @twsh if process.arity >= 1
args << argv if process.arity >= 2
output = nil
StringIO.open '', 'w' do |io|
orig = $stdout
$stdout = io
process.call *args
$stdout = orig
output = io.string unless io.string.empty?
end
output
else
`#{command} #{argv.join ' '}`.chomp
end
end
end
class Input
def initialize(twsh)
@twsh = twsh
end
def read
read_with_context
end
private
def read_with_context(context = nil, argv = [])
print context ? "#{context}> " : argv.empty? ? 'twsh% ' : '> '
context, argv, continue = parse gets, context, argv
continue ? read_with_context(context, argv) : argv
end
def parse(input, context = nil, argv = [])
escape = false
continue = false
v = !argv.empty? ? argv.pop : ''
new = lambda do
argv << v unless v.empty?
v = ''
end
input.each_byte do |c|
if escape
escape = false
case c
when LINE_FEED
continue = true
v << c if context
when ?n
v << "\n" if quoted? context
when ?t
v << "\t" if quoted? context
when ?f
v << "\f" if quoted? context
when ?v
v << "\v" if quoted? context
else
v << c
end
else
case c
when ?\n
v << c if context
when ?\s
if context
v << c
else
new.call
end
when ?'
if context == :quote
new.call
context = nil
elsif context
v << c
else
context = :quote
end
when ?"
if context == :dquote
new.call
context = nil
elsif context
v << c
else
context = :dquote
end
when ?`
if context == :bquote
v = @twsh.execute(parse(v)[1])
context = nil
elsif context
v << c
else
context = :bquote
end
when ?\\
escape = true
else
v << c
end
end
end
new.call
[context, argv, continue || !context.nil?]
end
def quoted?(context)
context == :quote || context == :dquote
end
end
end
Twsh::Command.setup do |c|
c.on('exit', 'quit', 'logout') { fail Twsh::Logout }
c.on 'echo' do |twsh, argv|
twsh.client.update argv.join ' '
nil
end
c.on 'head' do |twsh, argv|
n = 5
OptionParser.new do |opt|
opt.on('-n VAL', Integer) {|v| n = v}
opt.parse! argv
end
screen_name = argv.shift
iterator = lambda {|status| puts "#{status.user.screen_name}: #{status.text}"}
if screen_name
twsh.client.user_timeline(:screen_name => screen_name, :count => n).each &iterator
else
twsh.client.home_timeline(:count => n).each &iterator
end
nil
end
end
Twsh::Shell.login ARGV, ENV
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment