X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Runtime.git;a=blobdiff_plain;f=lib%2FCatalyst%2FDispatchType%2FChained.pm;h=e29e5b5916d4fdaa1b26cba8390cca4786f49bcd;hp=d1ac624a5b6cfd66a88e7a5d6df52801e0466e82;hb=342d21698a97962c51114b6ebc6bb8626511cfc6;hpb=cedb28e88e0c62feee5d99ea4f2ed1813a858f5e diff --git a/lib/Catalyst/DispatchType/Chained.pm b/lib/Catalyst/DispatchType/Chained.pm index d1ac624..e29e5b5 100644 --- a/lib/Catalyst/DispatchType/Chained.pm +++ b/lib/Catalyst/DispatchType/Chained.pm @@ -8,6 +8,7 @@ use Catalyst::ActionChain; use Catalyst::Utils; use URI; use Scalar::Util (); +use Encode 2.21 'decode_utf8'; has _endpoints => ( is => 'rw', @@ -101,6 +102,8 @@ sub list { my @parents = (); my $parent = "DUMMY"; my $extra = $self->_list_extra_http_methods($endpoint); + my $consumes = $self->_list_extra_consumes($endpoint); + my $scheme = $self->_list_extra_scheme($endpoint); my $curr = $endpoint; while ($curr) { if (my $cap = $curr->list_extra_info->{CaptureArgs}) { @@ -129,13 +132,21 @@ sub list { if (defined(my $cap = $p->list_extra_info->{CaptureArgs})) { $name .= ' ('.$cap.')'; } + if (defined(my $ct = $p->list_extra_info->{Consumes})) { + $name .= ' :'.$ct; + } + if (defined(my $s = $p->list_extra_info->{Scheme})) { + $scheme = uc $s; + } + unless ($p eq $parents[0]) { $name = "-> ${name}"; } push(@rows, [ '', $name ]); } - push(@rows, [ '', (@rows ? "=> " : '').($extra ? "$extra " : '')."/${endpoint}" ]); - $rows[0][0] = join('/', '', @parts) || '/'; + push(@rows, [ '', (@rows ? "=> " : '').($extra ? "$extra " : ''). ($scheme ? "$scheme: ":'')."/${endpoint}". ($consumes ? " :$consumes":"" ) ]); + my @display_parts = map { $_ =~s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg; decode_utf8 $_ } @parts; + $rows[0][0] = join('/', '', @display_parts) || '/'; $paths->row(@$_) for @rows; } @@ -148,6 +159,19 @@ sub _list_extra_http_methods { my ( $self, $action ) = @_; return unless defined $action->list_extra_info->{HTTP_METHODS}; return join(', ', @{$action->list_extra_info->{HTTP_METHODS}}); + +} + +sub _list_extra_consumes { + my ( $self, $action ) = @_; + return unless defined $action->list_extra_info->{CONSUMES}; + return join(', ', @{$action->list_extra_info->{CONSUMES}}); +} + +sub _list_extra_scheme { + my ( $self, $action ) = @_; + return unless defined $action->list_extra_info->{Scheme}; + return uc $action->list_extra_info->{Scheme}; } =head2 $self->match( $c, $path ) @@ -212,16 +236,16 @@ sub recurse_match { my @try_actions = @{$children->{$try_part}}; TRY_ACTION: foreach my $action (@try_actions) { if (my $capture_attr = $action->attributes->{CaptureArgs}) { - $capture_attr ||= 0; + my $capture_count = $capture_attr->[0] || 0; # Short-circuit if not enough remaining parts - next TRY_ACTION unless @parts >= $capture_attr->[0]; + next TRY_ACTION unless @parts >= $capture_count; my @captures; my @parts = @parts; # localise # strip CaptureArgs into list - push(@captures, splice(@parts, 0, $capture_attr->[0])); + push(@captures, splice(@parts, 0, $capture_count)); # check if the action may fit, depending on a given test by the app if ($action->can('match_captures')) { next TRY_ACTION unless $action->match_captures($c, \@captures) } @@ -285,6 +309,32 @@ Calls register_path for every Path attribute for the given $action. =cut +sub _check_args_attr { + my ( $self, $action, $name ) = @_; + + return unless exists $action->attributes->{$name}; + + if (@{$action->attributes->{$name}} > 1) { + Catalyst::Exception->throw( + "Multiple $name attributes not supported registering " . $action->reverse() + ); + } + my $args = $action->attributes->{$name}->[0]; + if (defined($args) and not ( + Scalar::Util::looks_like_number($args) and + int($args) == $args and $args >= 0 + )) { + require Data::Dumper; + local $Data::Dumper::Terse = 1; + local $Data::Dumper::Indent = 0; + $args = Data::Dumper::Dumper($args); + Catalyst::Exception->throw( + "Invalid $name($args) for action " . $action->reverse() . + " (use '$name' or '$name()')" + ); + } +} + sub register { my ( $self, $c, $action ) = @_; @@ -323,27 +373,24 @@ sub register { ); } - $action->attributes->{PathPart} = [ $part ]; + my $encoded_part = URI->new($part)->canonical; + $encoded_part =~ s{(?<=[^/])/+\z}{}; - unshift(@{ $children->{$part} ||= [] }, $action); + $action->attributes->{PathPart} = [ $encoded_part ]; + + unshift(@{ $children->{$encoded_part} ||= [] }, $action); $self->_actions->{'/'.$action->reverse} = $action; - if (exists $action->attributes->{Args}) { - my $args = $action->attributes->{Args}->[0]; - if (defined($args) and not ( - Scalar::Util::looks_like_number($args) and - int($args) == $args - )) { - require Data::Dumper; - local $Data::Dumper::Terse = 1; - local $Data::Dumper::Indent = 0; - $args = Data::Dumper::Dumper($args); - Catalyst::Exception->throw( - "Invalid Args($args) for action " . $action->reverse() . - " (use 'Args' or 'Args()')" - ); - } + foreach my $name (qw(Args CaptureArgs)) { + $self->_check_args_attr($action, $name); + } + + if (exists $action->attributes->{Args} and exists $action->attributes->{CaptureArgs}) { + Catalyst::Exception->throw( + "Combining Args and CaptureArgs attributes not supported registering " . + $action->reverse() + ); } unless ($action->attributes->{CaptureArgs}) { @@ -685,9 +732,11 @@ of the endpoint of the chain, not on the chained actions way. The C actions will be run before the chain dispatching begins. In every other aspect, C actions behave as documented. -The Cing to other actions does just what you would expect. But if -you C out of a chain, the rest of the chain will not get called -after the C. +The Cing to other actions does just what you would expect. i.e. +only the target action is run. The actions that that action is chained +to are not run. +If you C out of a chain, the rest of the chain will not get +called after the C. =head2 match_captures