Throwaway code

It has become increasingly common for me to come up with a program for an amazing task one day, to rewrite it the next day.

umcdist, the Wesnoth-UMC-Dev Distribution Tool, has been in development hell for a year mostly for this reason; the other reason is that it seems like it will perform worse than build-external-archive.sh a.k.a. “Scrappy” due to an excessive usage of Perl's system function. I cannot make up my mind and choose between performance and maintainability; Espreon knows that build-external-archive.sh is broken, but I can't be bothered to try to understand that unholy abomination again to fix it.

Meanwhile, umcstat (Wesnoth-UMC-Dev Statistics Service) is still a work in progress, but with more emphasis in progress; there's actual code written already, and I've been using freenode's Eir bot framework to test it.<

While Eir could possibly be a nice way to get rid of umcreg's Net::IRC dependency and code, it's actually a C++ program that can be compiled only with GCC 4.4 at minimum, due to at least one C++0x feature used throughout the code: auto. The target machine runs Debian lenny, unlike my laptop (Squeeze), and therefore doesn't have GCC 4.4!

Instead of sticking with Eir, I'm refactoring umcreg's IRC code into a custom Perl-only framework, umcbotd, and making creative use of eval writing an abomination code-named “Naia”, which I'm rewriting again because the first version I wrote, which worked, was very badly designed and ugly. I know it's a problem when I have three classes or modules all depending upon each other's internals.

The goal of umcbotd/Naia is producing a Net::IRC-based abstraction layer for our bots that treats them as “services” with multiple “modules” (not in the Perl sense, though) that can be easily inserted and removed from the system by adding/removing their files. umcreg already runs with a prototype implementation of this mechanism, but it needs to be generalized further before it can be usable with Naia.

Writing our bots could be this simple, if Naia gets completed:

#!/bin/true
CO_SERVICE_COMPONENT('umcreg');
sub ctcp_version_reply () { "Wesnoth-UMC-Dev Registry Service, using " . Naia::version_string() }
sub eh_ctcp_version
{
my ($self, $event) = @_;
$self->ctcp_reply($event->nick, 'VERSION ' . ctcp_version_reply());
}
# ...
my $bot = Naia::get_bot('umcreg');
my %eh = (
'cversion' => \&eh_ctcp_version,
'msg' => \&eh_msg_private,
'330' => \&eh_whoisloggedin,
'318' => \&eh_endofwhois,
'331' => \&eh_notopic,
'332' => \&eh_topic,
'403' => \&eh_nosuchchannel,
);
$bot->connect();
$bot->register_event_handlers(%eh);

And their modules would be like this, more or less the same as umcreg's modules already are:

#!/bin/true
# token, subroutine, privilege level (A: admin, H: half-admin, U: user)
CO_MODULE('RAW', \&co_raw, 'A');
sub co_raw
{
my ($parent, $nick, $hostmask, $svaname) = (shift, shift, shift, shift);
if(!@_) {
$parent->notice($nick, "Not enough arguments for \002RAW\002.");
return;
}
$parent->sl(join(' ', @_));
broadcast_to_log("RAW [$hostmask]");
}

... And of course it would still involve lots of ugly stuff under the hood (eval magic), but if done right I shouldn't have to touch it whenever I wanted to add or remove a feature from any of our two services.