Tutorial: Your first bot

dominicsayers edited this page Jul 6, 2011 · 7 revisions

Making your own leaf using Autumn is easy. In this tutorial, I’ll show you how to make a simple Fortune bot that responds to a few basic commands.

Step 1: Subclass Leaf

Create a new leaf by typing script/generate leaf fortune. This will create a
fortune directory in the leaves directory, along with the bare
bones of files needed within that directory. Edit the controller.rb
file. First we’ll create an array to hold our fortunes:


FORTUNES = [
  "You will make someone happy today.",
  "Someone you don't expect will be important to you today.",
  "Today will bring unexpected hardships."
]

As you can see, our 3 meager fortunes are stored in the FORTUNES class
constant. Now, we’ll want it to respond to the “!fortune” command, and all you
have to do is create a method called fortune_command to make it work:


def fortune_command(stem, sender, reply_to, msg)
  FORTUNES.pick
end

The pick method is provided by Facets, so you’ll need to add a
require 'facets/random' line at the top of your file. You may also need
to add gem 'facets' to the Gemfile in leaves/fortune. Our method returns
a fortune at random, which is automatically transmitted to the channel or
nick where the command was received.

Of course, any self-respecting fortune bot announces its presence when it starts
up, so, in your Controller class, override the Autumn::Leaf#did_start_up
method to display a cheerful greeting:


def did_start_up
  stems.message 'FortuneBot at your service! Type "!fortune" to get your fortune!'
end

…and that’s it! You now have a fully functional fortune bot featuring — not
two — but three unique and exciting fortunes!

(For more on that stems.message bit, see the README.)

Step 2: Add the Leaf to Your Season

If you want, you can add the fortune bot to your leaves.yml and
stems.yml files to try it out. Adding a leaf is easy; simply duplicate
the structure used for another leaf’s entry and change the values as
appropriate. A typical two-leaf configuration will look like:


Scorekeeper:
  class: Scorekeeper
  respond_to_private_messages: false
Fortune:
  class: Fortune
  respond_to_private_messages: true

As you notice, each leaf instance is given a name. In this example the name
happens to be the same as the leaf’s type name, but you could run two copies of
a leaf like so:


Fortune1:
  class: Fortune
Fortune2:
  class: Fortune

This doesn’t make a whole lot of sense for our fortune bot, but for more
complicated bots it can be useful.

We’ve created the leaf, but we have to add it to the stem for it to work.
(Remember, a stem is an IRC connection and a leaf is a bot.) So, in your
stems.yml file, add an entry for this leaf. Your new config will appear
something like:


Example:
  nick: Scorekeeper
  leaves:
    - Scorekeeper
    - Insulter
    - Fortune
  rejoin: true
  channel: somechannel
  server: irc.someserver.com

When you restart the server, the bot will come back online and will now also
respond to the “!fortune” command. This is a helpful tutorial on how stems and
leaves are separate. One leaf can have many stems, and one stem can have many
leaves. You can combine these two entities however you need.

Step 3: Upgrade to ERb Views

You’ve already learned that for your [word]_command-type methods, the bot
responds with whatever string your method returns. For more complicated
commands, however, you may want to upgrade to full view abstraction, a la Ruby
on Rails. This is what the views directory is for.

If you place a .txt.erb file in the views directory named
after your command, it will be parsed by ERb and rendered as the result. You can
pass variables to the ERb parser by using the Autumn::Leaf#var method. Let’s
upgrade our fortune_command method for that:


def fortune_command(stem, sender, reply_to, msg)
  var :fortune => FORTUNES.at_rand
end

We can then write a view, fortune.txt.erb, which will render the
fortune:

<%= var :fortune %>

OK, so admittedly, this doesn’t really get us anywhere, but for more complicated
bots, this well help separate view and controller concerns.

For more information on view rendering, see the Autumn::Leaf#render method.