--- 
author: 
  email: rafl@fsfe.org
  keyid: 742f2a428e635a5e
  name: Florian Ragwitz
categories: 
  - Perl
date: 2009-04-26T08:13:18Z
guid: c42e982b-d436-4680-b794-973c516befec
modified: 2009-04-26T09:14:50Z
raw: "-----BEGIN PGP SIGNED MESSAGE-----\nHash: SHA1\n\n=pod\n\nFor a long time the L<Catalyst Framework|http://catalystframework.org> has been using code attributes\nto allow users to declare actions that certain URLs get dispatched to.\nThat looks something like this:\n\n  lang:Perl\n  sub base    : Chained('/')    PathPart('') CaptureArgs(0) { ... }\n  sub index   : Chained('base') PathPart('') Args(0)        { ... }\n  sub default : Chained('base') PathPart('') Args           { ... }\n\nIt's a nice and clean syntax that keeps all important information\nright next to the method it belongs to.\n\nHowever, attributes in perl have a couple of limitations. For one, the\ninterface the perl core provides to use them is horrible and doesn't\nprovide nearly enough information to do a lot of things, but most\nimportantly attributes are just plain strings. That means you will\nneed to parse something like C<\"Chained('base')\"> into\nC<< (Chained => 'base') >> yourself to make proper use of them.\n\nWhile that's easy for the above example, it can be very hard in the\ngeneral case because only perl can parse Perl. It's one of the reasons\nyou can't use L<Catalyst::Controller::ActionRole|http://search.cpan.org/perldoc?Catalyst::Controller::ActionRole> to apply\nparameterized roles to your action instances, because parsing\nparameters out of things like\nC<< Does(SomeRole => { names => [qw/affe tiger/], answer_re => qr/42/ }) >>\nwould be awful and wrong.\n\nWith Catalyst 5.8 most of the attribute related code has been removed\nfrom the internals. It's now using L<MooseX::MethodAttributes|http://search.cpan.org/perldoc?MooseX::MethodAttributes> to do\nall the heavy lifting. Also the internals of how actions are\nregistered have been refactored to make it easier to implement\nalternate ways without changing the Catalyst core.\n\nAs a proof of concept for this I implemented a new way of declaring\nactions that's very similar to how L<Moose|http://search.cpan.org/perldoc?Moose> provides it's sugar\nfunctions. You can get it from\nL<github|http://github.com/rafl/catalystx-actions/tree>.\n\nWith that, the above example looks like this:\n\n  lang:Perl\n  action base    => (Chained => '/',    PathPart => '', CaptureArgs => 0) => sub { ... };\n  action index   => (Chained => 'base', PathPart => '', Args    => 0    ) => sub { ... };\n  action default => (Chained => 'base', PathPart => '', Args    => undef) => sub { ... };\n\n\nIt also moves method declaration from compiletime to runtime, making\nthis possible:\n\n  lang:Perl\n  for my $action (qw/foo bar baz/) {\n      action $action => (Chained => 'somewhere', Args => 0) => sub {\n          my ($self, $ctx) = @_;\n          $ctx->stash->{ $action } = $ctx->model('Foo')->get_stuff($action);\n      };\n  }\n\nAdmittedly, that's all very ugly, but illustrates well what kind of\nthings we're able to do now. But it doesn't need to be ugly. With\nL<Devel::Declare|http://search.cpan.org/perldoc?Devel::Declare> we have a great tool to add our own awesome syntax\nto perl, similar to how things like L<MooseX::Method::Signatures|http://search.cpan.org/perldoc?MooseX::Method::Signatures>,\nL<MooseX::MultiMethods|http://search.cpan.org/perldoc?MooseX::MultiMethods> and L<MooseX::Declare|http://search.cpan.org/perldoc?MooseX::Declare> do.\n\nSo how would a declarative syntax for Catalyst controllers look like?\nI don't know. Ideas include something like this:\n\n  under /some/where, action foo ('foo', $id) { ... }\n\nto mean:\n\n  sub foo : Chained('/some/where') PathPart('foo') CaptureArgs(1) { ... }\n\nAdding Moose type constraints to this would be interesting, too, and\nmake validation of captures and arguments a lot easier. Multi dispatch\nsimilar to MooseX::MultiMethods could be handy as well:\n\n  under /some/where {\n      action ('foo', Int $id) {\n          # find and stash an item by id\n      }\n      action ('foo', Str $name) {\n          # search items using $name\n      }\n      action ('foo', Any $thing) {\n          # display error page\n      }\n  }\n\nSo you see there are a lot of possibilities that should be\nexplored. Unfortunately I have no idea what kind of syntax and\nfeatures people would like to have, so your feedback on this would be\nmuch appreciated. :-)\n\n=cut\n-----BEGIN PGP SIGNATURE-----\nVersion: GnuPG v1.4.6 (GNU/Linux)\n\niD8DBQFJ9CYKdC8qQo5jWl4RAsRKAJ9Yad61aq7PRrSOiSV4+uFOWQuLRQCeKtwG\n0UpKH9fhZnP//tWX66Ispf0=\n=Lray\n-----END PGP SIGNATURE-----\n"
signed: 1
summary: " For a long time the Catalyst Framework has been …"
tags: 
  - 
    perl: 0
  - 
    syntax: 0
  - 
    catalyst: 0
