So I've already found a couple glitches/design issues with Catalyst.
Issue #1: Inheritance and actions
Say you have some code like this:
package Parent;
sub end : ActionClass('Stultify') { }
package Child;
use base 'Parent';
sub end : Private { my ( $self, $c ) = @_;
return $self->NEXT::end($c) if $c->stash()->{foo};
... }
$self->NEXT::end()
from Child, you'd expect the Stultify action to get run. But it won't, because of the way Catalyst handles action attributes. The canonical (in my mind) way to implement an attribute (at least that modifies the action of a sub) in Perl is to make a new sub which wrap the original sub and implements the action. Then you take this new sub and replace the old sub in the symbol table. Of course, given a few lexicals and a few attributes, you could create a nice little nested closure leak, but hey, what's some memory between friends?NEXT::end()
does not go back through the Catalyst dispatcher, it goes through NEXT.pm's dispatcher. This means that the Stultify action never gets called. Grr, annoying.Child::end()
, but that kinda defeats the purpose of inheritance!package VegGuide::Controller::Base;
use base 'Catalyst::Controller::REST';
sub end : ActionClass('Serialize')
{
my $self = shift;
my $c = shift;
# This works
return $self->NEXT::end($c)
if $c->stash()->{rest};
# These do not
# $c->detach('Catalyst::Controller::REST');
# $c->detach('Catalyst::Controller::REST', 'end');
if ( ( ! $c->response()->status()
|| $c->response()->status() == 200 )
&& ! $c->response()->body() )
{
return $c->forward( $c->view() );
}
return;
}