p1k3::2007/9/8/grape_flavored

Anyway, I had to start a little web application from scratch the other day, so I started looking for a framework, because I needed a lot of the sort of things you suspect someone has already written.

My criteria were as follows:

I looked at Catalyst, Jifty, and CGI::Application. The first two were interesting, but fell down on the dependency question. For purely pragmatic reasons, I doubted it would be worth the effort installing them on my target machine, and I suspect I was right. As it stands, I spent nearly a day on DBD::SQLite, the single XS module I wound up using. I'd prefer not to talk further about that experience, beyond noting in passing that just because it feels wrong to wrap

perl Makefile.PL
make

in a CGI script, FTP it to the right location, and watch something build in your browser doesn't mean that you shouldn't give it a shot.

CGI::Application caught my attention because its core abstraction is basically a dispatch table in the context of use CGI. Here is a concrete example:

# in FieldTrip.pm

package FieldTrip;
use base 'CGI::Application';

sub setup {
  my $self = shift;

  $self->start_mode('viewtrip');

  $self->run_modes(
    'viewtrip' => 'viewtrip',
  );
}

sub viewtrip {
  my $self = shift;
  return "Here is a trip.\n";
}

1;

# and then in a wrapper script called ft.cgi...

use FieldTrip;
my $ft = FieldTrip->new;
$ft->run;

ft.cgi can now be called like ft.cgi?rm=viewtrip, and you'll get the appropriate result. Actually, you'll get it even without the runmode parameter, since viewtrip is also the start mode. This is pretty darned simple. It certainly didn't require me to wrap my brain around much before I could evaluate its merits in real code.

CGI::Application also comes with a plugin architecture, and the plugins have so-far tended to be nicely discrete pieces of functionality which work as advertised. The above becomes something like this, with a little help:

package FieldTrip;
use base 'CGI::Application';
use CGI::Application::Plugin::AutoRunmode;

sub viewtrip : StartRunmode {
  my $self = shift;
  # etc.
}

1;

Here's my list of plugins:

Some other modules attracted me on the basis of simple/powerful:

In the end, I wound up with a project that looks a little like this:

Within FieldTrip.pm, my runmodes all look like this:

sub viewtrip : Runmode {
  return $_[0]->thing_out( 
    "Thing::Trip",
    'View trip details'
  );
}

Which involves some contortions elsewhere that I should probably simplify (maybe by just generating view, edit, and save modes for each kind of Thing with Class::Accessor), but is pretty close to declarative. Adding a runmode can be as simple as four or five lines of code in FieldTrip.pm and an appropriately named template in the pages directory.

Mid-way through this project, I realized that I could spend a little extra time and sell a small application built on exactly the same framework to another client. In order to do this, I had to put a single table in a SQLite database, create a 20-line subclass of Thing.pm, and rewrite a couple of templates. This was remarkably painless.

All original content on p1k3, unless otherwise noted, is released to the public domain.