Rails fans are understandably proud of the magic metaprogramming facilities of Ruby, the database introspection capabilities of ActiveRecord, and the fact that the most basic model class is only two lines long (at least in every tutorial I’ve seen).

I say that’s two lines too many.

Here’s how to have zero-line model modules in Perl — as many as you want. (If you have a complete CRUD application, you can use the same idea to generate RESTful controllers, too.)

I started by defining a base model class:

package MyApp::Model;

sub new
{
	my $class = shift;
	(my $name = $class) =~ s/__PACKAGE__:://;
	bless \$name, $class;
}

sub name
{
    return ${ +shift };
}

1;

Sure, it doesn’t do anything (such as connect to a database), but it serves the same purpose as ActiveRecord::Base in Rails.

Then I wrote the main module for my application, MyApp. (Hey, it’s Friday afternoon. I leave my creativity for the code.) All it has to do is load two modules:

package MyApp;

use GenModel;
use MyApp::Model::Prufrock;

1;

All that’s left (besides the mysterious GenModel) is myapp.pl:

#!/usr/bin/perl

use strict;
use warnings;

use MyApp;

my $model = MyApp::Model::Prufrock->new();
print "My model's name is: ", $model->name(), "!\n";

Now I have written GenModel, but I haven’t written MyApp::Model::Prufrock. The only references to it in my entire source tree are in the use line of MyApp and in the line that creates $model in myapp.pl.

I realize full well that a good model class for a complex application needs a few more lines of code, but why even write the model class until you really need it?

Of course all of the magic is in GenModel, which I don’t want to show quite yet. It’s a well-spaced screen full of fairly simple Perl code that doesn’t use eval or any other code generation tricks you might think. It’s no source filter and it doesn’t replace any of Perl’s syntax.

I’ll post the code in a couple of days. It uses a technique in chapter 8 of Perl Hacks. Meanwhile, I’d like to see a similar Ruby version that doesn’t use any eval either. (I have an idea how to make it work, but not without eval.)