Skip to content

Instantly share code, notes, and snippets.

/types.diff Secret

Created February 18, 2016 13:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/9d9cb3a77130fc91879f to your computer and use it in GitHub Desktop.
Save anonymous/9d9cb3a77130fc91879f to your computer and use it in GitHub Desktop.
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