The main idea behind this quiz was to show how easy it is to get an
irc bot up and running in ruby, especially given the number of bot
frameworks out there. I chose to base my bot on rif
[http://gitorious.org/ruby-irc], a nice lightweight library with
everything I needed to get started immediately.

The code consists of a Teams class, which does all the actual work of
maintaining teams, and a TeamBot, which inherits from RIF::Bot and
handles the IRC part of it. For the sake of simplicity, the bot
frontend does no real validation; it just unpacks an incoming message
into a command and arguments, and blindly sends those arguments to the
Teams  object. All public methods on the Teams object accept a player
name as a first argument, whether they need it or not, and return
either a string or an array of strings, or raise an exception. The bot
sends the return value to the channel; an array is sent one message at
a time.

-------------------------------------------------------------------------------------

gem 'rif'
require 'rif/bot'

class TeambotError < Exception
end

def TeambotError(foo)
  TeambotError.new(foo)
end

class Teams
  attr_accessor :teams, :members

  def initialize
    @teams = {}
    @members = {}
  end

  def create(player, team)
    raise TeambotError("team #{team} already created") if teams[team]
    teams[team] = true
    "created team #{team}"
  end

  def delete(player, team)
    teams.delete(team)
    members.delete_if {|k,v| v == team}
    "deleted team #{team}"
  end

  def join(player, team)
    raise TeambotError("no such team: #{team}") if not teams[team]
    members[player] = team
    "#{player} has joined team #{team}"
  end

  def leave(player, *args)
    team = members.delete(player)
    "#{player} has left team #{team}"
  end

  def reset(*args)
    @members = {}
    @teams = {}
    "deleted all teams"
  end

  def show(player, *args)
    if args[0] == 'my'
      members[player]
    elsif args[0] == 'teams'
      teams.map {|team, _| "#{team}: #{show_players(team)}"}
    elsif args[0] == 'team'
      show_players(team)
    end
  end

  private
  def players(team)
    members.select {|k,v| v == team}.keys
  end

  def show_players(team)
    players(team).join(" ")
  end
end

class TeamBot < RIF::Bot
  attr_reader :teams, :channel
  def initialize(channel, nick, server, port, username)
    @teams = Teams.new
    @channel = channel
    super(nick, server, port, username)
  end

  def on_endofmotd(event)
    join(channel)
  end

  def on_message(event)
    return unless event.channel == channel
    msg, *args = event.message.split(" ")
    player = event.nick
    begin
      *ret = teams.send(msg, player, *args)
    rescue NameError
      ret = nil
    rescue TeambotError => e
      ret = [e.message]
    end
    ret.each {|m| send_message(channel, m)} if ret
  end
end

if __FILE__ == $0
  channel = "##{ARGV[0]}"
  bot = TeamBot.new(channel, "teambot", "irc.freenode.net", 6667, "RIF Bot")
  bot.connect
end

martin