Declaring Catalyst Actions

Posted on 2009-4-26 (日) at 10:13 am by Florian Ragwitz [SIGNED]

Posted in: Perl

For a long time the Catalyst Framework has been using code attributes to allow users to declare actions that certain URLs get dispatched to. That looks something like this:

sub base    : Chained('/')    PathPart('') CaptureArgs(0) { ... }
sub index   : Chained('base') PathPart('') Args(0)        { ... }
sub default : Chained('base') PathPart('') Args           { ... }

It's a nice and clean syntax that keeps all important information right next to the method it belongs to.

However, attributes in perl have a couple of limitations. For one, the interface the perl core provides to use them is horrible and doesn't provide nearly enough information to do a lot of things, but most importantly attributes are just plain strings. That means you will need to parse something like "Chained('base')" into (Chained => 'base') yourself to make proper use of them.

While that's easy for the above example, it can be very hard in the general case because only perl can parse Perl. It's one of the reasons you can't use Catalyst::Controller::ActionRole to apply parameterized roles to your action instances, because parsing parameters out of things like Does(SomeRole => { names => [qw/affe tiger/], answer_re => qr/42/ }) would be awful and wrong.

With Catalyst 5.8 most of the attribute related code has been removed from the internals. It's now using MooseX::MethodAttributes to do all the heavy lifting. Also the internals of how actions are registered have been refactored to make it easier to implement alternate ways without changing the Catalyst core.

As a proof of concept for this I implemented a new way of declaring actions that's very similar to how Moose provides it's sugar functions. You can get it from github.

With that, the above example looks like this:

action base    => (Chained => '/',    PathPart => '', CaptureArgs => 0) => sub { ... };
action index   => (Chained => 'base', PathPart => '', Args    => 0    ) => sub { ... };
action default => (Chained => 'base', PathPart => '', Args    => undef) => sub { ... };


It also moves method declaration from compiletime to runtime, making this possible:

for my $action (qw/foo bar baz/) {
    action $action => (Chained => 'somewhere', Args => 0) => sub {
        my ($self, $ctx) = @_;
        $ctx->stash->{ $action } = $ctx->model('Foo')->get_stuff($action);
    };
}

Admittedly, that's all very ugly, but illustrates well what kind of things we're able to do now. But it doesn't need to be ugly. With Devel::Declare we have a great tool to add our own awesome syntax to perl, similar to how things like MooseX::Method::Signatures, MooseX::MultiMethods and MooseX::Declare do.

So how would a declarative syntax for Catalyst controllers look like? I don't know. Ideas include something like this:

under /some/where, action foo ('foo', $id) { ... }

to mean:

sub foo : Chained('/some/where') PathPart('foo') CaptureArgs(1) { ... }

Adding Moose type constraints to this would be interesting, too, and make validation of captures and arguments a lot easier. Multi dispatch similar to MooseX::MultiMethods could be handy as well:

under /some/where {
    action ('foo', Int $id) {
        # find and stash an item by id
    }
    action ('foo', Str $name) {
        # search items using $name
    }
    action ('foo', Any $thing) {
        # display error page
    }
}

So you see there are a lot of possibilities that should be explored. Unfortunately I have no idea what kind of syntax and features people would like to have, so your feedback on this would be much appreciated. :-)


Last modified: 2009-4-26 (日) at 11:14 pm


  • Re: Declaring Catalyst Actions

    Written by Anonymous Coward (0) on 2009-5-3 (日) at 2:10 pm

    Great work so far, to catch up any late readers, there's an ongoing conversation about this on IRC and I've blogged as well at:

    http://jjnapiorkowski.vox.com/library/post/rethinking-catalyst-actions-and-controllers.html

    http://jjnapiorkowski.vox.com/library/post/catalyst-actions-part-2-details-and-clarification.html

    Athough I think at this point some of the stuff I wrote there my minds been changed on :) However people with useful dieas and willing to hack code welcome to join the discussion.


Navigation

Categories

Tags

Login