File Coverage

blib/lib/Dancer/Route/Registry.pm
Criterion Covered Total %
statement 79 83 95.1
branch 20 24 83.3
condition 7 8 87.5
subroutine 14 15 93.3
pod 1 8 12.5
total 121 138 87.6


line stmt bran cond sub pod time code
1             package Dancer::Route::Registry;
2             our $AUTHORITY = 'cpan:SUKRIA';
3             # ABSTRACT: Route registry for Dancer
4             $Dancer::Route::Registry::VERSION = '1.3520';
5 170     170   1268 use strict;
  170         381  
  170         5166  
6 170     170   950 use warnings;
  170         408  
  170         4177  
7 170     170   907 use Carp;
  170         394  
  170         9421  
8 170     170   76524 use Dancer::Route;
  170         669  
  170         7444  
9 170     170   1283 use base 'Dancer::Object';
  170         523  
  170         19700  
10 170     170   1407 use Dancer::Logger;
  170         441  
  170         5261  
11 170     170   1162 use Dancer::Exception qw(:all);
  170         615  
  170         168068  
12              
13             Dancer::Route::Registry->attributes(qw( id ));
14              
15             my $id = 1;
16              
17             sub init {
18 114     114 1 451 my ($self) = @_;
19              
20 114 50       756 unless (defined $self->{id}) {
21 114         806 $self->id($id++);
22             }
23              
24             # Routes are stored here. Keys are route methods, and values are
25             # arrays of routes. Routes with options are stored in the
26             # beginning of the array while routes without options are stored
27             # at the end.
28 114         463 $self->{routes} = {};
29              
30             # Keep track of the border between routes with and without
31             # options, so that routes with options can be easily inserted into
32             # its routes array.
33 114         350 $self->{routes_border} = {};
34              
35 114         288 return $self;
36             }
37              
38             sub is_empty {
39 2     2 0 9 my ($self) = @_;
40 2         8 for my $method ( keys %{ $self->routes } ) {
  2         13  
41 1 50       4 return 0 if $self->routes($method);
42             }
43 1         11 return 1;
44             }
45              
46             # replace any ':foo' by '(.+)' and stores all the named
47             # matches defined in $REG->{route_params}{$route}
48             sub routes {
49 3466     3466 0 6020 my ($self, $method) = @_;
50              
51 3466 100       6099 if ($method) {
52 3464         5666 my $route = $self->{routes}{$method};
53 3464 100       10627 return $route ? $route : [];
54             }
55             else {
56 2         13 return $self->{routes};
57             }
58             }
59              
60             sub add_route {
61 1438     1438 0 2682 my ($self, $route) = @_;
62 1438   100     3433 $self->{routes}{$route->method} ||= [];
63 1438         2353 my @registered = @{$self->routes($route->method)};
  1438         3061  
64 1438         2633 my $last = $registered[-1];
65 1438 100       4756 $route->set_previous($last) if defined $last;
66              
67             # Routes are stored in the order they are declared. However,
68             # routes with options (such as ajax routes) are stored before
69             # routes without options. This way, we can have the following
70             # routes:
71             #
72             # get '/' => sub {};
73             # get qr{.*} => sub {};
74             # ajax '/' => sub {};
75             # ajax qr{.*} => sub {};
76             #
77             # And the user won't have to declare the ajax routes before the
78             # get routes.
79 1438 100       2000 if (keys %{$route->{options}}) {
  1438         3392  
80 11         26 splice @{$self->routes($route->method)},
81 11         22 $self->{routes_border}{$route->method}++,
82             0,
83             $route;
84             }
85             else {
86 1427         2139 push @{$self->routes($route->method)}, $route;
  1427         3025  
87             }
88              
89 1438         7988 return $route;
90             }
91              
92             # sugar for add_route
93              
94             sub register_route {
95 1439     1439 0 3782 my ($self, %args) = @_;
96              
97             # look if the caller (where the route is declared) exists as a Dancer::App
98             # object
99 1439         7928 my ($package) = caller(2);
100 1439 100 100     6435 if ($package && Dancer::App->app_exists($package)) {
101 651         1685 my $app = Dancer::App->get($package);
102 651         1757 my $route = Dancer::Route->new(prefix => $app->prefix, %args);
103 650         1706 return $app->registry->add_route($route);
104             }
105             else {
106              
107             # FIXME maybe this code is useless, drop it later if so
108 788         2684 my $route = Dancer::Route->new(%args);
109 788         1840 return $self->add_route($route);
110             }
111             }
112              
113             # sugar for Dancer.pm
114             # class, any, ARRAY(0x9864818), '/path', CODE(0x990ac88)
115             # or
116             # class, any, '/path', CODE(0x990ac88)
117             sub any_add {
118 24     24 0 126 my ($self, $pattern, @rest) = @_;
119              
120 24         171 my @methods = qw(get post put patch delete options head);
121              
122 24 100       164 if (ref($pattern) eq 'ARRAY') {
123 19         100 @methods = @$pattern;
124             # 'get' defaults to 'get' and 'head'
125 38         220 push @methods, 'head' if ((grep { $_ eq 'get' } @methods) and
126 19 100 66     63 not (grep { $_ eq 'head' } @methods));
  4         26  
127 19         87 $pattern = shift @rest;
128             }
129              
130             raise core_route => "Syntax error, methods should be provided as an ARRAY ref"
131 24 100       91 if grep {$_ eq $pattern} @methods;
  75         217  
132              
133 23         145 $self->universal_add($_, $pattern, @rest) for @methods;
134 23         130 return scalar(@methods);
135             }
136              
137             sub universal_add {
138 1439     1439 0 3365 my ($self, $method, $pattern, @rest) = @_;
139              
140 1439         2267 my %options;
141             my $code;
142              
143 1439 100       3507 if (@rest == 1) {
144 1427         2230 $code = $rest[0];
145             }
146             else {
147 12         24 %options = %{$rest[0]};
  12         60  
148 12         29 $code = $rest[1];
149             }
150              
151 1439         4815 my %route_args = (
152             method => $method,
153             code => $code,
154             options => \%options,
155             pattern => $pattern,
156             );
157              
158 1439         4334 return $self->register_route(%route_args);
159             }
160              
161             # look for a route in the given array
162             sub find_route {
163 0     0 0   my ($self, $r, $reg) = @_;
164 0           foreach my $route (@$reg) {
165 0 0         return $route if $r->equals($route);
166             }
167 0           return;
168             }
169              
170             1;
171              
172             __END__