Wednesday, January 30, 2008

Jerkbot gets a Groovy makeover

Tonight I decided to rewrite my example bot for jerklib. I chose to do it in Groovy because i've had the urge to use it. The fact that it integrates well with java makes it a perfect candidate to write a bot (or even a client) using Jerklib! As I was writing it I felt like a kid in a candy store, oogling at the coolness that is Groovy. To run this code download the jerklib jar. Then simply type:
groovy -cp jerklib.jar:. filename.groovy
Or you're on windows then it's:
groovy -cp jerklib.jar;. filename.groovy

Of course you'll replace filename.groovy w/ the file you saved it under.

A Note: I primarily used this class to test my additions to the jerklib -- so you can call this a scratchpad of sorts (at least it was at the time.)

import jerklib.Profile
import jerklib.ProfileImpl
import jerklib.ConnectionManager

* Created: Jan 29, 2008 11:42:23 PM
* @author Robert O'Connor
class GroovyJerkbot implements IRCEventListener {
def manager

GroovyJerkbot(String nick, String username, String hostname, int port) {
def profile = new ProfileImpl(username, nick, nick + new Random().nextInt(42),
nick + new Random().nextInt(512))
manager = new ConnectionManager(profile)
manager.requestConnection(hostname, port).addIRCEventListener(this)


static void main(args) {
def bot = new GroovyJerkbot("jerkbot", "jerkbot", "", 6667)

void receiveEvent(IRCEvent e) {
if (e.getType() == IRCEvent.Type.CONNECT_COMPLETE) {
else if (e.getType() == IRCEvent.Type.JOIN_COMPLETE) {
def JoinCompleteEvent event = (JoinCompleteEvent) e
} else if (e.getType() == IRCEvent.Type.CHANNEL_MESSAGE) {
MessageEvent event = (MessageEvent) e
// what does this is take the channel msg and match it to the pattern ~say foo
def matcher = event.getMessage() =~ /^~say\s+(.*)$/
if (matcher.matches())
}else if(event.getMessage() ==~ /^~part.*$/) {
e.getSession().partChannel(event.getChannel(),"I was asked to leave")
} else {
def whoMatcher = event.getMessage() =~ /^~who\s+(.*)$/
if(whoMatcher.matches()) {
def awayMatcher = event.getMessage() =~ /^~away\s+(.*)$/
if(awayMatcher.matches()) {
}else {

} else if (e.getType() == IRCEvent.Type.PRIVATE_MESSAGE) {
MessageEvent event = (MessageEvent)e
if(event.getMessage() ==~ /^~quit.*$/) {
e.getSession().close("I was asked to leave.")
} else if (e.getType() == IRCEvent.Type.NICK_CHANGE) {
NickChangeEvent event = (NickChangeEvent) e
println event.getOldNick()
println event.getNewNick()
println event.getUserName()
println event.getHostName()
println e.getRawEventData()
} else {
if (e.getType() == IRCEvent.Type.AWAY_EVENT) {
AwayEvent event = (AwayEvent)e
println "Nick: "+event.getNick()
println "Event Type: "+event.getEventType()
println "Us?: "+event.isYou()
println "Away?: "+event.isAway()




As you can see, the import for Random is missing (no need with groovy, it's imported implicitly, whereas in java, only java.lang is imported implicitly! Also, semi-colons are OPTIONAL!! Groovy has native regex support! =~ means to create the matcher for this pattern. The ==~ operator checks if the text matches the pattern given after the ==~ operator.

Nobody would argue with me if I said the above example was verbose. Jason Davis wrote this the following gem:

import jerklib.*;
import jerklib.tasks.*;

def stratMap =[:]
stratMap[ Type.CONNECT_COMPLETE ] = {x-> x.session.joinChannel "#jerklib"}
stratMap[ Type.JOIN_COMPLETE ] = {x-> "Hello World"}
stratMap[Type.CHANNEL_MESSAGE] = {x-> println x.rawEventData}

conMan = new ConnectionManager(new ProfileImpl("foo","gscripbot","gscripbot1","teh"));
session = conMan.requestConnection('');
session.addIRCEventListener({x-> close = stratMap[x.type]; if(close != null)close(x)} as IRCEventListener);

Jason used the Strategy Pattern for the event handling. It cleans up your code greatly and eliminates the need for a bunch of if statements. It also can cut down on the verbosity of your code, like it has in this case.