File Coverage

blib/lib/Path/Dispatcher/Rule/Under.pm
Criterion Covered Total %
statement 22 35 62.8
branch 3 8 37.5
condition 3 3 100.0
subroutine 5 6 83.3
pod 1 2 50.0
total 34 54 62.9


line stmt bran cond sub pod time code
1             package Path::Dispatcher::Rule::Under;
2             # ABSTRACT: rules under a predicate
3              
4             our $VERSION = '1.07';
5              
6 31     31   250 use Moo;
  31         102  
  31         187  
7 31     31   9651 use Type::Tiny;
  31         92  
  31         1023  
8 31     31   194 use Type::Utils qw(class_type);
  31         72  
  31         208  
9              
10             extends 'Path::Dispatcher::Rule';
11             with 'Path::Dispatcher::Role::Rules';
12              
13             my $PREFIX_RULE_TYPE = "Type::Tiny"->new(
14             name => "PrefixRule",
15             parent => class_type("Path::Dispatcher::Rule"),
16             constraint => sub { return ( shift()->prefix ) ? 1 : 0 },
17             message => sub { "This rule ($_) does not match just prefixes!" },
18             );
19              
20             has predicate => (
21             is => 'ro',
22             isa => $PREFIX_RULE_TYPE
23             );
24              
25             sub match {
26 21     21 1 751 my $self = shift;
27 21         33 my $path = shift;
28              
29 21 100       107 my $prefix_match = $self->predicate->match($path)
30             or return;
31              
32 16         131 my $leftover = $prefix_match->leftover;
33 16 50       44 $leftover = '' if !defined($leftover);
34              
35 16         48 my $new_path = $path->clone_path($leftover);
36              
37             # Pop off @matches until we have a last rule that is not ::Chain
38             #
39             # A better technique than isa might be to use the concept of 'endpoint', 'midpoint', or 'anypoint' rules and
40             # add a method to ::Rule that lets evaluate whether any rule is of the right kind (i.e. ->is_endpoint)
41             #
42             # Because the checking for ::Chain endpointedness is here, this means that outside of an ::Under, ::Chain behaves like
43             # an ::Always (one that will always trigger next_rule if it's block is ran)
44             #
45             my @matches = map {
46 16         835 $_->match(
  40         137  
47             $new_path,
48             extra_constructor_args => {
49             parent => $prefix_match,
50             },
51             )
52             } $self->rules;
53 16   100     137 pop @matches while @matches && $matches[-1]->rule->isa('Path::Dispatcher::Rule::Chain');
54 16         91 return @matches;
55             }
56              
57             sub complete {
58 0     0 0   my $self = shift;
59 0           my $path = shift;
60              
61 0           my $predicate = $self->predicate;
62              
63 0 0         my $prefix_match = $predicate->match($path)
64             or return $predicate->complete($path);
65              
66 0           my $new_path = $path->clone_path($prefix_match->leftover);
67              
68 0           my $prefix = substr($path->path, 0, length($path->path) - length($new_path->path));
69              
70 0           my @completions = map { $_->complete($new_path) } $self->rules;
  0            
71              
72 0 0         if ($predicate->can('untokenize')) {
73 0           return map { $predicate->untokenize($prefix, $_) } @completions;
  0            
74             }
75             else {
76 0           return map { "$prefix$_" } @completions;
  0            
77             }
78             }
79              
80             __PACKAGE__->meta->make_immutable;
81 31     31   28649 no Moo;
  31         85  
  31         184  
82              
83             1;
84              
85             __END__