Permalink
Browse files

fixed format inheritance and added tests

  • Loading branch information...
1 parent 8e06b58 commit b588e73455402d1379edab332fe950f5264f69e0 forwardever committed Feb 15, 2012
Showing with 348 additions and 106 deletions.
  1. +64 −25 lib/Forward/Routes.pm
  2. +18 −17 t/format_constraints.t
  3. +266 −61 t/nested_routes_with_format_inheritance.t
  4. +0 −3 t/resources_with_format_constraint.t
View
@@ -1,5 +1,4 @@
package Forward::Routes;
-
use strict;
use warnings;
@@ -301,26 +300,58 @@ sub via {
sub _match {
- my ($self, $method, $path) = @_;
+ my $self = shift;
+ my ($method, $path, $format_extracted_from_path, $last_path_part, $last_pattern) = @_;
+
+ # re-evaluate last path part if format changes from undef to def or vice versa
+ # and last path part has already been checked (empty path)
+ my $re_eval_pattern;
+ if (!(length $path) && defined($self->format) ne defined($self->parent->format)) {
+ $path = $last_path_part;
+ $re_eval_pattern = 1;
+ }
- # Format
- my $request_format;
- if (!@{$self->children} && $self->{format}) {
+
+ # change from def to undef format -> add format extension back to path
+ # (reverse format extraction)
+ if (!(defined $self->format) && $self->parent && defined $self->parent->format) {
+ $path .= '.' . $format_extracted_from_path if $format_extracted_from_path ne '';
+ $format_extracted_from_path = undef;
+ }
+
+
+ # use pattern of current route, or if it does not exist and path has to be
+ # re-evaluated because of format change, use last pattern
+ my $pattern;
+ if (defined $self->pattern->pattern) {
+ $pattern = $self->pattern;
+ }
+ elsif ($re_eval_pattern) {
+ $pattern = $last_pattern;
+ }
+ else {
+ $pattern = undef;
+ }
+
+
+ # extract format from path if not already done and format option is activated
+ if ($self->format && !(defined $format_extracted_from_path)) {
$path =~m/\.([\a-zA-Z0-9]{1,4})$/;
- $request_format = defined $1 ? $1 : '';
+ $format_extracted_from_path = defined $1 ? $1 : '';
- # format extension is only replaced if format constraint exists
- $path =~s/\.[\a-zA-Z0-9]{1,4}$// if $request_format;
+ $path =~s/\.[\a-zA-Z0-9]{1,4}$// if $format_extracted_from_path ne '';
}
- # Current pattern match
+
+ # match current pattern or return
my $captures = [];
- if (defined $self->pattern->pattern) {
- $captures = $self->_match_current_pattern(\$path) || return;
+ if ($pattern) {
+ ($captures, $last_path_part, $last_pattern) = $self->_match_current_pattern(\$path, $pattern);
+ $captures || return;
}
- # No Match, as path not empty, but further children
- return if length($path) && !@{$self->children};
+ # no match, as path not empty and no further children exist
+ return if length $path && !@{$self->children};
# Children match
my $matches = [];
@@ -330,7 +361,7 @@ sub _match {
foreach my $child (@{$self->children}) {
# Match?
- $matches = $child->_match($method => $path);
+ $matches = $child->_match($method => $path, $format_extracted_from_path, $last_path_part, $last_pattern);
last if $matches;
}
@@ -341,7 +372,7 @@ sub _match {
# Format and Method
unless (@{$self->children}) {
$self->_match_method($method) || return;
- $self->_match_format($request_format) || return;
+ $self->_match_format($format_extracted_from_path) || return;
}
# Match object
@@ -372,14 +403,17 @@ sub _match {
$match = $matches->[0];
}
- my $captures_hash = $self->_captures_to_hash(@$captures);
+ my $captures_hash = {};
+ if ($pattern) {
+ $captures_hash = $self->_captures_to_hash($pattern, @$captures);
+ }
# Merge defaults and captures, Copy! of $self->defaults
$match->_add_params({%{$self->defaults}, %$captures_hash});
# Format
unless (@{$self->children}) {
- $match->_add_params({format => $request_format}) if $self->{format};
+ $match->_add_params({format => $format_extracted_from_path}) if $self->{format};
}
# Captures
@@ -390,34 +424,39 @@ sub _match {
sub _match_current_pattern {
- my ($self, $path_ref) = @_;
+ my ($self, $path_ref, $pattern) = @_;
+
+ my $last_path_part = $$path_ref;
# Pattern
- my $regex = $self->pattern->compile->pattern;
+ my $regex = $pattern->compile->pattern;
+
my @captures = ($$path_ref =~ m/$regex/);
return unless @captures;
# Remove 1 at the end of array if no real captures present
- splice @captures, @{$self->pattern->captures};
+ splice @captures, @{$pattern->captures};
# Replace matching part
$$path_ref =~ s/$regex//;
-
+ if (length($last_path_part) && !(length $$path_ref)) {
+ return (\@captures, $last_path_part, $pattern);
+ }
return \@captures;
}
sub _captures_to_hash {
my $self = shift;
- my (@captures) = @_;
+ my ($pattern, @captures) = @_;
my $captures = {};
my $defaults = $self->{defaults};
- foreach my $name (@{$self->pattern->captures}) {
+ foreach my $name (@{$pattern->captures}) {
my $capture = shift @captures;
if (defined $capture) {
@@ -723,11 +762,11 @@ sub format {
sub _match_format {
- my ($self, $request_format) = @_;
+ my ($self, $format) = @_;
return 1 unless defined $self->format;
- my @success = grep { $_ eq $request_format } @{$self->format};
+ my @success = grep { $_ eq $format } @{$self->format};
return unless @success;
View
@@ -22,10 +22,10 @@ is_deeply $m->[0]->params => {foo => 'hello', bar => 'there.html'};
-### one format constraint
-$r = Forward::Routes->new->format('html');
-$r->add_route('foo')->name('one');
-$r->add_route(':foo/:bar')->name('two');
+### format constraint
+$r = Forward::Routes->new;
+$r->add_route('foo')->name('one')->format('html');
+$r->add_route(':foo/:bar')->name('two')->format('html');
$m = $r->match(get => 'foo.html');
is_deeply $m->[0]->params => {format => 'html'};
@@ -58,10 +58,11 @@ is $r->build_path('two', foo => 1, bar => 2)->{path}, '1/2.html';
is $r->build_path('two', foo => 0, bar => 2)->{path}, '0/2.html';
+
### pass empty format explicitly
-$r = Forward::Routes->new->format('');
-$r->add_route('foo')->name('one');
-$r->add_route(':foo/:bar')->name('two');
+$r = Forward::Routes->new;
+$r->add_route('foo')->name('one')->format('');
+$r->add_route(':foo/:bar')->name('two')->format('');
$m = $r->match(get => 'foo');
is_deeply $m->[0]->params => {format => ''};
@@ -89,9 +90,9 @@ is $r->build_path('two', foo => 1, bar => 2)->{path}, '1/2';
### pass undef format (no contraint validation)
-$r = Forward::Routes->new->format(undef);
-$r->add_route('foo')->name('one');
-$r->add_route(':foo/:bar')->name('two');
+$r = Forward::Routes->new;
+$r->add_route('foo')->name('one')->format(undef);
+$r->add_route(':foo/:bar')->name('two')->format(undef);
$m = $r->match(get => 'foo');
is_deeply $m->[0]->params => {};
@@ -114,9 +115,9 @@ is $r->build_path('two', foo => 1, bar => 2)->{path}, '1/2';
### multiple format constraints
-$r = Forward::Routes->new->format('html','xml');
-$r->add_route('foo')->name('one');
-$r->add_route(':foo/:bar')->name('two');
+$r = Forward::Routes->new;
+$r->add_route('foo')->name('one')->format('html','xml');
+$r->add_route(':foo/:bar')->name('two')->format('html','xml');
$m = $r->match(get => 'foo.html');
is_deeply $m->[0]->params => {format => 'html'};
@@ -157,9 +158,9 @@ is $r->build_path('two', foo => 1, bar => 2)->{path}, '1/2.html';
### multiple format constraints, with empty format allowed
-$r = Forward::Routes->new->format('html','');
-$r->add_route('foo')->name('one');
-$r->add_route(':foo/:bar')->name('two');
+$r = Forward::Routes->new;
+$r->add_route('foo')->name('one')->format('html','');
+$r->add_route(':foo/:bar')->name('two')->format('html','');
$m = $r->match(get => 'foo.html');
is_deeply $m->[0]->params => {format => 'html'};
@@ -187,4 +188,4 @@ is $m, undef;
# build path
is $r->build_path('one')->{path}, 'foo.html';
-is $r->build_path('two', foo => 1, bar => 2)->{path}, '1/2.html';
+is $r->build_path('two', foo => 1, bar => 2)->{path}, '1/2.html';
Oops, something went wrong.

0 comments on commit b588e73

Please sign in to comment.