File Coverage

blib/lib/YATT/Lite/WebMVC0/SubRoutes.pm
Criterion Covered Total %
statement 56 63 88.8
branch 19 22 86.3
condition 5 6 83.3
subroutine 10 11 90.9
pod 0 6 0.0
total 90 108 83.3


line stmt bran cond sub pod time code
1             package YATT::Lite::WebMVC0::SubRoutes;
2 4     4   6961 use strict;
  4         7  
  4         130  
3 4     4   19 use warnings qw(FATAL all NONFATAL misc);
  4         8  
  4         166  
4 4     4   20 use Carp;
  4         9  
  4         297  
5              
6 4         50 use YATT::Lite::Types ([Route =>
7             -fields => [qw/pattern_re
8             cf_name
9 4     4   365 cf_pattern cf_item cf_params/]]);
  4         13  
10 4     4   394 use YATT::Lite::RegexpNames;
  4         9  
  4         2700  
11              
12             sub new {
13 20     20 0 1397 bless [], shift;
14             }
15              
16             sub prepend {
17 0     0 0 0 my $self = shift; unshift @$self, @_; $self;
  0         0  
  0         0  
18             }
19              
20             sub append {
21 39     39 0 80 my $self = shift; push @$self, @_; $self;
  39         100  
  39         90  
22             }
23              
24             sub match {
25 82     82 0 165 my $self = shift;
26 82         232 foreach my Route $r (@$self) {
27             my ($slash, @match) = $_[0] =~ $r->{pattern_re}
28 151 100       1306 or next;
29 82   66     686 return ($r->{cf_item} // $r->{cf_name}, $r->{cf_params}, \@match);
30             }
31 0         0 return;
32             }
33              
34             sub create {
35 45     45 0 143 my ($self, $spec, $item) = @_;
36 45 100       186 my ($name, $pat) = ref $spec eq 'ARRAY' ? @$spec : (undef, $spec);
37 45         302 my Route $r = $self->Route->new;
38 45         105 $r->{cf_name} = $name;
39 45         97 $r->{cf_pattern} = $pat;
40 45         86 $r->{cf_item} = $item;
41 45         126 ($r->{pattern_re}, my @params) = $self->parse_pattern($pat);
42 45         129 $r->{cf_params} = \ @params;
43 45         229 $r;
44             }
45              
46             my %re_paren = qw!( (?: ) )?!;
47              
48             sub parse_pattern {
49 62     62 0 17255 my ($self, $pat) = @_;
50              
51 62         116 my (@pat, @params);
52 62 50       322 unless ($pat =~ m!^/!g) {
53 0         0 croak "Unsupported url pattern! $pat";
54             }
55              
56 62         114 my $last = 0;
57 62         286 while ($pat =~ m!\G(?: ([^:{}()]+) # $1 other text
58             | (?<=/) \:(\w+(?:\:\w+)*) # $2 :var:type
59             | \{(\w+ # $3 {var:...}
60             (?:
61             : (?: (?:\w+(?:\:\w+)*) # :type
62             | (?: [^{}]+ # regexp(other than {})
63             | (\{ # $4 re-qualifier(nestable)
64             (?: (?> [^{}]+)
65             | (?-1)
66             )*
67             \})
68             )+
69             )
70             )?
71             )
72             \}
73             | ([()]) # $5 (optional)
74             )
75             !xg) {
76 125 100       335 if (not @pat) {
77 60         128 push @pat, "(/)"; # To make sure first slash is captured.
78             }
79 125 100 100     511 if ($1) {
    100          
    50          
80 72         206 push @pat, quotemeta($1);
81             } elsif (my $var_type = $2 // $3) {
82 41         122 my ($name, $type_or_pat) = split /:/, $var_type, 2;
83 41         93 my $var = [$name];
84 41         71 push @pat, do {
85 41 100       101 unless ($type_or_pat) {
    100          
86 32         61 q!([^/]+)!
87 0         0 } elsif (my ($type) = $type_or_pat =~ /^(\w+)$/) {
88 1 50       15 my $sub = $self->can("re_$type")
89             or croak "Unknown pattern type: $type";
90 1         10 push @$var, $type;
91 1         8 '('.$sub->($self, 1).')'; # partial pattern
92             } else {
93 8         28 "($type_or_pat)";
94             }
95             };
96 41         85 push @params, $var;
97             } elsif ($5) {
98 12         33 push @pat, $re_paren{$5};
99             } else {
100 0         0 last;
101             }
102             } continue {
103 125         499 $last = pos($pat);
104             }
105 62 100       203 push @pat, quotemeta(substr($pat, $last)) if $last < length $pat;
106 62         183 my $all = join "", @pat;
107              
108 62         1464 (qr{^$all$}x, @params);
109             }
110              
111             1;