Skip to content

Commit

Permalink
Add order to route patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
bbrtj committed Oct 7, 2024
1 parent 489339e commit 369c50e
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 6 deletions.
1 change: 1 addition & 0 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Revision history for Kelp
{{$NEXT}}
[New Interface]
- Added after_unrendered hook to Kelp
- Added order key to routes

[Changes]
- Hooks are now run conditionally on controller objects and fall back to main app object
Expand Down
13 changes: 13 additions & 0 deletions lib/Kelp/Manual.pod
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,19 @@ route in line to be processed.

See L<Kelp::Routes/BRIDGES> for more information.

=head3 Route order

Routes will be executed in order that will usually be the one you want. Bridges
will execute before normal routes, and the routes will be sorted by patterns
using Perl C<cmp>. However, you can sometimes run into trouble with their ordering.

In that case, you can use special key C<order> to sort it out. All routes have
default C<order> of C<0>. If you want some of them to execute earlier, reduce
their order value. Late routes can be marked with positive order.

Of course, even if you specify order, bridges will still always come before
regular routes.

=head3 URL building

Each path can be given a name and later a URL can be built using that name and
Expand Down
2 changes: 1 addition & 1 deletion lib/Kelp/Routes.pm
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ sub match
# chain. If the patterns are not the same, their order will be changed
# by string sorting by patterns.
@$routes =
sort { $b->bridge <=> $a->bridge || $a->pattern cmp $b->pattern }
sort { $a->compare($b) }
grep { $_->match($path, $method) } @{$self->routes};

$self->cache->set($key, $routes);
Expand Down
21 changes: 21 additions & 0 deletions lib/Kelp/Routes/Pattern.pm
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ attr name => sub { $_[0]->pattern };
attr check => sub { {} };
attr defaults => sub { {} };
attr bridge => 0;
attr order => 0;
attr regex => sub { $_[0]->_build_regex };
attr named => sub { {} };
attr param => sub { [] };
Expand Down Expand Up @@ -226,6 +227,15 @@ sub match
return 1;
}

sub compare
{
my ($self, $other) = @_;

return $other->bridge <=> $self->bridge
|| $self->order <=> $other->order
|| $self->pattern cmp $other->pattern;
}

1;

__END__
Expand Down Expand Up @@ -331,6 +341,11 @@ of them, it will be used in case the placeholder value is missing.
A True/False value. Specifies if the route is a bridge. For more information
about bridges, please see L<Kelp::Routes/BRIDGES>
=head2 order
A numeric order of this route. Default order is C<0>, so if you want some
routes to take priority, you can use C<-1>. Lower is earlier.
=head2 regex
We recommend that you stick to using patterns, because they are simpler and
Expand Down Expand Up @@ -403,6 +418,12 @@ should be built like this:
If the pattern contains more than one unnamed items, then you should
probably give them some names.
=head2 compare
C<$compare( $other )>
Compares two routes. Used for sorting matched routes in a router.
=head1 ACKNOWLEDGEMENTS
This module was inspired by L<Routes::Tiny>.
Expand Down
10 changes: 5 additions & 5 deletions t/routes_match.t
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ my $r = Kelp::Routes->new;
# Similar routes with checks
{
$r->clear;
$r->add('/:a/:b' => 'a#b');
$r->add('/:a/:b' => {to => 'a#b', order => 10});
$r->add('/:a/:b' => {to => 'a#c', check => {b => '\d+'}});
$r->add('/:a/:b' => {to => 'a#d', check => {a => '\d+'}});
$r->add('/:a/:b' => {to => 'a#d', check => {a => '\d+'}, order => -1});
is_deeply _d($r->match('/aa/bb'), 'to'), [{to => 'A::b'}];
is_deeply _d($r->match('/aa/22'), 'to'), [{to => 'A::b'}, {to => 'A::c'}];
is_deeply _d($r->match('/11/bb'), 'to'), [{to => 'A::b'}, {to => 'A::d'}];
is_deeply _d($r->match('/11/22'), 'to'), [{to => 'A::b'}, {to => 'A::c'}, {to => 'A::d'}];
is_deeply _d($r->match('/aa/22'), 'to'), [{to => 'A::c'}, {to => 'A::b'}];
is_deeply _d($r->match('/11/bb'), 'to'), [{to => 'A::d'}, {to => 'A::b'}];
is_deeply _d($r->match('/11/22'), 'to'), [{to => 'A::d'}, {to => 'A::c'}, {to => 'A::b'}];
}

# Different routes (same beginning)
Expand Down

0 comments on commit 369c50e

Please sign in to comment.