text: "    For a long time the Catalyst Framework has been using code at-\n    tributes to allow users to declare actions that certain URLs get\n    dispatched to. That looks something like this:\n\n      lang:Perl sub base : Chained('/') PathPart('') CaptureArgs(0) {\n      ... } sub index : Chained('base') PathPart('') Args(0) { ... } sub\n      default : Chained('base') PathPart('') Args { ... }\n\n    It's a nice and clean syntax that keeps all important information\n    right next to the method it belongs to.\n\n    However, attributes in perl have a couple of limitations. For one,\n    the interface the perl core provides to use them is horrible and\n    doesn't provide nearly enough information to do a lot of things, but\n    most importantly attributes are just plain strings. That means you\n    will need to parse something like \"Chained('base')\" into (Chained =>\n    'base') yourself to make proper use of them.\n\n    While that's easy for the above example, it can be very hard in the\n    general case because only perl can parse Perl. It's one of the rea-\n    sons you can't use Catalyst::Controller::ActionRole to apply parame-\n    terized roles to your action instances, because parsing parameters\n    out of things like Does(SomeRole => { names => [qw/affe tiger/], an-\n    swer_re => qr/42/ }) would be awful and wrong.\n\n    With Catalyst 5.8 most of the attribute related code has been re-\n    moved from the internals. It's now using MooseX::MethodAttributes to\n    do all the heavy lifting. Also the internals of how actions are reg-\n    istered have been refactored to make it easier to implement alter-\n    nate ways without changing the Catalyst core.\n\n    As a proof of concept for this I implemented a new way of declaring\n    actions that's very similar to how Moose provides it's sugar func-\n    tions. You can get it from github.\n\n    With that, the above example looks like this:\n\n      lang:Perl action base => (Chained => '/', PathPart => '', Cap-\n      tureArgs => 0) => sub { ... }; action index => (Chained => 'base',\n      PathPart => '', Args => 0 ) => sub { ... }; action default =>\n      (Chained => 'base', PathPart => '', Args => undef) => sub { ... };\n\n    It also moves method declaration from compiletime to runtime, making\n    this possible:\n\n      lang:Perl for my $action (qw/foo bar baz/) { action $action =>\n      (Chained => 'somewhere', Args => 0) => sub { my ($self, $ctx) =\n      @_; $ctx->stash->{ $action } = $ctx->model('Foo')->get_stuff($ac-\n      tion); }; }\n\n    Admittedly, that's all very ugly, but illustrates well what kind of\n    things we're able to do now. But it doesn't need to be ugly. With\n    Devel::Declare we have a great tool to add our own awesome syntax to\n    perl, similar to how things like MooseX::Method::Signatures,\n    MooseX::MultiMethods and MooseX::Declare do.\n\n    So how would a declarative syntax for Catalyst controllers look\n    like? I don't know. Ideas include something like this:\n\n      under /some/where, action foo ('foo', $id) { ... }\n\n    to mean:\n\n      sub foo : Chained('/some/where') PathPart('foo') Cap-\n      tureArgs(1) { ... }\n\n    Adding Moose type constraints to this would be interesting, too, and\n    make validation of captures and arguments a lot easier. Multi dis-\n    patch similar to MooseX::MultiMethods could be handy as well:\n\n      under /some/where { action ('foo', Int $id) {\n              # find and stash an item by id\n          } action ('foo', Str $name) {\n              # search items using $name\n          } action ('foo', Any $thing) {\n              # display error page\n          } }\n\n    So you see there are a lot of possibilities that should be ex-\n    plored. Unfortunately I have no idea what kind of syntax and fea-\n    tures people would like to have, so your feedback on this would be\n    much appreciated.\n    :-)\n"
title: Declaring Catalyst Actions
type: pod
uri: http://perldition.org/articles/Declaring%20Catalyst%20Actions.pod
xhtml: "<div class=\"pod\">\n<p>For a long time the <a href=\"http://catalystframework.org\">Catalyst Framework</a> has been using code attributes\nto allow users to declare actions that certain URLs get dispatched to.\nThat looks something like this:</p>\n<pre><span class=\"Keyword\">sub </span><span class=\"Function\">base</span><span class=\"Normal\">    : Chained(</span><span class=\"Operator\">&apos;</span><span class=\"String\">/</span><span class=\"Operator\">&apos;</span><span class=\"Normal\">)    PathPart(</span><span class=\"Operator\">&apos;&apos;</span><span class=\"Normal\">) CaptureArgs(0) { ... }</span><span class=\"Normal\">\n</span><span class=\"Keyword\">sub </span><span class=\"Function\">index</span><span class=\"Normal\">   : Chained(</span><span class=\"Operator\">&apos;</span><span class=\"String\">base</span><span class=\"Operator\">&apos;</span><span class=\"Normal\">) PathPart(</span><span class=\"Operator\">&apos;&apos;</span><span class=\"Normal\">) Args(0)        { ... }</span><span class=\"Normal\">\n</span><span class=\"Keyword\">sub </span><span class=\"Function\">default</span><span class=\"Normal\"> : Chained(</span><span class=\"Operator\">&apos;</span><span class=\"String\">base</span><span class=\"Operator\">&apos;</span><span class=\"Normal\">) PathPart(</span><span class=\"Operator\">&apos;&apos;</span><span class=\"Normal\">) Args           { ... }</span>\n</pre>\n<p>It's a nice and clean syntax that keeps all important information\nright next to the method it belongs to.</p>\n<p>However, attributes in perl have a couple of limitations. For one, the\ninterface the perl core provides to use them is horrible and doesn't\nprovide nearly enough information to do a lot of things, but most\nimportantly attributes are just plain strings. That means you will\nneed to parse something like <code>&quot;Chained('base')&quot;</code> into\n<code>(Chained =&gt; 'base')</code> yourself to make proper use of them.</p>\n<p>While that's easy for the above example, it can be very hard in the\ngeneral case because only perl can parse Perl. It's one of the reasons\nyou can't use <a href=\"http://search.cpan.org/perldoc?Catalyst::Controller::ActionRole\">Catalyst::Controller::ActionRole</a> to apply\nparameterized roles to your action instances, because parsing\nparameters out of things like\n<code>Does(SomeRole =&gt; { names =&gt; [qw/affe tiger/], answer_re =&gt; qr/42/ })</code>\nwould be awful and wrong.</p>\n<p>With Catalyst 5.8 most of the attribute related code has been removed\nfrom the internals. It's now using <a href=\"http://search.cpan.org/perldoc?MooseX::MethodAttributes\">MooseX::MethodAttributes</a> to do\nall the heavy lifting. Also the internals of how actions are\nregistered have been refactored to make it easier to implement\nalternate ways without changing the Catalyst core.</p>\n<p>As a proof of concept for this I implemented a new way of declaring\nactions that's very similar to how <a href=\"http://search.cpan.org/perldoc?Moose\">Moose</a> provides it's sugar\nfunctions. You can get it from\n<a href=\"http://github.com/rafl/catalystx-actions/tree\">github</a>.</p>\n<p>With that, the above example looks like this:</p>\n<pre><span class=\"Normal\">action base    =&gt; (Chained =&gt; </span><span class=\"Operator\">&apos;</span><span class=\"String\">/</span><span class=\"Operator\">&apos;</span><span class=\"Normal\">,    PathPart =&gt; </span><span class=\"Operator\">&apos;&apos;</span><span class=\"Normal\">, CaptureArgs =&gt; 0) =&gt; </span><span class=\"Keyword\">sub </span><span class=\"Normal\">{ ... };</span><span class=\"Normal\">\n</span><span class=\"Normal\">action </span><span class=\"Function\">index</span><span class=\"Normal\">   =&gt; (Chained =&gt; </span><span class=\"Operator\">&apos;</span><span class=\"String\">base</span><span class=\"Operator\">&apos;</span><span class=\"Normal\">, PathPart =&gt; </span><span class=\"Operator\">&apos;&apos;</span><span class=\"Normal\">, Args    =&gt; 0    ) =&gt; </span><span class=\"Keyword\">sub </span><span class=\"Normal\">{ ... };</span><span class=\"Normal\">\n</span><span class=\"Normal\">action default =&gt; (Chained =&gt; </span><span class=\"Operator\">&apos;</span><span class=\"String\">base</span><span class=\"Operator\">&apos;</span><span class=\"Normal\">, PathPart =&gt; </span><span class=\"Operator\">&apos;&apos;</span><span class=\"Normal\">, Args    =&gt; </span><span class=\"Function\">undef</span><span class=\"Normal\">) =&gt; </span><span class=\"Keyword\">sub </span><span class=\"Normal\">{ ... };</span>\n\n\n</pre>\n<p>It also moves method declaration from compiletime to runtime, making\nthis possible:</p>\n<pre><span class=\"Keyword\">for</span><span class=\"Normal\"> </span><span class=\"Keyword\">my</span><span class=\"Normal\"> </span><span class=\"DataType\">$action</span><span class=\"Normal\"> (</span><span class=\"Operator\">qw/</span><span class=\"Normal\">foo bar baz</span><span class=\"Operator\">/</span><span class=\"Normal\">) {</span><span class=\"Normal\">\n</span><span class=\"Normal\">    action </span><span class=\"DataType\">$action</span><span class=\"Normal\"> =&gt; (Chained =&gt; </span><span class=\"Operator\">&apos;</span><span class=\"String\">somewhere</span><span class=\"Operator\">&apos;</span><span class=\"Normal\">, Args =&gt; 0) =&gt; </span><span class=\"Keyword\">sub </span><span class=\"Normal\">{</span><span class=\"Normal\">\n</span><span class=\"Normal\">        </span><span class=\"Keyword\">my</span><span class=\"Normal\"> (</span><span class=\"DataType\">$self</span><span class=\"Normal\">, </span><span class=\"DataType\">$ctx</span><span class=\"Normal\">) = </span><span class=\"DataType\">@_</span><span class=\"Normal\">;</span><span class=\"Normal\">\n</span><span class=\"Normal\">        </span><span class=\"DataType\">$ctx</span><span class=\"Normal\">-&gt;</span><span class=\"DataType\">stash</span><span class=\"Normal\">-&gt;{ </span><span class=\"DataType\">$action</span><span class=\"Normal\"> } = </span><span class=\"DataType\">$ctx</span><span class=\"Normal\">-&gt;</span><span class=\"DataType\">model</span><span class=\"Normal\">(</span><span class=\"Operator\">&apos;</span><span class=\"String\">Foo</span><span class=\"Operator\">&apos;</span><span class=\"Normal\">)</span><span class=\"Operator\">-</span><span class=\"Normal\">&gt;get_stuff(</span><span class=\"DataType\">$action</span><span class=\"Normal\">);</span><span class=\"Normal\">\n</span><span class=\"Normal\">    };</span><span class=\"Normal\">\n</span><span class=\"Normal\">}</span>\n</pre>\n<p>Admittedly, that's all very ugly, but illustrates well what kind of\nthings we're able to do now. But it doesn't need to be ugly. With\n<a href=\"http://search.cpan.org/perldoc?Devel::Declare\">Devel::Declare</a> we have a great tool to add our own awesome syntax\nto perl, similar to how things like <a href=\"http://search.cpan.org/perldoc?MooseX::Method::Signatures\">MooseX::Method::Signatures</a>,\n<a href=\"http://search.cpan.org/perldoc?MooseX::MultiMethods\">MooseX::MultiMethods</a> and <a href=\"http://search.cpan.org/perldoc?MooseX::Declare\">MooseX::Declare</a> do.</p>\n<p>So how would a declarative syntax for Catalyst controllers look like?\nI don't know. Ideas include something like this:</p>\n<pre><span class=\"Normal\">under /some/where, action foo (</span><span class=\"Operator\">&apos;</span><span class=\"String\">foo</span><span class=\"Operator\">&apos;</span><span class=\"Normal\">, </span><span class=\"DataType\">$id</span><span class=\"Normal\">) { ... }</span>\n</pre>\n<p>to mean:</p>\n<pre><span class=\"Keyword\">sub </span><span class=\"Function\">foo</span><span class=\"Normal\"> : Chained(</span><span class=\"Operator\">&apos;</span><span class=\"String\">/some/where</span><span class=\"Operator\">&apos;</span><span class=\"Normal\">) PathPart(</span><span class=\"Operator\">&apos;</span><span class=\"String\">foo</span><span class=\"Operator\">&apos;</span><span class=\"Normal\">) CaptureArgs(</span><span class=\"Float\">1</span><span class=\"Normal\">) { ... }</span>\n</pre>\n<p>Adding Moose type constraints to this would be interesting, too, and\nmake validation of captures and arguments a lot easier. Multi dispatch\nsimilar to MooseX::MultiMethods could be handy as well:</p>\n<pre><span class=\"Normal\">under /some/where {</span><span class=\"Normal\">\n</span><span class=\"Normal\">    action (</span><span class=\"Operator\">&apos;</span><span class=\"String\">foo</span><span class=\"Operator\">&apos;</span><span class=\"Normal\">, </span><span class=\"Function\">Int</span><span class=\"Normal\"> </span><span class=\"DataType\">$id</span><span class=\"Normal\">) {</span><span class=\"Normal\">\n</span><span class=\"Normal\">        </span><span class=\"Comment\"># find and stash an item by id</span><span class=\"Comment\">\n</span><span class=\"Normal\">    }</span><span class=\"Normal\">\n</span><span class=\"Normal\">    action (</span><span class=\"Operator\">&apos;</span><span class=\"String\">foo</span><span class=\"Operator\">&apos;</span><span class=\"Normal\">, Str </span><span class=\"DataType\">$name</span><span class=\"Normal\">) {</span><span class=\"Normal\">\n</span><span class=\"Normal\">        </span><span class=\"Comment\"># search items using $name</span><span class=\"Comment\">\n</span><span class=\"Normal\">    }</span><span class=\"Normal\">\n</span><span class=\"Normal\">    action (</span><span class=\"Operator\">&apos;</span><span class=\"String\">foo</span><span class=\"Operator\">&apos;</span><span class=\"Normal\">, Any </span><span class=\"DataType\">$thing</span><span class=\"Normal\">) {</span><span class=\"Normal\">\n</span><span class=\"Normal\">        </span><span class=\"Comment\"># display error page</span><span class=\"Comment\">\n</span><span class=\"Normal\">    }</span><span class=\"Normal\">\n</span><span class=\"Normal\">}</span>\n</pre>\n<p>So you see there are a lot of possibilities that should be\nexplored. Unfortunately I have no idea what kind of syntax and\nfeatures people would like to have, so your feedback on this would be\nmuch appreciated. :-)</p>\n\n\n</div>"
