class Tw::App::Main

Public Class Methods

new() click to toggle source
# File lib/tw/app/main.rb, line 13
def initialize
  on_exit do
    exit 0
  end

  on_error do
    exit 1
  end
end

Public Instance Methods

all_requests?(args) click to toggle source
# File lib/tw/app/opt_parser.rb, line 16
def all_requests?(args)
  !args.map{|arg| request? arg}.include?(false)
end
client() click to toggle source
# File lib/tw/app/main.rb, line 23
def client
  @client ||= Tw::Client.new
end
listname?(arg) click to toggle source
# File lib/tw/app/opt_parser.rb, line 8
def listname?(arg)
  arg =~ /^@[a-zA-Z0-9_]+\/[a-zA-Z0-9_-]+$/ ? arg.scan(/^@([a-zA-Z0-9_]+)\/([a-zA-Z0-9_-]+)$/)[0] : false
end
on_error(&block) click to toggle source
# File lib/tw/app/main.rb, line 35
def on_error(&block)
  if block_given?
    @on_error = block
  else
    @on_error.call if @on_error
  end
end
on_exit(&block) click to toggle source
# File lib/tw/app/main.rb, line 27
def on_exit(&block)
  if block_given?
    @on_exit = block
  else
    @on_exit.call if @on_exit
  end
end
request?(arg) click to toggle source
# File lib/tw/app/opt_parser.rb, line 12
def request?(arg)
  username?(arg) or listname?(arg)
end
run(argv) click to toggle source
# File lib/tw/app/main.rb, line 43
def run(argv)
  @args = ArgsParser.parse argv, :style => :equal do
    arg :user, 'user account', :alias => :u
    arg 'user:add', 'add user'
    arg 'user:list', 'show user list'
    arg 'user:default', 'set default user'
    arg :timeline, 'show timeline', :alias => :tl
    arg :dm, 'show direct messages'
    arg 'dm:to', 'create direct message'
    arg :favorite, 'favorite tweet', :alias => :fav
    arg :retweet, 'retweet', :alias => :rt
    arg :delete, 'delete tweet', :alias => :del
    arg :search, 'search public timeline', :alias => :s
    arg :stream, 'show user stream', :alias => :st
    arg :status_id, 'show status_id', :alias => :id
    arg :file, 'upload file'
    arg :pipe, 'pipe tweet'
    arg :format, 'output format', :default => 'text'
    arg :silent, 'silent mode'
    arg :yes, 'do not show dialogue'
    arg :conf, 'config file', :default => Tw::Conf.conf_file
    arg :version, 'show version', :alias => :v
    arg :help, 'show help', :alias => :h

    validate :user, 'invalid user name' do |v|
      v =~ /^[a-zA-Z0-9_]+$/
    end

    validate 'user:default', 'invalid user name' do |v|
      v =~ /^[a-zA-Z0-9_]+$/
    end

    validate 'dm:to', 'invalid user name' do |v|
      v =~ /^[a-zA-Z0-9_]+$/
    end

    validate :file, "file does not exists" do |v|
      File.exists? v
    end
  end

  if @args.has_option? :help
    STDERR.puts "Tw - Twitter client on Ruby v#{Tw::VERSION}"
    STDERR.puts "     http://shokai.github.io/tw"
    STDERR.puts
    STDERR.puts @args.help
    STDERR.puts
    STDERR.puts "e.g."
    STDERR.puts "tweet  tw hello world"
    STDERR.puts "       echo 'hello' | tw --pipe"
    STDERR.puts "       tw 'yummy!!' --file=food.jpg --yes"
    STDERR.puts "read   tw @username"
    STDERR.puts "       tw @username @user2 @user2/listname"
    STDERR.puts "       tw --search=ruby"
    STDERR.puts "       tw --stream"
    STDERR.puts "       tw --stream:filter=ruby,java"
    STDERR.puts "       tw --dm:to=username \"hello!\""
    STDERR.puts "id     tw @shokai --id"
    STDERR.puts "       tw --id=334749349588377601"
    STDERR.puts 'reply  tw "@shokai wow!!" --id=334749349588377601'
    STDERR.puts "       tw --fav=334749349588377601"
    STDERR.puts "       tw --rt=334749349588377601"
    STDERR.puts "       tw --format=json"
    STDERR.puts '       tw --format="@#{user} #{text} - https://twitter.com/#{user}/#{id}"'
    STDERR.puts "delete tw --del=334749349588377601"
    on_exit
  end

  Render.silent = (@args.has_option? :silent or @args.has_param? :format)
  Render.show_status_id = @args[:status_id]
  Tw::Conf.conf_file = @args[:conf]

  regist_cmds

  cmds.each do |name, cmd|
    next unless @args[name]
    cmd.call @args[name], @args
  end

  auth
  if @args.argv.size < 1
    if @args.has_param? :status_id
      client.show_status @args[:status_id]
    else
      Render.display client.mentions, @args[:format]
    end
  elsif all_requests?(@args.argv)
    Render.display Parallel.map(@args.argv, :in_threads => @args.argv.size){|arg|
      if user = username?(arg)
        res = client.user_timeline user
      elsif (user, list = listname?(arg)) != false
        res = client.list_timeline(user, list)
      end
      res
    }, @args[:format]
  else
    message = @args.argv.join(' ')
    tweet_opts = {}
    if (len = message.char_length_with_t_co) > 280
      STDERR.puts "tweet too long (#{len} chars)"
      on_error
    else
      if @args.has_param? :status_id
        client.show_status @args[:status_id]
        puts "--"
        puts "reply \"#{message}\"? (#{len} chars)"
        tweet_opts[:in_reply_to_status_id] = @args[:status_id]
      else
        puts "tweet \"#{message}\"?  (#{len} chars)"
        if @args.has_param? :file
          puts "upload \"#{@args[:file]}\"? (#{File.size @args[:file]} bytes)"
        end
      end
      unless @args.has_option? :yes
        puts '[Y/n]'
        on_exit if STDIN.gets.strip =~ /^n/i
      end
    end
    begin
      if @args.has_param? :file
        client.tweet_with_file message, File.open(@args[:file]), tweet_opts
      else
        client.tweet message, tweet_opts
      end
    rescue => e
      STDERR.puts e.message
    end
  end
