Subject: | Adding support for both named and splat() parameters (in the same URI) |
This patch provides support for both named and splat() parameters in the
same URI.
I posted a shorter version of this patch earlier on the dancer-users
list. The patch attached here contains the same code but adds validation
tests.
Subject: | splat.diff |
diff --git a/lib/Dancer/Route.pm b/lib/Dancer/Route.pm
index eaf99b6..7823668 100644
--- a/lib/Dancer/Route.pm
+++ b/lib/Dancer/Route.pm
@@ -300,7 +300,12 @@ sub match {
# if named variables were found, return params accordingly
if (@$variables) {
for (my $i = 0; $i < ~~ @$variables; $i++) {
+ if($variables->[$i] eq 'splat' && $capture) {
+ $params{splat} ||= [];
+ push @{$params{splat}}, $values[$i];
+ } else {
$params{$variables->[$i]} = $values[$i];
+ }
}
return \%params;
}
diff --git a/lib/Dancer/Route/Builder.pm b/lib/Dancer/Route/Builder.pm
index 53ff3f0..ebf428b 100644
--- a/lib/Dancer/Route/Builder.pm
+++ b/lib/Dancer/Route/Builder.pm
@@ -45,20 +45,15 @@ sub make_regexp {
}
else {
# look for route with params (/hello/:foo)
- if ($pattern =~ /:/) {
- @params = $pattern =~ /:([^\/\.]+)/g;
+ if ($pattern =~ /[:*]/) {
+ @params = $pattern =~ /(:[^\/\.]+|\*)/g;
if (@params) {
- $pattern =~ s/(:[^\/\.]+)/\(\[\^\/\]\+\)/g;
+ $pattern =~ s/(:[^\/\.]+|\*)/\(\[\^\/\]\+\)/g;
+ @params = map { /^:(.*)$/ ? $1 : 'splat' } @params;
$capture = 1;
}
}
- # parse wildcards
- if ($pattern =~ /\*/) {
- $pattern =~ s/\*/\(\[\^\/\]\+\)/g;
- $capture = 1;
- }
-
# escape dots
$pattern =~ s/\./\\\./g if $pattern =~ /\./;
}
diff --git a/t/03_route_handler/04_wildcards.t b/t/03_route_handler/04_wildcards.t
index 60d0495..cb4d7d4 100644
--- a/t/03_route_handler/04_wildcards.t
+++ b/t/03_route_handler/04_wildcards.t
@@ -7,7 +7,7 @@ use t::lib::TestUtils;
use Dancer ':syntax';
use Dancer::Route;
-my @paths = ('/hello/*', '/hello/*/welcome/*', '/download/*.*');
+my @paths = ('/hello/*', '/hello/*/welcome/*', '/download/*.*', '/mix/:name/*');
my @tests = (
{path => '/hello/sukria',
@@ -18,6 +18,9 @@ my @tests = (
{path => '/download/wolverine.pdf',
expected => ['wolverine', 'pdf']},
+
+ {path => '/mix/alexis/sukrieh',
+ expected => ['sukrieh']},
);
my $nb_tests = (scalar(@paths)) + (scalar(@tests) * 2);
diff --git a/t/03_route_handler/24_multiple_params.t b/t/03_route_handler/24_multiple_params.t
index acb8736..050f273 100644
--- a/t/03_route_handler/24_multiple_params.t
+++ b/t/03_route_handler/24_multiple_params.t
@@ -1,7 +1,7 @@
use strict;
use warnings;
-use Test::More tests => 26*2+9, import => ['!pass'];
+use Test::More tests => 38*2+11, import => ['!pass'];
use t::lib::TestUtils;
@@ -14,10 +14,10 @@ use Dancer::Config 'setting';
ok(get('/' => sub { 'index' }), 'first route set');
ok(get('/name/:name' => sub { params->{name} }), 'second route set');
ok(get('/name/:name/:location' => sub { params->{name} }), 'third route set');
-# ok(get('/name/:name/:location/*' => sub { [params->{name},splat] }), 'third route set');
+ ok(get('/name/:name/:location/*' => sub { [params->{name},splat] }), 'third route set');
ok(get('/location/:location' => sub { params->{location} }), 'fourth route set');
ok(get('/location/:name/:location' => sub { params->{location} }), 'fifth route set');
-# ok(get('/location/:name/:location/*' => sub { [params->{location},splat] }), 'fifth route set');
+ ok(get('/location/:name/:location/*' => sub { [params->{location},splat] }), 'fifth route set');
ok(post('/name/:name' => sub { params->{name} }), 'sixth route set');
ok(post('/name/:name/:location' => sub { params->{name} }), 'seventh route set');
ok(post('/location/:location' => sub { params->{location} }), 'eigth route set');
@@ -31,17 +31,17 @@ my @tests = (
{method => 'GET', path => '/name/bill', expected => 'bill'},
{method => 'GET', path => '/name/bob', expected => 'bob'},
-# {method => 'GET', path => '/name/bob/paris/wine', expected => ['bob','wine'] },
-# {method => 'GET', path => '/name/bob/dublin/beer', expected => ['bob','beer'] },
-# {method => 'GET', path => '/name/bob/paris/wine', expected => ['bob','wine'] },
+ {method => 'GET', path => '/name/bob/paris/wine', expected => ['bob','wine'] },
+ {method => 'GET', path => '/name/bob/dublin/beer', expected => ['bob','beer'] },
+ {method => 'GET', path => '/name/bob/paris/wine', expected => ['bob','wine'] },
-# {method => 'GET', path => '/name/bill/paris/wine', expected => ['bill','wine'] },
-# {method => 'GET', path => '/name/bill/dublin/beer', expected => ['bill','beer'] },
-# {method => 'GET', path => '/name/bill/paris/wine', expected => ['bill','wine'] },
+ {method => 'GET', path => '/name/bill/paris/wine', expected => ['bill','wine'] },
+ {method => 'GET', path => '/name/bill/dublin/beer', expected => ['bill','beer'] },
+ {method => 'GET', path => '/name/bill/paris/wine', expected => ['bill','wine'] },
-# {method => 'GET', path => '/name/bob/paris/today', expected => ['bob','today'] },
-# {method => 'GET', path => '/name/bob/dublin/now', expected => ['bob','now'] },
-# {method => 'GET', path => '/name/bob/paris/tomorrow', expected => ['bob','tomorrow'] },
+ {method => 'GET', path => '/name/bob/paris/today', expected => ['bob','today'] },
+ {method => 'GET', path => '/name/bob/dublin/now', expected => ['bob','now'] },
+ {method => 'GET', path => '/name/bob/paris/tomorrow', expected => ['bob','tomorrow'] },
{method => 'GET', path => '/name/bob/paris', expected => 'bob' },
{method => 'GET', path => '/name/bob/dublin', expected => 'bob' },
@@ -64,9 +64,9 @@ my @tests = (
{method => 'GET', path => '/location/bob/dublin', expected => 'dublin' },
{method => 'GET', path => '/location/bob/paris', expected => 'paris' },
-# {method => 'GET', path => '/location/bob/paris/wine', expected => ['paris','wine'] },
-# {method => 'GET', path => '/location/bob/dublin/beer', expected => ['dublin','beer'] },
-# {method => 'GET', path => '/location/bob/paris/wine', expected => ['paris','wine'] },
+ {method => 'GET', path => '/location/bob/paris/wine', expected => ['paris','wine'] },
+ {method => 'GET', path => '/location/bob/dublin/beer', expected => ['dublin','beer'] },
+ {method => 'GET', path => '/location/bob/paris/wine', expected => ['paris','wine'] },
{method => 'post', path => '/name/bob', expected => 'bob'},
{method => 'post', path => '/name/bob/paris', expected => 'bob' },