Funny, this looks a bit similar to a project i'll release very soon called Catalyst.
I started the project while i maintained
Maypole, it was supposed to fix some design flaws and become Maypole 3.0.
But it has fast grown into something very different from
Maypole, so it became a subproject which now completely aims at enterprise class applications.
There are still lots of features from
Maypole present but i also added many things from
Struts, Struts-Chain, Struts-Delegate(Action mapping, Chain of Responsibility, Forms, Decorators, Filters),
Tomcat(Contexts, Sessions, elegant api for headers, cookies and uploads...),
SpringMVC(AOP features...),
Ruby on Rails (Multiple controller support) and
WebWork2.
Stuff like exception handling, roles based security, i18n, mod_perl1/mod_perl2/CGI support with unified api, simple debugging and profiling is naturally built in.
It also has many benefits for development in big teams and refactoring. (separation of flow and code, splitting code into small pieces...)
Here is an example for a Controller class.
package PetStore;
use strict;
use Catalyst '-Debug';
# Application name
PetStore->config->name('Catalyst PetStore');
# Root directory for additional files
PetStore->config->root('/home/sri/PetStore/web');
# Base uri for our application
PetStore->config->base('http://localhost/petstore');
# Session settings
PetStore->config->session(
class => 'Apache::Session::Postgres',
options => {
DataSource => 'dbi:Pg:dbname=petstore',
TableName => 'session',
UserName => 'postgres',
Password => 0,
Commit => 1
}
);
# Actions
PetStore->action(
# Built in action that'll get called at the end of a request,
# we use it for the view here,
# which in this case is YAML REST or TT2
_end => sub {
# form() returns a Data::FormValidator::Results object that
# will be automatically initialised when you use it
if ( form->valid('rest') ) {
# trunk is our universal data container to exchange
# informations between actions and methods
trunk( content_type => 'text/plain' );
call('PetStore::View::REST');
}
else {
# Set a default template
trunk( template => 'index.tt' );
call('PetStore::View::TT');
}
},
# Built in action that'll get called once at startup time to
# initialze your environment
'_setup' => sub {
# setup initializes a Catalyst component for you
setup('PetStore::Model::Cart');
setup(
'PetStore::Model::CDBI',
base => 'Catalyst::Model::CDBI',
dsn => 'dbi:Pg:dbname=petstore',
user => 'postgres',
password => '',
options => { AutoCommit => 1 }
);
setup( 'PetStore::View::REST',
base => 'Catalyst::View::REST::YAML' );
setup( 'PetStore::View::TT', base => 'Catalyst::View::TT' );
},
# Private action to publish the cart
_cart_to_objects => sub {
call(qw(PetStore::Model::Cart items_to_objects));
call(qw(PetStore::Model::CDBI::Item describe_cart_items));
call(qw(PetStore::Model::CDBI::Category describe_cart_items));
},
# Private action to to publish categories
_categories_to_objects => sub {
call(qw(PetStore::Model::CDBI::Category list));
},
# Start page
'index.html' => sub {
trunk( template => 'index.tt' );
# Merge with the existing Data::FormValidator::Results object
# or create a new one
form( required => ['yada'] );
# Include a private action at this point
include('_categories_to_objects');
},
# Show and edit the cart
'cart.html' => sub {
trunk( template => 'cart.tt' );
call(qw(PetStore::Model::Cart add)) if form->valid('add');
call(qw(PetStore::Model::Cart update))
if form->valid('update');
include('_cart_to_objects');
},
# Show products in category
'category.html' => sub {
roles(qw(foo bar));
trunk( template => 'category.tt' );
call(qw(PetStore::Controller::CDBI::Product list));
}
);
1;
The code is almost done and i'm currently writing documentation and examples for it, so if you're interested just hang out at #maypole on irc.perl.org (i'm searching testers;) or wait for the release, which will happen soon.