Skip to content

Commit

Permalink
Named routes:
Browse files Browse the repository at this point in the history
You can now give names to the routes:

    get NAME, PATH, sub {...};

Or the lesser-known one:

    get NAME, PATH, OPTIONS_HASHREF, sub {...};

The PATH, as before, can be a string (matching our spec) or a full
regular expression.

If you do not give a name, a globally incrementing number will
be used. I'm not sure that's the best idea but it's a unique
identified that, if leaks, does not say which App this is part of.

This should lend in the future to allow `uri_for` (or a different
DSL keyword) to use the name of a route instead of the path:

End result should look something like this:

    # MyApp.pm
    get 'view_product', '/view/product/:id' => sub {...};

    # in template:
    <% uri_for( 'view_product', { id => 4 } ); %>

We're getting there...
  • Loading branch information
xsawyerx committed Oct 10, 2016
1 parent a803b0a commit 6ce9112
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 5 deletions.
21 changes: 16 additions & 5 deletions lib/Dancer2/Core/DSL.pm
Original file line number Diff line number Diff line change
Expand Up @@ -232,11 +232,22 @@ sub _normalize_route {
my $methods = shift;
my %args;

# Options are optional, deduce their presence from arg length.
# @_ = ( REGEXP, OPTIONS, CODE )
# or
# @_ = ( REGEXP, CODE )
@args{qw/regexp options code/} = @_ == 3 ? @_ : ( $_[0], {}, $_[1] );
# Options are optional, try to deduce their presence from arg length.
if ( @_ == 4 ) {
# @_ = ( NAME, REGEXP, OPTIONS, CODE )
@args{qw<name regexp options code>} = @_;
} elsif ( @_ == 2 ) {
# @_ = ( REGEXP, CODE )
@args{qw<regexp options code>} = ( $_[0], {}, $_[1] );
} elsif ( @_ == 3 ) {
# @_ = ( REGEXP, OPTIONS, CODE )
# @_ = ( NAME, REGEXP, CODE )
if (ref $_[1] eq 'HASH') {
@args{qw<regexp options code>} = @_;
} else {
@args{qw<name regexp code>} = @_;
}
}

return map $app->add_route( %args, method => $_ ), @{$methods};
}
Expand Down
8 changes: 8 additions & 0 deletions lib/Dancer2/Core/Route.pm
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ use Scalar::Util 'blessed';

our ( $REQUEST, $RESPONSE, $RESPONDER, $WRITER, $ERROR_HANDLER );

my $count = 0;

has name => (
is => 'ro',
isa => Str,
default => sub { $count++ },
);

has method => (
is => 'ro',
isa => Dancer2Method,
Expand Down
93 changes: 93 additions & 0 deletions t/named_routes.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use strict;
use warnings;
use Test::More 'tests' => 5;
use Plack::Test;
use HTTP::Request::Common;

{
package MyApp;

use Dancer2;

# Name, Regexp, Code
get 'view_static', '/view' => sub {
'View Static';
};

get 'view_regex', qr{^/view_r$} => sub {
'View Regex'
};

# Name, Regexp, Options, Code
get 'base_static', '/' => { 'user_agent' => 'XX' }, sub {
'Base Static';
};

# Name, Regexp, Options, Code
get 'base_regex', qr{^/r$} => { 'user_agent' => 'XX' }, sub {
'Base Regex';
};

get '/ignore1' => sub {1};
get '/ignore2' => sub {1};
get '/ignore3' => sub {1};
}

my $test = Plack::Test->create( MyApp->to_app );

subtest 'Named route' => sub {
plan 'tests' => 2;

my $response = $test->request( GET '/view' );
ok( $response->is_success, 'Successfully reached /view' );
is( $response->content, 'View Static', 'Static route with name' );
};

subtest 'Named regex route' => sub {
plan 'tests' => 2;

my $response = $test->request( GET '/view_r' );
ok( $response->is_success, 'Successfully reached /view_r' );
is( $response->content, 'View Regex', 'Regex route with name' );
};

subtest 'Named route with options' => sub {
plan 'tests' => 2;

my $response = $test->request( GET '/', 'User-Agent' => 'XX' );
ok( $response->is_success, 'Successfully reached /' );
is($response->content, 'Base Static',
'Static route with name and options');
};

subtest 'Named regex route with options' => sub {
plan 'tests' => 2;

my $response = $test->request( GET '/r', 'User-Agent' => 'XX' );
ok( $response->is_success, 'Successfully reached /r' );
is($response->content, 'Base Regex', 'Regex route with name and options');
};

subtest 'Route objects' => sub {
plan 'tests' => 3;

my @apps = @{ Dancer2::runner->apps };
is( scalar @apps, 1, 'Only one app exists' );

my @routes = @{ $apps[0]->routes->{'get'} };
is( scalar @routes, 7, 'Five routes registered' );

is_deeply(
[ map $_->name, @routes ],
[
'view_static',
'view_regex',
'base_static',
'base_regex',
0, # /ignore1 (0) + HEAD (Plack::Middleware::Head) (1)
2, # /ignore2 (2) + HEAD (Plack::Middleware::Head) (3)
4, # /ignore3 (4) + HEAD (Plack::Middleware::Head) (5)
],
'All the right route names',
);
};

0 comments on commit 6ce9112

Please sign in to comment.