10 Catalyst models in 10 days1

Published · Sunday, 12 July 2009 (Updated · 7 March 2010)

Catchy enough for you? I’ve been lax in my Perl Iron Man participation. Excepting a recent little 9th grade essay, I’m way behind so being the over-compensating type let’s catch-up too much.

10 in 10 on github

Update, July 25. The code for this project is in github now—p5-myapp-10in10. If you have tweaks, corrections, patches, etc, do them against that. Thank you for your interest in these articles and Catalyst, the best web framework going.

Catalyst—The Perl MVC Framework

Introduction

This is part gimmick and the code discussions won’t be deep but it should be fun for anyone interested and useful for newcomers to Catalyst and Perl hackers looking to blaze into wilder territories. I feel that the model part of the MVC is the crux of any application and has the most room to play and improve an application.

Your Controllers are half-done from the jump. If you’re doing straight HTTP and trying to be REST-ful, the dispatch mostly writes itself.

Your Views are somewhat similar. JSON or XML or nice bare XHTML. It’s neither that difficult nor that likely to be elaborate—well, CSS can be quite elaborate—unless yur doin’ it rong.

Your Models can handle more and remove the necessity of more logic trees from the app than you’d expect. To some degree this is just pushing the complexity around but it’s the right way, unquestionably2, to do it.

This list is subject to change but now I’ve at least committed to ten of them. Most will be a bit fluffy but the techniques can be used in any Catalyst application and it should give a decent range of things to try and ways to do them. These will get you thinking about models more as services and maybe get you to approach them more creatively.

Models we’ll tackle (subject to substitution)

  1. Random quote.
  2. Moon phase information.
  3. Cover images via Amazon.com’s APA.
  4. Random numbers and really truly random numbers.
  5. Stock quotes (Catalyst::Model::Adaptor).
  6. Log file model (Apache access log).
  7. Page view counter (SQLite).
  8. Graphical title elements.
  9. TheSchwartz job queue.
  10. Fixing legacy code by not fixing it.

In the final post I’ll include the sample code every article as a regular Perl distribution in a Catalyst app so you can run the examples without having to put them together in each article. Note that manually putting them together is the best way to get the knowledge under your belt. So play along if you can.

All examples proceed from the following set-up

I use emacs and that’s what’s on the command line examples. You can use any editor you like, of course.

Create your test application

catalyst.pl MyApp
created "MyApp"
created "MyApp/script"
created "MyApp/lib"
created "MyApp/root"
created "MyApp/root/static"
created "MyApp/root/static/images"
created "MyApp/t"
created "MyApp/lib/MyApp"
created "MyApp/lib/MyApp/Model"
created "MyApp/lib/MyApp/View"
created "MyApp/lib/MyApp/Controller"
created "MyApp/myapp.conf"
created "MyApp/lib/MyApp.pm"
created "MyApp/lib/MyApp/Controller/Root.pm"
created "MyApp/README"
created "MyApp/Changes"
created "MyApp/t/01app.t"
created "MyApp/t/02pod.t"
created "MyApp/t/03podcoverage.t"
created "MyApp/root/static/images/catalyst_logo.png"
created "MyApp/root/static/images/btn_120x50_built.png"
created "MyApp/root/static/images/btn_120x50_built_shadow.png"
created "MyApp/root/static/images/btn_120x50_powered.png"
created "MyApp/root/static/images/btn_120x50_powered_shadow.png"
created "MyApp/root/static/images/btn_88x31_built.png"
created "MyApp/root/static/images/btn_88x31_built_shadow.png"
created "MyApp/root/static/images/btn_88x31_powered.png"
created "MyApp/root/static/images/btn_88x31_powered_shadow.png"
created "MyApp/root/favicon.ico"
created "MyApp/Makefile.PL"
created "MyApp/script/myapp_cgi.pl"
created "MyApp/script/myapp_fastcgi.pl"
created "MyApp/script/myapp_server.pl"
created "MyApp/script/myapp_test.pl"
created "MyApp/script/myapp_create.pl"

Make a few local modifications

