use Catalyst::ActionChain;
use URI;
+# please don't perltidy this. hairy code within.
+
=head1 NAME
-Catalyst::DispatchType::Path - Path DispatchType
+Catalyst::DispatchType::ChildOf - Path Part DispatchType
=head1 SYNOPSIS
Debug output for Path Part dispatch points
-Matt is an idiot and hasn't implemented this yet.
-
=cut
-#sub list {
-# my ( $self, $c ) = @_;
-# my $paths = Text::SimpleTable->new( [ 35, 'Path' ], [ 36, 'Private' ] );
-# foreach my $path ( sort keys %{ $self->{paths} } ) {
-# foreach my $action ( @{ $self->{paths}->{$path} } ) {
-# $path = "/$path" unless $path eq '/';
-# $paths->row( "$path", "/$action" );
-# }
-# }
-# $c->log->debug( "Loaded Path actions:\n" . $paths->draw )
-# if ( keys %{ $self->{paths} } );
-#}
+sub list {
+ my ( $self, $c ) = @_;
+
+ return unless $self->{endpoints};
+
+ my $paths = Text::SimpleTable->new(
+ [ 35, 'Path Spec' ], [ 36, 'Private' ]
+ );
+
+ ENDPOINT: foreach my $endpoint (
+ sort { $a->reverse cmp $b->reverse }
+ @{ $self->{endpoints} }
+ ) {
+ my $args = $endpoint->attributes->{Args}->[0];
+ my @parts = (defined($args) ? (("*") x $args) : '...');
+ my $parent = "DUMMY";
+ my $curr = $endpoint;
+ while ($curr) {
+ if (my $cap = $curr->attributes->{Captures}) {
+ unshift(@parts, (("*") x $cap->[0]));
+ }
+ if (my $pp = $curr->attributes->{PartPath}) {
+ unshift(@parts, $pp->[0])
+ if (defined $pp->[0] && length $pp->[0]);
+ }
+ $parent = $curr->attributes->{ChildOf}->[0];
+ $curr = $self->{actions}{$parent};
+ }
+ next ENDPOINT unless $parent eq '/'; # skip dangling action
+ $paths->row(join('/', '', @parts), "/$endpoint");
+ }
+
+ $c->log->debug( "Loaded Path Part actions:\n" . $paths->draw );
+}
=head2 $self->match( $c, $path )
next TRY unless
($try_part eq join('/', # assemble equal number of parts
splice( # and strip them off @parts as well
- @parts, 0, scalar(split('/', $try_part))
- )));
+ @parts, 0, scalar(@{[split('/', $try_part)]})
+ ))); # @{[]} to avoid split to @_
}
my @try_actions = @{$children->{$try_part}};
TRY_ACTION: foreach my $action (@try_actions) {
$parent = '/'.$action->namespace;
}
+ $action->attributes->{ChildOf} = [ $parent ];
+
my $children = ($self->{children_of}{$parent} ||= {});
my @path_part = @{ $action->attributes->{PathPart} || [] };
);
}
+ $action->attributes->{PartPath} = [ $part ];
+
unshift(@{ $children->{$part} ||= [] }, $action);
+ ($self->{actions} ||= {})->{'/'.$action->reverse} = $action;
+
+ if ($action->attributes->{Args}) {
+ unshift(@{ $self->{endpoints} ||= [] }, $action);
+ }
+
+ return 1;
}
=head2 $self->uri_for_action($action, $captures)
sub uri_for_action {
my ( $self, $action, $captures ) = @_;
- return undef if @$captures;
-
- if (my $paths = $action->attributes->{Path}) {
- my $path = $paths->[0];
- $path = '/' unless length($path);
- $path = "/${path}" unless ($path =~ m/^\//);
- $path = URI->new($path)->canonical;
- return $path;
- } else {
- return undef;
+ return undef unless ($action->attributes->{ChildOf}
+ && $action->attributes->{Args});
+
+ my @parts = ();
+ my @captures = @$captures;
+ my $parent = "DUMMY";
+ my $curr = $action;
+ while ($curr) {
+ if (my $cap = $curr->attributes->{Captures}) {
+ return undef unless @captures >= $cap->[0]; # not enough captures
+ unshift(@parts, splice(@captures, -$cap->[0]));
+ }
+ if (my $pp = $curr->attributes->{PartPath}) {
+ unshift(@parts, $pp->[0])
+ if (defined $pp->[0] && length $pp->[0]);
+ }
+ $parent = $curr->attributes->{ChildOf}->[0];
+ $curr = $self->{actions}{$parent};
}
+
+ return undef unless $parent eq '/'; # fail for dangling action
+
+ return undef if @captures; # fail for too many captures
+
+ return join('/', '', @parts);
+
}
=head1 AUTHOR
-Matt S Trout
-Sebastian Riedel, C<sri@cpan.org>
+Matt S Trout <mst@shadowcatsystems.co.uk>
=head1 COPYRIGHT
use Test::More;
-plan tests => 12;
+plan tests => 17;
use_ok('TestApp');
ok(!defined($dispatcher->uri_for_action($regex_action)),
"Regex action without captures returns undef");
+ok(!defined($dispatcher->uri_for_action($regex_action, [ 1, 2, 3 ])),
+ "Regex action with too many captures returns undef");
+
is($dispatcher->uri_for_action($regex_action, [ 'foo', 123 ]),
"/action/regexp/foo/123",
"Regex action interpolates captures correctly");
"/action/index",
"index action returns correct path");
+my $childof_action = $dispatcher->get_action_by_path(
+ '/action/childof/endpoint',
+ );
+
+ok(!defined($dispatcher->uri_for_action($childof_action)),
+ "ChildOf action without captures returns undef");
+
+ok(!defined($dispatcher->uri_for_action($childof_action, [ 1, 2 ])),
+ "ChildOf action with too many captures returns undef");
+
+is($dispatcher->uri_for_action($childof_action, [ 1 ]),
+ "/childof/foo/1/end",
+ "ChildOf action with correct captures returns correct path");
+
my $request = Catalyst::Request->new( {
base => URI->new('http://127.0.0.1/foo')
} );
is($context->uri_for($regex_action, [ 'foo', 123 ], qw/bar baz/, { q => 1 }),
"http://127.0.0.1/foo/action/regexp/foo/123/bar/baz?q=1",
"uri_for correct for regex with captures, args and query");
+
+is($context->uri_for($childof_action, [ 1 ], 2, { q => 1 }),
+ "http://127.0.0.1/foo/childof/foo/1/end/2?q=1",
+ "uri_for correct for childof with captures, args and query");