end
username?(arg) click to toggle source
# File lib/tw/app/opt_parser.rb, line 4
def username?(arg)
  arg =~ /^@[a-zA-Z0-9_]+$/ ? arg.scan(/^@([a-zA-Z0-9_]+)$/)[0][0] : false
end

Private Instance Methods

auth() click to toggle source
# File lib/tw/app/main.rb, line 174
def auth
  return unless @args
  client.auth @args.has_param?(:user) ? @args[:user] : nil
end
cmd(name, &block) click to toggle source
# File lib/tw/app/cmds.rb, line 204
def cmd(name, &block)
  if block_given?
    cmds[name.to_sym] = block
  else
    return cmds[name.to_sym]
  end
end
cmds() click to toggle source
# File lib/tw/app/cmds.rb, line 212
def cmds
  @cmds ||= Hash.new
end
regist_cmds() click to toggle source
# File lib/tw/app/cmds.rb, line 5
def regist_cmds
  cmd :user do |v, opts|
    if v == true
      STDERR.puts 'e.g.  tw "hello" --user=USERNAME'
      on_error
    else
      Render.puts "switch user -> @#{v}"
    end
  end

  cmd 'user:add' do |v, opts|
    Tw::Auth.regist_user
    on_exit
  end

  cmd 'user:list' do |v, opts|
    Tw::Conf['users'].keys.each do |name|
      puts name == Tw::Conf['default_user'] ? "* #{name}" : "  #{name}"
    end
    puts "(#{Tw::Conf['users'].size} users)"
    on_exit
  end

  cmd 'user:default' do |v, opts|
    if v.class == String
      Tw::Conf['default_user'] = v
      Tw::Conf.save
      puts "set default user \"@#{Tw::Conf['default_user']}\""
    else
      puts "@"+Tw::Conf['default_user'] if Tw::Conf['default_user']
      STDERR.puts "e.g.  tw --user:default=USERNAME"
    end
    on_exit
  end

  cmd :timeline do |v, opts|
    unless v.class == String
      auth
      Render.display client.home_timeline, opts[:format]
      on_exit
    end
  end

  cmd :dm do |v, opts|
    auth
    Render.display client.direct_messages, opts[:format]
    on_exit
  end

  cmd 'dm:to' do |to, opts|
    unless opts[:pipe]
      message = opts.argv.join(' ')
      len = message.char_length_with_t_co
      if len > 140
        STDERR.puts "message too long (#{len} chars)"
        on_error
      elsif len < 1
        STDERR.puts 'e.g.  tw --dm:to=USERNAME  "hello"'
        on_error
      else
        puts "DM to @#{to}"
        puts "\"#{message}\"?  (#{len} chars)"
        unless opts.has_option? :yes
          puts '[Y/n]'
          on_exit if STDIN.gets.strip =~ /^n/i
        end
        auth
        client.direct_message_create to, message
      end
      on_exit
    end
  end

  cmd :favorite do |v, opts|
    if opts.has_param? :favorite
      id = opts[:favorite]
      auth
      client.show_status id
      puts 'Fav this?'
      unless opts.has_option? :yes
        puts '[Y/n]'
        on_exit if STDIN.gets.strip =~ /^n/i
      end
      puts "success!" if client.favorite id
    end
    on_exit
  end

  cmd :retweet do |v, opts|
    if opts.has_param? :retweet
      id = opts[:retweet]
      auth
      client.show_status id
      puts 'RT this?'
      unless opts.has_option? :yes
        puts '[Y/n]'
        on_exit if STDIN.gets.strip =~ /^n/i
      end
      puts "success!" if client.retweet id
    end
    on_exit
  end

  cmd :delete do |v, opts|
    if opts.has_param? :delete
      id = opts[:delete]
      auth
      client.show_status id
      puts 'Delete this?'
      unless opts.has_option? :yes
        puts '[Y/n]'
        on_exit if STDIN.gets.strip =~ /^n/i
      end
      puts "success!" if client.destroy_status id
    end
    on_exit
  end

  cmd :pipe do |v, opts|
    auth
    lines = STDIN.readlines.join
    lines.split(/(.{140})/u).select{|m|m.size>0}.each do |message|
      begin
        if opts.has_param? 'dm:to'
          puts to = opts['dm:to']
          client.direct_message_create to, message
        else
          tweet_opts = {}
          tweet_opts[:in_reply_to_status_id] = opts[:status_id] if opts.has_param? :status_id
          client.tweet message, tweet_opts
        end
      rescue => e
        STDERR.puts e.message
      end
    end
    on_exit
  end

  cmd :search do |v, opts|
    if v.class == String
      auth
      Render.display client.search(v), opts[:format]
      on_exit
    else
      STDERR.puts "e.g.  tw --search=ruby"
      on_error
    end
  end

  cmd :stream do |v, opts|
    stream = Tw::Client::Stream.new opts.has_param?(:user) ? opts[:user] : nil
    Render.puts "-- waiting stream.."
    loop do
      begin
        stream.user_stream do |s|
          Render.display s, opts[:format]
        end
      rescue Timeout::Error, SocketError => e
        sleep 5
        next
      rescue => e
        STDERR.puts e
        on_error
      end
    end
    on_exit
  end

  cmd 'stream:filter' do |v, opts|
    unless v.class == String
      STDERR.puts "e.g.  tw --stream:filter=ruby,java"
      on_error
    else
      track_words = v.split(/\s*,\s*/)
      stream = Tw::Client::Stream.new opts.has_param?(:user) ? opts[:user] : nil
      Render.puts "-- waiting stream..  track \"#{track_words.join(',')}\""
      loop do
        begin
          stream.filter track_words do |s|
            Render.display s, opts[:format]
          end
        rescue Timeout::Error, SocketError => e
          sleep 5
          next
        rescue => e
          STDERR.puts e
          on_error
        end
      end
      on_exit
    end
  end

  cmd :version do |v, opts|
    puts "tw version #{Tw::VERSION}"
    on_exit
  end
end