-
-
Save anonymous/9d9cb3a77130fc91879f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/lib/Mojolicious/Routes.pm b/lib/Mojolicious/Routes.pm | |
index 9bff8d5..084db93 100644 | |
--- a/lib/Mojolicious/Routes.pm | |
+++ b/lib/Mojolicious/Routes.pm | |
@@ -10,12 +10,13 @@ use Scalar::Util 'weaken'; | |
has base_classes => sub { [qw(Mojolicious::Controller Mojo)] }; | |
has cache => sub { Mojo::Cache->new }; | |
-has [qw(conditions shortcuts)] => sub { {} }; | |
+has [qw(conditions shortcuts types)] => sub { {} }; | |
has hidden => sub { [qw(attr has new tap)] }; | |
has namespaces => sub { [] }; | |
sub add_condition { $_[0]->conditions->{$_[1]} = $_[2] and return $_[0] } | |
sub add_shortcut { $_[0]->shortcuts->{$_[1]} = $_[2] and return $_[0] } | |
+sub add_type { $_[0]->types->{$_[1]} = $_[2] and return $_[0] } | |
sub continue { | |
my ($self, $c) = @_; | |
@@ -279,6 +280,8 @@ Namespaces to load controllers from. | |
Contains all available shortcuts. | |
+=head2 types | |
+ | |
=head1 METHODS | |
L<Mojolicious::Routes> inherits all methods from L<Mojolicious::Routes::Route> | |
@@ -307,6 +310,8 @@ Register a shortcut. | |
... | |
}); | |
+=head2 add_type | |
+ | |
=head2 continue | |
$r->continue(Mojolicious::Controller->new); | |
diff --git a/lib/Mojolicious/Routes/Pattern.pm b/lib/Mojolicious/Routes/Pattern.pm | |
index dbf8806..f11741f 100644 | |
--- a/lib/Mojolicious/Routes/Pattern.pm | |
+++ b/lib/Mojolicious/Routes/Pattern.pm | |
@@ -7,8 +7,9 @@ has [qw(placeholders tree)] => sub { [] }; | |
has quote_end => ')'; | |
has quote_start => '('; | |
has [qw(regex unparsed)]; | |
-has relaxed_start => '#'; | |
-has wildcard_start => '*'; | |
+has type_end => '}'; | |
+has type_start => '{'; | |
+has types => sub { {relaxed => '([^/]+)', wildcard => '(.+)'} }; | |
sub match { | |
my ($self, $path, $detect) = @_; | |
@@ -86,11 +87,12 @@ sub _compile { | |
my $placeholders = $self->placeholders; | |
my $constraints = $self->constraints; | |
my $defaults = $self->defaults; | |
+ my $types = $self->types; | |
my $block = my $regex = ''; | |
my $optional = 1; | |
for my $token (reverse @{$self->tree}) { | |
- my ($op, $value) = @$token; | |
+ my ($op, $value, $type) = @$token; | |
my $fragment = ''; | |
# Text | |
@@ -108,13 +110,9 @@ sub _compile { | |
unshift @$placeholders, $value; | |
# Placeholder | |
- if ($op eq 'placeholder') { $fragment = '([^/.]+)' } | |
- | |
- # Relaxed | |
- elsif ($op eq 'relaxed') { $fragment = '([^/]+)' } | |
- | |
- # Wildcard | |
- else { $fragment = '(.+)' } | |
+ if ($op eq 'placeholder') { | |
+ $fragment = $type && $types->{$type} ? $types->{$type} : '([^/.]+)'; | |
+ } | |
# Custom regex | |
if (my $c = $constraints->{$value}) { $fragment = _compile_req($c) } | |
@@ -161,42 +159,51 @@ sub _tokenize { | |
my $quote_end = $self->quote_end; | |
my $quote_start = $self->quote_start; | |
+ my $type_end = $self->type_end; | |
+ my $type_start = $self->type_start; | |
my $placeholder = $self->placeholder_start; | |
- my $relaxed = $self->relaxed_start; | |
- my $wildcard = $self->wildcard_start; | |
- my (@tree, $inside, $quoted); | |
+ my (@tree, $spec, $type); | |
for my $char (split '', $pattern) { | |
# Quote start | |
if ($char eq $quote_start) { | |
- push @tree, ['placeholder', '']; | |
- ($inside, $quoted) = (1, 1); | |
+ push @tree, ['placeholder', '', '']; | |
+ $spec = 1; | |
} | |
# Placeholder start | |
elsif ($char eq $placeholder) { | |
- push @tree, ['placeholder', ''] unless $inside++; | |
+ push @tree, ['placeholder', '', ''] unless $spec++; | |
} | |
# Relaxed or wildcard start (upgrade when quoted) | |
- elsif ($char eq $relaxed || $char eq $wildcard) { | |
- push @tree, ['placeholder', ''] unless $quoted; | |
- $tree[-1][0] = $char eq $relaxed ? 'relaxed' : 'wildcard'; | |
- $inside = 1; | |
+ elsif ($char eq '#' || $char eq '*') { | |
+ push @tree, ['placeholder', '', ''] unless $spec; | |
+ $tree[-1][2] = $char eq '#' ? 'relaxed' : 'wildcard'; | |
+ $spec = 1; | |
} | |
# Quote end | |
- elsif ($char eq $quote_end) { ($inside, $quoted) = (0, 0) } | |
+ elsif ($char eq $quote_end) { $spec = 0 } | |
+ | |
+ # Type start | |
+ elsif ($char eq $type_start) { ($type, $spec) = (1, 1) } | |
+ | |
+ # Type end | |
+ elsif ($char eq $type_end) { $type = 0 } | |
# Slash | |
elsif ($char eq '/') { | |
push @tree, ['slash']; | |
- $inside = 0; | |
+ $spec = 0; | |
} | |
- # Placeholder, relaxed or wildcard | |
- elsif ($inside) { $tree[-1][-1] .= $char } | |
+ # Type | |
+ elsif ($type) { $tree[-1][2] .= $char } | |
+ | |
+ # Placeholder | |
+ elsif ($spec) { $tree[-1][1] .= $char } | |
# Text (optimize slash+text and *+text+slash+text) | |
elsif ($tree[-1][0] eq 'text') { $tree[-1][-1] .= $char } | |
@@ -288,13 +295,6 @@ Character indicating the start of a quoted placeholder, defaults to C<(>. | |
Pattern in compiled regular expression form. | |
-=head2 relaxed_start | |
- | |
- my $start = $pattern->relaxed_start; | |
- $pattern = $pattern->relaxed_start('*'); | |
- | |
-Character indicating a relaxed placeholder, defaults to C<#>. | |
- | |
=head2 tree | |
my $tree = $pattern->tree; | |
@@ -303,6 +303,12 @@ Character indicating a relaxed placeholder, defaults to C<#>. | |
Pattern in parsed form. Note that this structure should only be used very | |
carefully since it is very dynamic. | |
+=head2 type_end | |
+ | |
+=head2 type_start | |
+ | |
+=head2 types | |
+ | |
=head2 unparsed | |
my $unparsed = $pattern->unparsed; | |
@@ -310,13 +316,6 @@ carefully since it is very dynamic. | |
Raw unparsed pattern. | |
-=head2 wildcard_start | |
- | |
- my $start = $pattern->wildcard_start; | |
- $pattern = $pattern->wildcard_start('*'); | |
- | |
-Character indicating the start of a wildcard placeholder, defaults to C<*>. | |
- | |
=head1 METHODS | |
L<Mojolicious::Routes::Pattern> inherits all methods from L<Mojo::Base> and | |
diff --git a/lib/Mojolicious/Routes/Route.pm b/lib/Mojolicious/Routes/Route.pm | |
index 35fcf12..49e5870 100644 | |
--- a/lib/Mojolicious/Routes/Route.pm | |
+++ b/lib/Mojolicious/Routes/Route.pm | |
@@ -73,8 +73,6 @@ sub name { | |
return $self; | |
} | |
-sub new { shift->SUPER::new->parse(@_) } | |
- | |
sub options { shift->_generate_route(OPTIONS => @_) } | |
sub over { | |
@@ -119,10 +117,15 @@ sub render { | |
sub root { shift->_chain->[0] } | |
sub route { | |
- my $self = shift; | |
- my $route = $self->add_child(__PACKAGE__->new(@_))->children->[-1]; | |
+ my $self = shift; | |
+ | |
+ my $route = __PACKAGE__->new; | |
+ my $pattern = $route->pattern; | |
+ $pattern->types({%{$pattern->types}, %{$self->root->types}}); | |
+ $self->add_child($route->parse(@_)); | |
my $format = $self->pattern->constraints->{format}; | |
- $route->pattern->constraints->{format} //= 0 if defined $format && !$format; | |
+ $pattern->constraints->{format} //= 0 if defined $format && !$format; | |
+ | |
return $route; | |
} | |
@@ -395,16 +398,6 @@ the current route. | |
# Route with destination and custom name | |
$r->get('/user')->to('user#show')->name('show_user'); | |
-=head2 new | |
- | |
- my $r = Mojolicious::Routes::Route->new; | |
- my $r = Mojolicious::Routes::Route->new('/:action'); | |
- my $r = Mojolicious::Routes::Route->new('/:action', action => qr/\w+/); | |
- my $r = Mojolicious::Routes::Route->new(format => 0); | |
- | |
-Construct a new L<Mojolicious::Routes::Route> object and L</"parse"> pattern if | |
-necessary. | |
- | |
=head2 options | |
my $route = $r->options('/:foo'); | |
diff --git a/t/mojolicious/pattern.t b/t/mojolicious/pattern.t | |
index 179758b..fa77f2d 100644 | |
--- a/t/mojolicious/pattern.t | |
+++ b/t/mojolicious/pattern.t | |
@@ -106,7 +106,8 @@ is_deeply $pattern->match('/test/foo/bar.baz/yada'), | |
{controller => 'foo', action => 'bar.baz/yada'}, 'right structure'; | |
is $pattern->render({controller => 'foo', action => 'bar.baz/yada'}), | |
'/test/foo/bar.baz/yada', 'right result'; | |
-$pattern = Mojolicious::Routes::Pattern->new('/tset/:controller/*action'); | |
+$pattern | |
+ = Mojolicious::Routes::Pattern->new('/tset/:controller/:action{wildcard}'); | |
is_deeply $pattern->match('/tset/foo/bar.baz/yada'), | |
{controller => 'foo', action => 'bar.baz/yada'}, 'right structure'; | |
is $pattern->render({controller => 'foo', action => 'bar.baz/yada'}), | |
diff --git a/t/mojolicious/routes.t b/t/mojolicious/routes.t | |
index 524abcc..0c984a7 100644 | |
--- a/t/mojolicious/routes.t | |
+++ b/t/mojolicious/routes.t | |
@@ -79,7 +79,7 @@ $r->route('/wildcards/1/(*wildcard)', wildcard => qr/(?:.*)/) | |
->to(controller => 'wild', action => 'card'); | |
# /wildcards/2/* | |
-$r->route('/wildcards/2/(*wildcard)') | |
+$r->route('/wildcards/2/(wildcard{wildcard})') | |
->to(controller => 'card', action => 'wild'); | |
# /wildcards/3/*/foo |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment