File Coverage

blib/lib/Spike/Site/Router/Route.pm
Criterion Covered Total %
statement 53 90 58.8
branch 29 48 60.4
condition 16 37 43.2
subroutine 11 26 42.3
pod 0 13 0.0
total 109 214 50.9


line stmt bran cond sub pod time code
1             package Spike::Site::Router::Route;
2              
3 2     2   16582 use strict;
  2         3  
  2         48  
4 2     2   7 use warnings;
  2         2  
  2         50  
5              
6 2     2   6 use base qw(Spike::Tree);
  2         3  
  2         685  
7              
8 2     2   9 use List::Util qw(first any);
  2         2  
  2         138  
9 2     2   531 use HTTP::Status qw(:constants);
  2         3196  
  2         2202  
10              
11             sub route {
12 28     28 0 46 my ($self, $path) = splice @_, 0, 2;
13              
14 28 100 66     88 return $self if !defined $path || !length $path;
15              
16 20   66     75 my $first = ($path =~ s!^/*([^/]+)!!) && $1;
17              
18 20 100       28 return $self if !length $first;
19              
20 19   66     58 my $rule = $first =~ m!^#! && @_ && ref $_[0] && shift;
21 19     0   31 my $fake_rule = sub {};
22              
23             my $child = first {
24 6 100 33 6   13 $_->name eq $first &&
      33        
25             ($_->rule || $fake_rule) == ($rule || $fake_rule)
26 19         63 } $self->childs;
27              
28 19 100       41 if (!$child) {
29 14         23 $child = $self->new($first);
30 14         22 $self->add_child($child);
31              
32 14 100       19 $child->rule($rule) if $rule;
33             }
34              
35 19         33 return $child->route($path, @_);
36             }
37              
38             sub _check_rule {
39 39     39   35 my ($self, $rule, $value) = @_;
40              
41 39 100       85 if (ref $rule eq 'CODE') {
    100          
    50          
42 7         11 return $rule->($_ = $value);
43             }
44             elsif (ref $rule eq 'ARRAY') {
45 19     19   65 return any { $_ eq $value } @$rule;
  19         66  
46             }
47             elsif (ref $rule eq 'Regexp') {
48 13         75 return $value =~ m!^(?:$rule)$!;
49             }
50              
51 0         0 return !1;
52             }
53              
54             sub _find {
55 123     123   96 my ($self, $part) = @_;
56              
57 123         152 my @ordered = ([], [], []);
58              
59 123         173 for my $child ($self->childs) {
60 141         180 my $name = $child->name;
61              
62 141 100       315 if ($name eq '*') {
    100          
    100          
63 9         7 push @{$ordered[2]}, $child;
  9         17  
64             }
65             elsif ($name =~ m!^#!) {
66 45         70 my $rule = $child->rule;
67              
68 45 100 100     89 if (!$rule || $self->_check_rule($rule, $part)) {
69 33 100       31 push @{$ordered[$rule ? 0 : 1]}, $child;
  33         88  
70             }
71             }
72             elsif ($name eq $part) {
73 59         136 return $child;
74             }
75             }
76              
77 64   100     262 return $ordered[0][0] || $ordered[1][0] || $ordered[2][0] || ();
78             }
79              
80             sub find {
81 132     132 0 312 my ($self, $path) = @_;
82              
83 132 100 33     290 return $self if !defined $path || !length $path;
84              
85 123   33     438 my $first = ($path =~ s!^/*([^/]+)!!) && $1;
86              
87 123 50       155 return $self if !length $first;
88              
89 123         128 return $_->find($path) for $self->_find($first);
90              
91 22 50       88 return wantarray ? (undef, $self) : ();
92             }
93              
94             sub _handler {
95 0     0     my ($self, $hash, $default) = splice @_, 0, 3;
96              
97 0 0         return $hash->{$default} if !@_;
98              
99 0 0         if (@_ == 1) {
100             return $hash->{+shift}
101 0 0 0       if defined $_[0] && !ref $_[0];
102              
103 0           $hash->{$default} = shift;
104 0           return $self;
105             }
106              
107 0           $hash->{+shift} = $_[1], shift while @_;
108 0           return $self;
109             }
110              
111             sub _handlers {
112 0     0     my ($self, $hash) = @_;
113              
114 0           return grep { defined $hash->{$_} }
  0            
115             keys %$hash;
116             }
117              
118             sub method {
119 0     0 0   my $self = shift;
120 0   0       return $self->_handler($self->{method} ||= {}, '*', @_);
121             }
122              
123             sub methods {
124 0     0 0   my $self = shift;
125 0           return $self->_handlers($self->{method});
126             }
127              
128             sub _method {
129 0     0     my ($self, $method) = splice @_, 0, 2;
130              
131 0 0         return $self->method($method) if !@_;
132              
133 0 0         if (@_ == 1) {
134 0 0 0       return $self->route(shift)->method($method)
135             if defined $_[0] && !ref $_[0];
136              
137 0           $self->method($method, shift);
138 0           return $self;
139             }
140              
141 0           $self->route(shift)->method($method, shift) while @_;
142 0           return $self;
143             }
144              
145 0     0 0   sub get { shift->_method('GET', @_) }
146 0     0 0   sub post { shift->_method('POST', @_) }
147 0     0 0   sub put { shift->_method('PUT', @_) }
148 0     0 0   sub delete { shift->_method('DELETE', @_) }
149 0     0 0   sub all { shift->_method('*', @_) }
150              
151             sub error {
152 0     0 0   my $self = shift;
153 0   0       return $self->_handler($self->{error} ||= {}, HTTP_INTERNAL_SERVER_ERROR, @_);
154             }
155              
156             sub errors {
157 0     0 0   my $self = shift;
158 0           return $self->_handlers($self->{error});
159             }
160              
161             sub prepare {
162 0     0 0   my $self = shift;
163 0 0         return $self->_handler($self, undef, 'prepare', @_ ? shift : ());
164             }
165              
166             sub finalize {
167 0     0 0   my $self = shift;
168 0 0         return $self->_handler($self, undef, 'finalize', @_ ? shift : ());
169             }
170              
171             __PACKAGE__->mk_accessors(qw(rule));
172              
173             1;