cd MyApp/
rm myapp.conf
mv root/static/images root/static/img

That’s some slight bias on my part. I hate the Config::General format and typing “images” is much harder than “img” if you have to do it a thousand times and the element name is <img />.

Edit the main application module

We want to use unicode, automatic configuration loading, and static service of images and such when running the test server. Changing the static include_path isn’t always done but I find it much cleaner and only marginally more verbose to set-up in whatever webserver (Apache, lighttpd, nginx, varnish, et cetera) when you are ready to let the static stuff be served appropriately. This is not discussed in these articles.

emacs lib/MyApp.pm
package MyApp;
use strict;
use warnings;
use Catalyst::Runtime 5.80;

use parent qw( Catalyst );
use Catalyst qw(
                Unicode
                ConfigLoader
                Static::Simple
                );

our $VERSION = '0.01';

__PACKAGE__->config
    ( name => "10 Example Catalyst Models, v$VERSION",
      setup_components => { except => qr,[^:\w], },
      static => {
          include_path => [ __PACKAGE__->path_to('root','static') ],
      },
     );

__PACKAGE__->setup();

1;

Then you can run your test server with the following command and it should nicely restart whenever you make changes–

./script/myapp_server.pl -d -r -p 3000

The -r flag is for “restart.” It’s one of the best things about Catalyst development if you didn’t already know. You can develop and see changes instantly (well, as fast as the server can restart) and without having to do anything yourself. Take that, compiled languages. Note, port 3000 is the default. It’s included FYI and so you can tweak without looking it up.

Requirements

One example in particular—the log parser—requires Perl 5.10 as it uses named captures in its regular expression and some 5.10 features; if you leave that out a high 5.8 or 5.9 should do. Catalyst 5.8 is required in the Makefile.PL for MyApp because we use Moose in the log model but everything else will run on 5.7 for sure and the log might just anyway if for some reason you don’t want to upgrade to 5.8.

There are a good handful of modules you’ll need to install to do the various examples. They’ll be listed in each article. You can definitely start with getting to know local::lib. It’s not discussed but it is awesome for setting up local CPAN stuff where you don’t have root permissions or don’t want to mess with the environment for other users.

You’ll have to have these modules installed, at least: Catalyst::Runtime, Catalyst::Devel, Catalyst::Plugin::Unicode, Catalyst::Plugin::ConfigLoader, and Catalyst::Plugin::Static::Simple.

cpan Catalyst::Runtime Catalyst::Devel
cpan Catalyst::Plugin::Unicode
cpan Catalyst::Plugin::ConfigLoader
cpan Catalyst::Plugin::Static::Simple

They come with a long list of dependencies—many modules will need to be installed to run Catalyst. I used to balk at this. I don’t anymore. The dependencies pull in some awesome code from some really smart hackers. Trying to replace it yourself or thinking you don’t need it is developmental suicide. I have taken to using quite a few of the modules I used to think were overkill—like Path::Class, URI, and DateTime—in my daily code. Embrace modern Perl. It’s harder at first. It’s easier for every moment after that from edits and feature additions to debugging and packaging for distribution.

I also strongly recommend you update to the latest CPAN.pm. Older ones make some installation issues much more problematic.

cpan CPAN

All articles, including this one are very likely to be updated as we go and I see things that should have been more clear or are plain wrong.

Tune in tomorrow for our first entry—Catalyst Model #1: Random quotes.

1 Business days. Two weeks’ worth plus this intro and a wrap-up after model #10.

2 What?! You question me!?!?!?

Okay. It’s like this. I’ve been writing CGIs and web apps since 1998. I’ve done a couple thousand of them at this point. While gentlemen may differ, I’m not talking through my hat. Fat models make maintenance, testing, extensibility, everything, better. Disagree if you like but do it up front so those of us with common sense will have the chance to avoid ever working with you.


Child resources of 10 Catalyst models in 10 days1


digg stumbleupon del.icio.us reddit Fark Technorati Faves

« If you only had one programming language to choose –or– Let the FUD be with you · Questions from the QueryLog: access catalyst config from a model »
« Perl resources, modules, and sample code »