Created
December 11, 2009 19:50
-
-
Save takkkun/254459 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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