FAQ
Hi,

I believe I've discovered a bug in Catalyst::Controller. I triggered it
while using Catalyst::Controller::ActionRole so my examples below will
refer to that module.

If I have a Catalyst controller with a configuration like the following:

__PACKAGE->config(
action => {
some_action => { Does => [ '+Some:ActionRole' ] }
}
);


This will break *if* the Action module that processes the 'Does' attribute
changes the value that is passed to it. For a real world example of this see
Catalyst::Controller::ActionRole which changes the value passed to its
_parse_Does_attr method.

The _parse_attrs method in Catalyst::Controller does the following:

[...]
foreach my $key (keys %raw_attributes) {

my $raw = $raw_attributes{$key};

foreach my $value (ref($raw) eq 'ARRAY' ? @$raw : $raw) {

my $meth = "_parse_${key}_attr";
if ( my $code = $self->can($meth) ) {
( $key, $value ) = $self->$code( $c, $name, $value );
}
push( @{ $final_attributes{$key} }, $value );
}
}
[...]

The problem lies in the inner foreach. When $row is an array reference (and
only when $row is an array reference) $value will be an *alias* to each element
of that array. So if $value is changed within the attribute parsing method
this means that the next time this attribute parsing method is called the
$value passed to it will be the changed value...but this only occurs when
using a configuration like what I pasted above because the actual configuration
hash gets changed. I don't recall which perl introduced aliasing, but I use
perl 5.10.1.

Here is a simple patch which resolves the issue:

--- Controller.pm 2010-07-28 15:03:32.000000000 -0700
+++ Controller.pm.bak 2011-02-02 16:55:47.000000000 -0800
@@ -322,11 +322,12 @@

foreach my $value (ref($raw) eq 'ARRAY' ? @$raw : $raw) {

+ my $t_val = $value;
my $meth = "_parse_${key}_attr";
if ( my $code = $self->can($meth) ) {
- ( $key, $value ) = $self->$code( $c, $name, $value );
+ ( $key, $t_val ) = $self->$code( $c, $name, $t_val );
}
- push( @{ $final_attributes{$key} }, $value );
+ push( @{ $final_attributes{$key} }, $t_val );
}
}


A workaround, at least when using Catalyst::Controller::ActionRole, is
to not use the array ref syntax:

__PACKAGE->config(
action => {
some_action => { Does => '+Some:ActionRole' }
}
);


Of course this workaround isn't useful if you want to apply multiple roles to
an action.

I can probably provide a program that demonstrates this, but I've found
that writing a 'simple' Catalyst application requires a lot of setup. :o/

Catalyst::Runtime 5.80031
Catalyst::Controller::ActionRole 0.15

--
seth /\ sethdaniel.org

Search Discussions

  • Seth Daniel at Feb 4, 2011 at 7:01 pm

    On Thu, Feb 03, 2011 at 09:15:03AM -0800, Seth Daniel wrote:
    Hi,

    I believe I've discovered a bug in Catalyst::Controller. I triggered it
    while using Catalyst::Controller::ActionRole so my examples below will
    refer to that module.
    [...snip...]
    I can probably provide a program that demonstrates this, but I've found
    that writing a 'simple' Catalyst application requires a lot of setup. :o/

    http://doubleplusgood.org/ccbug.tar

    I whittled down the Catalyst::Controller::ActionRole tests to as few
    files as I could.

    Unpack the tar file and cd to the 't' dir.

    Run 'prove execution-via-config.t'. It should fail with the bug I
    reported.

    You can get the test to pass if you change
    t/lib/TestApp/Controller/ExecutionViaConfig.pm to apply the '+Moo' role
    like so:

    __PACKAGE__->config(
    action => {
    three => { Does => '+Moo' }
    }
    );

    --
    seth /\ sethdaniel.org

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupcatalyst @
categoriescatalyst, perl
postedFeb 3, '11 at 5:15p
activeFeb 4, '11 at 7:01p
posts2
users1
websitecatalystframework.org
irc#catalyst

1 user in discussion

Seth Daniel: 2 posts

People

Translate

site design / logo © 2021 Grokbase