File Coverage

blib/lib/Path/Dispatcher/Rule/Sequence.pm
Criterion Covered Total %
statement 47 47 100.0
branch 11 12 91.6
condition 6 6 100.0
subroutine 8 8 100.0
pod 0 3 0.0
total 72 76 94.7


line stmt bran cond sub pod time code
1             package Path::Dispatcher::Rule::Sequence;
2             # ABSTRACT: a sequence of rules
3              
4             our $VERSION = '1.07';
5              
6 31     31   229 use Moo;
  31         76  
  31         187  
7 31     31   9529 use Types::Standard qw(Str);
  31         77  
  31         195  
8              
9             extends 'Path::Dispatcher::Rule';
10             with 'Path::Dispatcher::Role::Rules';
11              
12             has delimiter => (
13             is => 'ro',
14             isa => Str,
15             default => ' ',
16             );
17              
18             sub _match_as_far_as_possible {
19 80     80   128 my $self = shift;
20 80         112 my $path = shift;
21              
22 80         233 my @tokens = $self->tokenize($path->path);
23 80         248 my @rules = $self->rules;
24 80         127 my @matched;
25              
26 80   100     351 while (@tokens && @rules) {
27 152         276 my $rule = $rules[0];
28 152         241 my $token = $tokens[0];
29              
30 152 100       440 last unless $rule->match($path->clone_path($token));
31              
32 112         456 push @matched, $token;
33 112         200 shift @rules;
34 112         443 shift @tokens;
35             }
36              
37 80         379 return (\@matched, \@tokens, \@rules);
38             }
39              
40             sub _match {
41 48     48   73 my $self = shift;
42 48         78 my $path = shift;
43              
44 48         96 my ($matched, $tokens, $rules) = $self->_match_as_far_as_possible($path);
45              
46 48 100       193 return if @$rules; # didn't provide everything necessary
47 26 100 100     157 return if @$tokens && !$self->prefix; # had tokens left over
48              
49 24         67 my $leftover = $self->untokenize(@$tokens);
50             return {
51 24         98 leftover => $leftover,
52             positional_captures => $matched,
53             };
54             }
55              
56             sub complete {
57 32     32 0 53 my $self = shift;
58 32         45 my $path = shift;
59              
60 32         69 my ($matched, $tokens, $rules) = $self->_match_as_far_as_possible($path);
61 32 50       78 return if @$tokens > 1; # had tokens leftover
62 32 100       78 return if !@$rules; # consumed all rules
63              
64 30         50 my $rule = shift @$rules;
65 30 100       76 my $token = @$tokens ? shift @$tokens : '';
66              
67 30         91 return map { $self->untokenize(@$matched, $_) }
  40         92  
68             $rule->complete($path->clone_path($token));
69             }
70              
71             sub tokenize {
72 80     80 0 127 my $self = shift;
73 80         120 my $path = shift;
74 80         1008 return grep { length } split $self->delimiter, $path;
  196         562  
75             }
76              
77             sub untokenize {
78 64     64 0 112 my $self = shift;
79 64         123 my @tokens = @_;
80             return join $self->delimiter,
81 88         299 grep { length }
82 64         179 map { split $self->delimiter, $_ }
  88         675  
83             @tokens;
84             }
85              
86             __PACKAGE__->meta->make_immutable;
87 31     31   31382 no Moo;
  31         79  
  31         185  
88              
89             1;
90              
91             __END__