h1. Marvin Marvin is a simple IRC Framework for Rails suitable for building things such as simple IRC bots. Extracted from real use - we'd originally used a heavily modified version of MatzBot - it's been built to service a particular need. h2. Background Marvin is an event driven framework in two ways - for one, it uses EventMachine for all networking purposes - as a result, it's both relatively stable / reliable and also powerful. Following on from this, the irc library is event driven. At the base level, you choose a client (By Default, Marvin::IRC::Client.) and then you register any number of handlers. Whenever an event happens e.g. an incoming message, a connection unbinding or event just post_init, each handler is notified and given a small set of details about the event. Handlers are very simple - in fact, you could get away with registering Object.new as a handler. To function, handlers only require one method: handle - which takes two options. an event name (e.g. :incoming_message) and a hash of the aforementioned attributes / details. This data can then be processed. Alternatively, if a handler has a "handle_[event_name]" method (e.g. handle_incoming_message), it will instead be called. Also, if client= is implemented this will be called when the client is setup containing a reference to said client. This is used to that the handler can respond to actions. Like Rack for HTTP, Marvin provides a fair amount of example handlers for simple stuff inside IRC. h2. Getting Started The easiest way to get started with Marvin is by installing the Marvin gem. To do this, make sure Github is added to your gem sources (and you are using rubygems >= 1.2.0): $ gem sources -a http://gems.github.com $ sudo gem install username-marvin Once you have installed the gem, you should have access to the "marvin" command: $ marvin --help You can create a new marvin folder: $ marvin create my_marvin_project Then simply edit your settings in the +config/settings.yml+ default: name: "My Marvin Bot" server: irc.freenode.net port: 6667 channel: "#marvin-testing" use_logging: false datastore_location: tmp/datastore.json development: user: MarvinBot name: MarvinBot nick: MarvinBot3000 production: deployed: false You can use the defaults or configure it. By default your marvin bot will not do any logging. You will need to set that up. From this point you can begin running the bot as a daemon or as a console application: $ ./script/run The bot should join the specified channel and will resond to some simple commands by default: | MarvinBot3000: hello | YourName: Hola! h2. Marvin::Base - A handler starting point The first, Marvin::Base provides a base set of methods (e.g. say, reply etc etc.) which make writing a client easier. You can simply inherit from Marvin::Base, write some logic and then use the class method on_event to define responses to events. The passed in meta data for each event is then usable via options.attribute_name - an openstruct version of the details. e.g. class NinjaStuff < Marvin::Base on_event :incoming_message do do_something end def do_something reply options.message # Will echo back the message end end Or the like. Also, the halt! method can be called in any subclass to halt the handler callback chain. h2. Marvin::CommandHandler - Ridiculously easy Bots With Marvin::CommandHandler, you get to define seriously simple classes which can act as a simple bot. It takes great inspiration from "MatzBot":http://github.com/defunkt/matzbot/tree/master which was actually one of the main inspirations for creating marvin. To write a CommandHandler, you simply create a subclass (ala ActiveRecord::Base), define a few methods and then just use the "exposes" class method. e.g. class MySecondExample < Marvin::CommandHandler exposes :hello def hello(data) reply "Hello!" end end Where data is an array of parameters. exposed methods will be called when they match the following pattern: Botname: h2. Marvin::MiddleMan - Introducing middleware Marvin::MiddleMan lets you insert middleware between handlers and you're client - letting you do things such as translating all messages on the fly. It's build to be extensible and is relatively simple to use. On any Marvin::Base subclass (baring the MiddleMan itself), you can simple use the normal methods of registering a handler with one exception - you now pass one argument, the class reference to your middleman class. h2. Marvin::DataStore - A dead simple persistent hash store Want to save data between when you stop and start your IRC Client? With Marvin, it's really, really simple - Marvin::DataStore offers a simple syntax for persistent data stores. New datastores can be created with Marvin::DataStore.new("global-store-key"). From there, you have a hash to do whatever the hell you want. Just make sure the data you store is JSON-serializable. When you start - stop a server (via Marvin::Loader.run! and Marvin::Loader.stop!) you're data will be loaded from and written to disk accordingly. If you're inside a Marvin::Base subclass it's even easier. You can get a cattr_access style accessor for free - just use the "uses_datastore" method. e.g: class X < Marvin::Base uses_datastore "datastore-global-key", :cattr_name end Then, self.cattr_name will point to the data store instance.