Class | Autumn::Leaf |
In: |
lib/autumn/leaf.rb
|
Parent: | Object |
This is the superclass that all Autumn leaves use. To write a leaf, sublcass this class and implement methods for each of your leaf‘s commands. Your leaf‘s repertoire of commands is derived from the names of the methods you write. For instance, to have your leaf respond to a "!hello" command in IRC, write a method like so:
def hello_command(stem, sender, reply_to, msg) stem.message "Why hello there!", reply_to end
You can also implement this method as:
def hello_command(stem, sender, reply_to, msg) return "Why hello there!" end
Methods of the form [word]_command tell the leaf to respond to commands in IRC of the form "![word]". They should accept four parameters:
Sender hashes: A "sender hash" is a hash with the following keys: nick (the user‘s nickname), user (the user‘s username), and host (the user‘s hostname). Any of these fields except nick could be nil. Sender hashes are used throughout the Stem and Leaf classes, as well as other classes; they always have the same keys.
If your *_command method returns a string, it will be sent as an IRC message to "reply-to" parameter.If your leaf needs to respond to more complicated commands, you will have to override the did_receive_channel_message method (see below). If you like, you can remove the quit_command method in your subclass, for instance, to prevent the leaf from responding to !quit. You can also protect that method using filters (see "Filters").
If you want to separate view logic from the controller, you can use ERb to template your views. See the render method for more information.
Aside from adding your own *_command-type methods, you should investigate overriding the "hook" methods, such as will_start_up, did_start_up, did_receive_private_message, did_receive_channel_message, etc. There‘s a laundry list of so-named methods you can override. Their default implementations do nothing, so there‘s no need to call super.
Most of the IRC actions (such as joining and leaving a channel, setting a topic, etc.) are part of a Stem object. If your leaf is only running off of one stem, you can call these stem methods directly, as if they were methods in the Leaf class. Otherwise, you will need to specify which stem to perform these IRC actions on. Usually, the stem is given to you, as a parameter for your *_command method, for instance.
For the sake of convenience, you can make Stem method calls on the stems attribute; these calls will be forwarded to every stem in the stems attribute. For instance, to broadcast a message to all servers and all channels:
stems.message "Ready for orders!"
Like Ruby on Rails, you can add filters to each of your commands to be executed before or after the command is run. You can do this using the before_filter and after_filter methods, just like in Rails. Filters are run in the order they are added to the chain. Thus, if you wanted to run your preload filter before you ran your cache filter, you‘d write the calls in this order:
class MyLeaf < Leaf before_filter :my_preload before_filter :my_cache end
See the documentation for the before_filter and after_filter methods and the README file for more information on filters.
If a leaf is initialized with a hash for the authentication option, the values of that hash are used to choose an authenticator that will be run before each command. This authenticator will determine whether or not the user can run that command. The options that can be specified in this hash are:
type: | The name of a class in the Autumn::Authentication module, in snake_case. Thus, if you wanted to use the Autumn::Authentication::Password class, which does password-based authentication, you‘d set this value to password. |
only: | A list of protected commands for which authentication is required; all other commands are unprotected. |
except: | A list of unprotected commands; all other commands require authentication. |
silent: | Normally, when someone fails to authenticate himself before running a protected command, the leaf responds with an error message (e.g., "You have to authenticate with a password first"). Set this to true to suppress this behaivor. |
In addition, you can also specify any custom options for your authenticator. These options are passed to the authenticator‘s initialize method. See the classes in the Autumn::Authentication module for such options.
If you annotate a command method as protected, the authenticator will be run unconditionally, regardless of the only or except options:
class Controller < Autumn::Leaf def destructive_command(stem, sender, reply_to, msg) # ... end ann :destructive_command, :protected => true end
Autumn comes with a framework for logging as well. It‘s very similar to the Ruby on Rails logging framework. To log an error message:
logger.error "Quiz data is missing!"
By default the logger will only log info events and above in production seasons, and will log all messages for debug seasons. (See the README for more on seasons.) To customize the logger, and for more information on logging, see the LogFacade class documentation.
The Autumn::Formatting module contains sub-modules which handle formatting for different clients (such as mIRC-style formatting, the most common). The specific formatting module that‘s included depends on the leaf‘s initialization options; see initialize.
DEFAULT_COMMAND_PREFIX | = | '!' | Default for the command_prefix init option. |
Instantiates a leaf. This is generally handled by the Foliater class. Valid options are:
command_prefix: | The string that must precede all command names (default "!") |
responds_to_private_messages: | If true, the bot responds to known commands sent in private messages. |
logger: | The LogFacade instance for this leaf. |
database: | The name of a custom database connection to use. |
formatter: | The name of an Autumn::Formatting class to use as the formatter (chooses Autumn::Formatting::DEFAULT by default). |
As well as any user-defined options you want.
Adds a filter to the end of the list of filters to be run after a command is executed. You can use these filters to perform tasks that must be done after a command is run, such as cleaning up temporary files. Pass the name of your filter as a symbol, and an optional has of options. See the before_filter docs for more.
Your method will be called with five parameters — see the before_filter method for more information. Unlike before_filter filters, however, any return value is ignored. For example, if you create the filter:
after_filter :clean_tmp, :only => :sendfile, :remove_symlinks => true
then any time the bot receives a "!sendfile" command, after running the command it will evaluate:
clean_tmp_filter <stem>, <channel>, <sender hash>, :sendfile, <message>, { :remove_symlinks => true }
Duplicates a command. This method aliases the command method and also ensures the correct view file is rendered if appropriate.
alias_command :google, :g
Adds a filter to the end of the list of filters to be run before a command is executed. You can use these filters to perform tasks that prepare the leaf to respond to a command, or to determine whether or not a command should be run (e.g., authentication). Pass the name of your filter as a symbol, and an optional has of options:
only: | Only run the filter for these commands |
except: | Do not run the filter for these commands |
Each option can refer to a single command or an Array of commands. Commands should be symbols such as :quit for the !quit command.
Your method will be called with these parameters:
If your filter returns either nil or false, the filter chain will be halted and the command will not be run. For example, if you create the filter:
before_filter :read_files, :only => [ :quit, :reload ], :remote_files => true
then any time the bot receives a "!quit" or "!reload" command, it will first evaluate:
read_files_filter <stem>, <channel>, <sender hash>, <command>, <message>, { :remote_files => true }
and if the result is not false or nil, the command will be executed.
Performs the block in the context of a database, referenced by symbol. For instance, if you had defined in database.yml a connection named "scorekeeper", you could access that connection like so:
database(:scorekeeper) do [...] end
If your database is named after your leaf (as in the example above for a leaf named "Scorekeeper"), it will automatically be set as the database context for the scope of all hook, filter and command methods. However, if your database connection is named differently, or if you are working in a method not invoked by the Leaf class, you will need to set the connection using this method.
If you omit the dbname parameter, it will try to guess the name of your database connection using the leaf‘s name and the leaf‘s class name.
If the database connection cannot be found, the block is executed with no database scope.
Invoked just before the leaf starts up. Override this method to do any pre-startup tasks you need. The leaf is fully initialized and all methods and helper objects are available.
Invoked when a channel gains a property. property can be any value returned by the stem‘s Daemon. If the peroperty is not in the hash, it will be a string (not a symbol) equal to the letter value for that property (e.g., ‘k’ for password). If the property takes an argument (such as user limit or password), it will be passed via argument (which is otherwise nil). bestower is a sender hash.
Invoked when a message is sent to a channel the leaf is a member of (even if that message was a valid command). sender is a sender hash.
Invoked when a notice is received. Notices are like channel or pivate messages, except that leaves are expected not to respond to them. sender is a sender hash; recipient is either a channel or a nick.
Invoked after the leaf is started up and is ready to accept commands. Override this method to do any post-startup tasks you need, such as displaying a greeting message.
Invoked when a user changes his nick. person is a sender hash containing the person‘s old nick, and nick is their new nick.
Sets a custom view name to render. The name doesn‘t have to correspond to an actual command, just an existing view file. Example:
def my_command(stem, sender, reply_to, msg) render :help and return if msg.empty? # user doesn't know how to use the command [...] end
Only one view is rendered per command. If this method is called multiple times, the last value set is used. This method has no effect outside of a *_command method.
By default, the view named after the command will be rendered. If no such view exists, the value returned by the method will be used as the response.
Invoked when someone changes a channel‘s topic. topic is the new topic. person is a sender hash.
Invoked when someone gains a channel privilege. privilege can be any value returned by the stem‘s Daemon. If the privilege is not in the hash, it will be a string (not a symbol) equal to the letter value for that privilege (e.g., ‘v’ for voice). bestower is a sender hash.
Invoked when someone gains a user mode. mode can be an value returned by the stem‘s Daemon. If the mode is not in the hash, it will be a string (not a symbol) equal to the letter value for that mode (e.g., ‘i’ for invisible). bestower is a sender hash.
Invoked when someone invites another person to a channel. For some IRC servers, this will only be invoked if the leaf itself is invited into a channel. inviter is a sender hash; invitee is a nick.
Invoked when someone is kicked from a channel. Note that this is called when your leaf is kicked as well, so it may well be the case that channel is a channel you are no longer in! kicker is a sender hash; victim is a nick.
Gets or sets a variable for use in the view. Use this method in *_command methods to pass data to the view ERb file, and in the ERb file to retrieve these values. For example, in your controller.rb file:
def my_command(stem, sender, reply_to, msg) var :num_lights => 4 end
And in your my.txt.erb file:
THERE ARE <%= var :num_lights %> LIGHTS!