File Coverage

blib/lib/Router/Simple/Route.pm
Criterion Covered Total %
statement 76 76 100.0
branch 43 46 93.4
condition 11 13 84.6
subroutine 6 6 100.0
pod 0 2 0.0
total 136 143 95.1


line stmt bran cond sub pod time code
1             package Router::Simple::Route;
2 12     12   50 use strict;
  12         15  
  12         386  
3 12     12   51 use warnings;
  12         68  
  12         288  
4 12     12   47 use Carp ();
  12         11  
  12         368  
5              
6             use Class::Accessor::Lite 0.05 (
7 12         77 rw => [qw(name dest on_match method host pattern)],
8 12     12   6537 );
  12         12326  
9              
10             sub new {
11 40     40 0 49 my $class = shift;
12              
13             # connect([$name, ]$pattern[, \%dest[, \%opt]])
14 40 100 100     208 if (@_ == 1 || ref $_[1]) {
15 31         58 unshift(@_, undef);
16             }
17              
18 40         79 my ($name, $pattern, $dest, $opt) = @_;
19 40 50       73 Carp::croak("missing pattern") unless $pattern;
20 40         207 my $row = +{
21             name => $name,
22             dest => $dest,
23             on_match => $opt->{on_match},
24             };
25 40 100       145 if (my $method = $opt->{method}) {
26 22 50       66 $method = [$method] unless ref $method;
27 22         32 $row->{method} = $method;
28              
29 22         22 my $method_re = join '|', @{$method};
  22         44  
30 22         269 $row->{method_re} = qr{^(?:$method_re)$};
31             }
32 40 100       94 if (my $host = $opt->{host}) {
33 5         8 $row->{host} = $host;
34 5 50       67 $row->{host_re} = ref $host ? $host : qr(^\Q$host\E$);
35             }
36              
37 40         66 $row->{pattern} = $pattern;
38              
39             # compile pattern
40 40         41 my @capture;
41 40         30 $row->{pattern_re} = do {
42 40 100       74 if (ref $pattern) {
43 2         3 $row->{_regexp_capture} = 1;
44 2         2 $pattern;
45             } else {
46 38         230 $pattern =~ s!
47             \{((?:\{[0-9,]+\}|[^{}]+)+)\} | # /blog/{year:\d{4}}
48             :([A-Za-z0-9_]+) | # /blog/:year
49             (\*) | # /blog/*/*
50             ([^{:*]+) # normal string
51             !
52 102 100       324 if ($1) {
    100          
    100          
53 28         82 my ($name, $pattern) = split /:/, $1, 2;
54 28         42 push @capture, $name;
55 28 100       88 $pattern ? "($pattern)" : "([^/]+)";
56             } elsif ($2) {
57 7         12 push @capture, $2;
58 7         20 "([^/]+)";
59             } elsif ($3) {
60 4         4 push @capture, '__splat__';
61 4         9 "(.+)";
62             } else {
63 63         213 quotemeta($4);
64             }
65             !gex;
66             # for example, pattern '/comment/' will both match '/comment/' and '/comment'
67 38 100 66     132 $pattern .= '?' if $opt->{directory_slash} and $pattern =~ m{\/$};
68 38         674 qr{^$pattern$};
69             }
70             };
71 40         92 $row->{capture} = \@capture;
72 40   100     102 $row->{dest} ||= +{};
73              
74 40         174 return bless $row, $class;
75             }
76              
77             sub match {
78 119     119 0 121 my ($self, $env) = @_;
79              
80 119 100       230 if ($self->{host_re}) {
81 15 100       80 unless ($env->{HTTP_HOST} =~ $self->{host_re}) {
82 4         8 return undef;
83             }
84             }
85 115 100       714 if (my @captured = ($env->{PATH_INFO} =~ $self->{pattern_re})) {
86 43         44 my %args;
87             my @splat;
88 43 100       101 if ($self->{_regexp_capture}) {
89 1         2 push @splat, @captured;
90             } else {
91 42 100 100     34 if (@{$self->{capture}} > 0 && scalar(@{$self->{capture}}) != scalar(@captured)) {
  42         173  
  23         93  
92             # Should not contain parenthesis in regexp pattern
93             #
94             # Good: "/{date:(?:\d+)}"
95             # Bad: "/{date:(\d+)}"
96 1         148 Carp::carp("Path pattern should not contain paren. This code may not works in future version of Router::Simple. : " . $self->{pattern});
97             }
98              
99 42         114 for my $i (0..@{$self->{capture}}-1) {
  42         144  
100 47 100       82 if ($self->{capture}->[$i] eq '__splat__') {
101 4         9 push @splat, $captured[$i];
102             } else {
103 43         97 $args{$self->{capture}->[$i]} = $captured[$i];
104             }
105             }
106             }
107 43 100       112 if ($self->{method_re}) {
108 28 100 50     179 unless (($env->{REQUEST_METHOD} || '') =~ $self->{method_re}) {
109 8         14 $Router::Simple::_METHOD_NOT_ALLOWED = 1;
110 8         37 return undef;
111             }
112             }
113 35         183 my $match = +{
114 35 100       39 %{$self->{dest}},
115             %args,
116             ( @splat ? ( splat => \@splat ) : () ),
117             };
118 35 100       90 if ($self->{on_match}) {
119 3         10 my $ret = $self->{on_match}->($env, $match);
120 3 100       23 return undef unless $ret;
121             }
122 34         117 return $match;
123             }
124 72         127 return undef;
125             }
126              
127             1;
128             __END__