File Coverage

blib/lib/Kelp/Routes.pm
Criterion Covered Total %
statement 142 147 96.6
branch 55 64 85.9
condition 36 48 75.0
subroutine 22 22 100.0
pod 9 9 100.0
total 264 290 91.0


line stmt bran cond sub pod time code
1             package Kelp::Routes;
2              
3 41     41   549185 use Kelp::Base;
  41         96  
  41         287  
4              
5 41     41   306 use Carp;
  41         95  
  41         3046  
6 41     41   398 use Plack::Util;
  41         91  
  41         1215  
7 41     41   224 use Kelp::Util;
  41         96  
  41         1371  
8 41     41   23864 use Kelp::Routes::Location;
  41         132  
  41         355  
9 41     41   300 use Try::Tiny;
  41         77  
  41         127811  
10              
11             our @CARP_NOT = qw(Kelp::Module::Routes);
12              
13             attr base => ''; # the default is set by config module
14             attr rebless => 0; # do not rebless app by default
15             attr pattern_obj => 'Kelp::Routes::Pattern';
16             attr fatal => 0;
17             attr routes => sub { [] };
18             attr names => sub { {} };
19              
20             # Cache
21             attr cache => sub {
22             my $self = shift;
23             my %cache;
24              
25             Plack::Util::inline_object(
26             get => sub { $cache{$_[0]} },
27             set => sub { $cache{$_[0]} = $_[1] },
28             clear => sub { %cache = () }
29             );
30             };
31              
32             sub add
33             {
34 250     250 1 13416 my ($self, $pattern, $descr, $parent) = @_;
35 250 100 66     1069 $parent = {} if !$parent || ref $parent ne 'HASH';
36              
37 250         811 my $route = $self->_parse_route($parent, $pattern, $descr);
38              
39 241         982 Kelp::Util::_DEBUG(routes => 'Added route: ', $route);
40              
41 241         634 return $self->_build_location($route);
42             }
43              
44             sub clear
45             {
46 27     27 1 28368 my ($self) = @_;
47              
48 27         114 $self->routes([]);
49 27         87 $self->cache->clear;
50 27         92 $self->names({});
51             }
52              
53             sub url
54             {
55 15     15 1 38 my $self = shift;
56 15   33     52 my $name = shift // croak "Route name is missing";
57 15 50       61 my %args = @_ == 1 ? %{$_[0]} : @_;
  0         0  
58              
59 15 100       78 return $name unless exists $self->names->{$name};
60 10         33 my $route = $self->routes->[$self->names->{$name}];
61 10         44 return $route->build(%args);
62             }
63              
64             sub _build_location
65             {
66             # build a specific location object on which ->add can be called again
67 241     241   477 my ($self, $route) = @_;
68              
69 241         1356 return Kelp::Routes::Location->new(
70             router => $self,
71             parent => $route,
72             );
73             }
74              
75             sub _message
76             {
77 23     23   67 my ($self, $type_str, @parts) = @_;
78 23         48 my $message = "[ROUTES] $type_str: ";
79              
80 23         49 for my $part (@parts) {
81 41   50     92 $part //= '';
82 41         272 $part =~ s/ at .+? line \d+.\n//g; # way prettier errors
83             }
84              
85 23         1370 return $message . join ' - ', @parts;
86             }
87              
88             sub _error
89             {
90 22     22   62 my ($self, @parts) = @_;
91              
92 22 100       101 croak $self->_message('ERROR', @parts) if $self->fatal;
93 13         38 carp $self->_message('WARNING, route is skipped', @parts);
94 13         2640 return;
95             }
96              
97             sub _warning
98             {
99 1     1   4 my ($self, @parts) = @_;
100              
101 1         5 carp $self->_message('WARNING', @parts);
102             }
103              
104             sub _parse_route
105             {
106 263     263   665 my ($self, $parent, $key, $val) = @_;
107              
108             # Scalar, e.g. 'bar#foo'
109             # CODE, e.g. sub { ... }
110 263 100 100     1363 if (!ref $val || ref $val eq 'CODE') {
111 186         612 $val = {to => $val};
112             }
113              
114             # Sanity check
115 263 100       846 if (ref $val ne 'HASH') {
116 1         6 return $self->_error('Route description must be a string, CODE or HASH');
117             }
118              
119             # Handle key in form of [METHOD => 'pattern']
120 262 100       720 if (ref $key eq 'ARRAY') {
121 23 50       59 if ((grep { defined } @$key) != 2) {
  46         130  
122 0         0 return $self->_error("Path as an ARRAY is expected to have two parameters");
123             }
124              
125 23         57 my ($method, $pattern) = @$key;
126 23 100       41 if (!grep { $method eq $_ } qw/GET POST PUT DELETE/) {
  92         205  
127 1         6 $self->_warning("Using an odd method '$method'");
128             }
129              
130 23         62 $val->{method} = $method;
131 23         49 $key = $pattern;
132             }
133              
134             # Only SCALAR and Regexp allowed
135 262 100 100     845 if (ref $key && ref $key ne 'Regexp') {
136 2         14 return $self->_error("Pattern '$key' can not be computed");
137             }
138              
139 260         690 $val->{pattern} = $key;
140              
141             # Format and load the target of 'to'
142 260         455 my $error;
143             try {
144 260     260   14839 $val->{to} = $self->format_to($val->{to});
145 252         795 $val->{dest} = $self->load_destination($val->{to});
146             }
147             catch {
148 18     18   9549 $error = $_;
149 260         7020 };
150              
151 260 100 66     6626 if (!defined $val->{dest} || $error) {
152 18         128 return $self->_error("Invalid destination for route '$key'", $error);
153             }
154              
155             # store tree for later and set up bridge based on it
156 242         556 my $tree = delete $val->{tree};
157 242 50 33     742 if ($tree && (ref $tree ne 'ARRAY' || @$tree % 2 != 0)) {
      66        
158 0         0 return $self->_error("Tree must be an even-sized ARRAY");
159             }
160 242   100     1311 $val->{bridge} ||= defined $tree;
161              
162             # psgi + bridge is incompatible, as psgi route will only render (not return true values)
163 242 100 100     732 if ($val->{psgi} && $val->{bridge}) {
164 1         5 return $self->_error("Route '$key' cannot have both 'psgi' and 'bridge'");
165             }
166              
167             # Adjust the destination for psgi
168             $val->{dest} = $self->wrap_psgi($val->{to}, $val->{dest})
169 241 100       684 if $val->{psgi};
170              
171             # Credit stuff from tree parent, if possible
172 241 100       607 if (defined $parent->{pattern}) {
173 19 100 100     81 if ($val->{name} && $parent->{name}) {
174 13         42 $val->{name} = $parent->{name} . '_' . $val->{name};
175             }
176 19         62 $val->{pattern} = $parent->{pattern} . $val->{pattern};
177             }
178              
179             # Can now add the object to routes
180 241         709 my $route = $self->build_pattern($val);
181 241         582 push @{$self->routes}, $route;
  241         787  
182              
183             # Add route index to names
184 241 100       745 if (my $name = $val->{name}) {
185 26 50       71 if (exists $self->names->{$name}) {
186 0         0 $self->_warning("Multiple routes named '$name'");
187             }
188 26         49 $self->names->{$name} = $#{$self->routes};
  26         57  
189             }
190              
191             # handle further tree levels, if any
192 241   100     1161 $tree //= [];
193 241         693 while (@$tree) {
194 13         44 my ($k, $v) = splice(@$tree, 0, 2);
195 13         62 $self->_parse_route($val, $k, $v);
196             }
197              
198 241         907 return $route;
199             }
200              
201             # Override to change what 'to' values are valid
202             sub format_to
203             {
204 260     260 1 647 my ($self, $to) = @_;
205 260         511 my $ref = ref $to;
206              
207 260 100 100     1843 if (!defined $to) {
    100 33        
208 4         392 croak 'missing';
209             }
210             elsif (!$to || ($ref && $ref ne 'CODE')) {
211 4         59 croak 'neither a string nor a coderef';
212             }
213              
214 252 100       783 $to = Kelp::Util::camelize($to, $self->base)
215             unless $ref;
216              
217 252         711 return $to;
218             }
219              
220             # Override to change the way the application loads the destination from 'to'
221             sub load_destination
222             {
223 252     252 1 531 my ($self, $to) = @_;
224 252         479 my $ref = ref $to;
225              
226 252 100 66     1054 if (!$ref && $to) {
    50          
227              
228             # Load the class, if there is one
229 119 100       311 if (my $class = Kelp::Util::extract_class($to)) {
    100          
230 103         285 my $method = Kelp::Util::extract_function($to);
231              
232 103         314 Kelp::Util::load_package($class);
233              
234 101         665 my $method_code = $class->can($method);
235 101 100       269 croak "method '$method' does not exist in class '$class'"
236             unless $method_code;
237              
238 99 100 66     266 return [$self->rebless && $class->isa($self->base) ? $class : undef, $method_code];
239             }
240             elsif (exists &$to) {
241              
242             # Move to reference
243 10         20 return [undef, \&{$to}];
  10         68  
244             }
245             else {
246 6         72 croak "function '$to' does not exist";
247             }
248             }
249             elsif ($ref) {
250 133 50       365 croak "don't know how to load from reftype '$ref'"
251             unless $ref eq 'CODE';
252              
253 133         1058 return [undef, $to];
254             }
255              
256 0         0 return undef;
257             }
258              
259             # Override to change the way a psgi application is adapted to kelp
260             sub wrap_psgi
261             {
262 5     5 1 9 my ($self, $to, $destination) = @_;
263              
264             # adjust the subroutine to load
265             # don't adjust the controller (index 0) to still call the proper hooks if
266             # it was configured to be a controller action
267              
268 5         22 $destination->[1] = Kelp::Util::adapt_psgi($destination->[1]);
269 5         12 return $destination;
270             }
271              
272             # Override to use a custom pattern object
273             sub build_pattern
274             {
275             return Kelp::Util::load_package($_[0]->pattern_obj)->new(
276 241     241 1 852 %{$_[1]}
  241         1630  
277             );
278             }
279              
280             sub match
281             {
282 302     302 1 37143 my ($self, $path, $method) = @_;
283 302   100     944 $method //= '';
284              
285             # Look for this path and method in the cache. If found,
286             # return the array of routes that matched the previous time.
287             # If not found, then return all routes.
288 302         756 my $key = "$path:$method";
289 302         1022 my $routes = $self->cache->get($key);
290 302 100       982 if (!defined $routes) {
291              
292             # Look through all routes, grep the ones that match and sort them with
293             # the compare method. Perl sort function is stable, meaning it will
294             # preserve the initial order of records it considers equal. This means
295             # that the order of registering routes is crucial when a couple of
296             # routes are registered with the same pattern: routes defined earlier
297             # will be run first and the first one to render will end the execution
298             # chain.
299             @$routes =
300 42         146 sort { $a->compare($b) }
301 234         427 grep { $_->match($path, $method) } @{$self->routes};
  1151         2757  
  234         685  
302              
303 234         708 $self->cache->set($key, $routes);
304             }
305             else {
306             # matching fills the route parameters
307 68         481 $_->match($path, $method) for @$routes;
308             }
309              
310             # shallow copy to make sure nothing pollutes the cache
311 302         1197 return [@$routes];
312             }
313              
314             # dispatch does not do many sanity checks on the destination, since those are
315             # done in format_to and load_destination. A single check is present, which
316             # lazy-computes dest if it is not set (since some code might have overrode add).
317             sub dispatch
318             {
319 266     266 1 620 my ($self, $app, $route) = @_;
320 266 50       749 $app || die "Application instance required";
321 266 50       1155 $route || die "No route pattern instance supplied";
322              
323 266         758 my $dest = $route->dest;
324 266 50       680 $route->dest($self->load_destination($route->to))
325             unless $dest;
326              
327 266         527 my ($controller, $action) = @{$dest};
  266         678  
328 266         711 my $c = $app->context->set_controller($controller);
329              
330 266         691 $app->context->run_method(before_dispatch => ($route->to));
331 266         1001 return $action->($c, @{$route->param});
  266         656  
332             }
333              
334             1;
335              
336             __END__
337              
338             =pod
339              
340             =head1 NAME
341              
342             Kelp::Routes - Routing for a Kelp app
343              
344             =head1 SYNOPSIS
345              
346             use Kelp::Routes;
347             my $r = Kelp::Routes->new( base => 'MyApp' );
348             $r->add( '/home', 'home' );
349              
350             =head1 DESCRIPTION
351              
352             The router provides the connection between the HTTP requests and the web
353             application code. It tells the application I<"If you see a request coming to
354             *this* URI, send it to *that* subroutine for processing">. For example, if a
355             request comes to C</home>, then send it to C<sub home> in the current
356             namespace. The process of capturing URIs and sending them to their corresponding
357             code is called routing.
358              
359             This router was specifically crafted as part of the C<Kelp> web framework. It
360             is, however, possible to use it on its own, if needed.
361              
362             It provides a simple, yet sophisticated routing utilizing Perl 5.10's
363             regular expressions, which makes it fast, robust and reliable.
364              
365             The routing process can roughly be broken down into three steps:
366              
367             =over
368              
369             =item B<Adding routes>
370              
371             First you create a router object:
372              
373             my $r = Kelp::Routes->new();
374              
375             Then you add your application's routes and their descriptions:
376              
377             $r->add( '/path' => 'Module::function' );
378             ...
379              
380             If you add a trailing slash to your route, it will be mandatory in request path
381             for the route to match. If you don't add it, it will be optional.
382              
383             =item B<Matching>
384              
385             Once you have your routes added, you can match with the L</match> subroutine.
386              
387             my $patterns_aref = $r->match( $path, $method );
388              
389             The Kelp framework already does matching for you, so you may never
390             have to do your own matching. The above example is provided only for
391             reference.
392              
393             The order of patterns in C<$patterns_aref> is the order in which the framework
394             will be executing the routes. Bridges are always before regular routes, and
395             shorter routes come first within a given type (bridge or no-bridge). If route
396             patterns are exactly the same, the ones defined earlier will also be executed
397             earlier.
398              
399             Routes will continue going through that execution chain until one of the
400             bridges return a false value, one of the non-bridges return a defined value, or
401             one of the routes renders something explicitly using methods in
402             L<Kelp::Response>. It is generally not recommended to have more than one
403             non-bridge route matching a pattern as it may be harder to debug which one gets
404             to actually render a response.
405              
406             =item B<Building URLs from routes>
407              
408             You can name each of your routes, and use that name later to build a URL:
409              
410             $r->add( '/begin' => { to => 'function', name => 'home' } );
411             my $url = $r->url('home'); # /begin
412              
413             This can be used in views and other places where you need the full URL of
414             a route.
415              
416             =back
417              
418             =head1 PLACEHOLDERS
419              
420             Often routes may get more complicated. They may contain variable parts. For
421             example this one C</user/1000> is expected to do something with user ID 1000.
422             So, in this case we need to capture a route that begins with C</user/> and then
423             has something else after it.
424              
425             Naturally, when it comes to capturing routes, the first instinct of the Perl
426             programmer is to use regular expressions, like this:
427              
428             qr{/user/(\d+)} -> "sub home"
429              
430             This module will let you do that, however regular expressions can get very
431             complicated, and it won't be long before you lose track of what does what.
432              
433             This is why a good router (this one included) allows for I<named placeholders>.
434             These are words prefixed with special symbols, which denote a variable piece in
435             the URI. To use the above example:
436              
437             "/user/:id" -> "sub home"
438              
439             It looks a little cleaner.
440              
441             Placeholders are variables you place in the route path. They are identified by
442             a prefix character and their names must abide to the rules of a regular Perl
443             variable. If necessary, curly braces can be used to separate placeholders from
444             the rest of the path.
445              
446             There are three types of place holders:
447              
448             =head2 Explicit
449              
450             These placeholders begin with a column (C<:>) and must have a value in order for the
451             route to match. All characters are matched, except for the forward slash.
452              
453             $r->add( '/user/:id' => 'Module::sub' );
454             # /user/a -> match (id = 'a')
455             # /user/123 -> match (id = 123)
456             # /user/ -> no match
457             # /user -> no match
458             # /user/10/foo -> no match
459              
460             $r->add( '/page/:page/line/:line' => 'Module::sub' );
461             # /page/1/line/2 -> match (page = 1, line = 2)
462             # /page/bar/line/foo -> match (page = 'bar', line = 'foo')
463             # /page/line/4 -> no match
464             # /page/5 -> no match
465              
466             $r->add( '/{:a}ing/{:b}ing' => 'Module::sub' );
467             # /walking/singing -> match (a = 'walk', b = 'sing')
468             # /cooking/ing -> no match
469             # /ing/ing -> no match
470              
471             =head2 Optional
472              
473             Optional placeholders begin with a question mark C<?> and denote an optional
474             value. You may also specify a default value for the optional placeholder via
475             the L</defaults> option. Again, like the explicit placeholders, the optional
476             ones capture all characters, except the forward slash.
477              
478             $r->add( '/data/?id' => 'Module::sub' );
479             # /bar/foo -> match ( id = 'foo' )
480             # /bar/ -> match ( id = undef )
481             # /bar -> match ( id = undef )
482              
483             $r->add( '/:a/?b/:c' => 'Module::sub' );
484             # /bar/foo/baz -> match ( a = 'bar', b = 'foo', c = 'baz' )
485             # /bar/foo -> match ( a = 'bar', b = undef, c = 'foo' )
486             # /bar -> no match
487             # /bar/foo/baz/moo -> no match
488              
489             Optional default values may be specified via the C<defaults> option.
490              
491             $r->add(
492             '/user/?name' => {
493             to => 'Module::sub',
494             defaults => { name => 'hank' }
495             }
496             );
497              
498             # /user -> match ( name = 'hank' )
499             # /user/ -> match ( name = 'hank' )
500             # /user/jane -> match ( name = 'jane' )
501             # /user/jane/cho -> no match
502              
503             =head2 Wildcards
504              
505             The wildcard placeholders expect a value and capture all characters, including
506             the forward slash.
507              
508             $r->add( '/:a/*b/:c' => 'Module::sub' );
509             # /bar/foo/baz/bat -> match ( a = 'bar', b = 'foo/baz', c = 'bat' )
510             # /bar/bat -> no match
511              
512             =head2 Slurpy
513              
514             Slurpy placeholders will take as much as they can or nothing. It's a mix of a
515             wildcard and optional placeholder.
516              
517             $r->add( '/path/>rest' => 'Module::sub' );
518             # /path -> match ( rest = undef )
519             # /path/foo -> match ( rest = '/foo' )
520             # /path/foo/bar -> match ( rest = '/foo/bar' )
521              
522             Just like optional parameters, they may have C<defaults>.
523              
524             =head2 Using curly braces
525              
526             Curly braces may be used to separate the placeholders from the rest of the
527             path:
528              
529             $r->add( '/{:a}ing/{:b}ing' => 'Module::sub' );
530             # /looking/seeing -> match ( a = 'look', b = 'see' )
531             # /ing/ing -> no match
532              
533             $r->add( '/:a/{?b}ing' => 'Module::sub' );
534             # /bar/hopping -> match ( a = 'bar', b = 'hopp' )
535             # /bar/ing -> match ( a = 'bar' )
536             # /bar -> no match
537              
538             $r->add( '/:a/{*b}ing/:c' => 'Module::sub' );
539             # /bar/hop/ping/foo -> match ( a = 'bar', b = 'hop/p', c = 'foo' )
540             # /bar/ing/foo -> no match
541              
542             =head1 BRIDGES
543              
544             The L</match> subroutine will stop and return the route that best matches the
545             specified path. If that route is marked as a bridge, then L</match> will
546             continue looking for another match, and will eventually return an array of one or
547             more routes. Bridges can be used for authentication or other route preprocessing.
548              
549             $r->add( '/users/*', { to => 'Users::auth', bridge => 1 } );
550             $r->add( '/users/:action' => 'Users::dispatch' );
551              
552             The above example will require F</users/profile> to go through two
553             subroutines: C<Users::auth> and C<Users::dispatch>:
554              
555             my $arr = $r->match('/users/view');
556             # $arr is an array of two routes now, the bridge and the last one matched
557              
558             Just like regular routes, bridges can render a response, but it must be done
559             manually by calling C<< $self->res->render() >> or other methods from
560             L<Kelp::Response>. When a render happens in a bridge, its return value will be
561             discarded and no other routes in chain will be run as if a false value was
562             returned. For example, this property can be used to render a login page in
563             place instead of a 403 response, or just simply redirect to one.
564              
565             =head1 TREES
566              
567             A quick way to add bridges is to use the L</tree> option. It allows you to
568             define all routes under a bridge. Example:
569              
570             $r->add(
571             '/users/*' => {
572             to => 'users#auth',
573             name => 'users',
574             tree => [
575             '/profile' => {
576             name => 'profile',
577             to => 'users#profile'
578             },
579             '/settings' => {
580             name => 'settings',
581             to => 'users#settings',
582             tree => [
583             '/email' => { name => 'email', to => 'users#email' },
584             '/login' => { name => 'login', to => 'users#login' }
585             ]
586             }
587             ]
588             }
589             );
590              
591             The above call to C<add> causes the following to occur under the hood:
592              
593             =over
594              
595             =item
596              
597             The paths of all routes inside the tree are joined to the path of their
598             parent, so the following five new routes are created:
599              
600             /users -> MyApp::Users::auth
601             /users/profile -> MyApp::Users::profile
602             /users/settings -> MyApp::Users::settings
603             /users/settings/email -> MyApp::Users::email
604             /users/settings/login -> MyApp::Users::login
605              
606             =item
607              
608             The names of the routes are joined via C<_> with the name of their parent:
609              
610             /users -> 'users'
611             /users/profile -> 'users_profile'
612             /users/settings -> 'users_settings'
613             /users/settings/email -> 'users_settings_email'
614             /users/settings/login -> 'users_settings_login'
615              
616             =item
617              
618             The C</users> and C</users/settings> routes are automatically marked as
619             bridges, because they contain a tree.
620              
621             =back
622              
623             =head1 LOCATIONS
624              
625             Instead of using trees, you can alternatively use locations returned by the
626             L</add> method, which will work exactly the same. The object returned from
627             C<add> will be a facade implementing a localized version of C<add>:
628              
629             # /users
630             my $users = $r->add( '/users' => {
631             to => 'users#auth',
632             name => 'users',
633             } );
634              
635             # /users/profile, /users becomes a bridge
636             my $profile = $users->add( '/profile' => {
637             name => 'profile',
638             to => 'users#profile'
639             } );
640              
641             # /users/settings, has its own tree so it's a bridge
642             my $settings = $users->add( '/settings' => {
643             name => 'settings',
644             to => 'users#settings',
645             tree => [
646             '/email' => { name => 'email', to => 'users#email' },
647             '/login' => { name => 'login', to => 'users#login' }
648             ],
649             } );
650              
651             =head1 PLACK APPS
652              
653             Kelp makes it easy to nest Plack/PSGI applications inside your Kelp app. All
654             you have to do is provide a Plack application runner in C<to> and set C<psgi>
655             to a true value.
656              
657             use Plack::App::File;
658              
659             $r->add( '/static/>path' => {
660             to => Plack::App::File->new(root => "/path/to/static")->to_app,
661             psgi => 1,
662             });
663              
664             You must provide a proper placeholder at the end if you want your app to occpy
665             all the subpaths under the base path. A slurpy placeholder like C<< >path >>
666             works best and mimics L<Plack::App::URLMap>'s behavior. B<It is an error to
667             only provide a placeholder in the middle of the pattern>. Kelp will take B<the
668             last placeholder> and assume it comes B<after> the base route. If it doesn't,
669             the paths set for the nested app will be wrong.
670              
671             Note that a route cannot have C<psgi> and C<bridge> (or C<tree>) simultaneously.
672              
673             =head1 PLACK MIDDLEWARES
674              
675             If your route is not a Plack app and you want to reuse Plack middleware when
676             handling it, you may use C<psgi_middleware> and wrap L<Kelp/NEXT_APP>:
677              
678             use Plack::Middleware::ContentMD5;
679              
680             $r->add('/checksummed' => {
681             to => 'get_content',
682             psgi_middleware => Plack::Middleware::ContentMD5->wrap(Kelp->NEXT_APP),
683             });
684              
685             You can also apply C<psgi_middleware> to bridges. Also, it is more readable to
686             use L<Plack::Builder> for this:
687              
688             use Plack::Builder;
689              
690             $r->add('/api' => {
691             to => sub { 1 }, # always pass through
692             bridge => 1,
693             psgi_middleware => builder {
694             enable 'Auth::Basic', authenticator => sub { ... };
695             Kelp->NEXT_APP;
696             },
697             });
698              
699             Now everything under C</api> will go through this middleware. Note however that
700             C<psgi_middleware> is app-level middleware, not route-level. This means that
701             even if your bridge was to cut off traffic (return false value), all middleware
702             declared in routes will still have to run regardless, and it will run even
703             before the first route is executed. Don't think about it as I<"middleware for a
704             route">, but rather as I<"middleware for an app which is going to execute that
705             route">.
706              
707             It is worth noting that using middleware in your routes will result in better
708             performance than global middleware. Having a ton of global middleware, even if
709             bound to a specific route, may result in quite a big overhead since it will
710             have to do a bunch of regular expression matches or string comparisons for
711             every route in your system. On the other hand, Kelp router is pretty optimized
712             and will only do the matching once, and only the matched routes will have to go
713             through this middleware.
714              
715             =head1 ATTRIBUTES
716              
717             =head2 base
718              
719             Sets the base class for the routes destinations.
720              
721             my $r = Kelp::Routes->new( base => 'MyApp' );
722              
723             This will prepend C<MyApp::> to all route destinations.
724              
725             $r->add( '/home' => 'home' ); # /home -> MyApp::home
726             $r->add( '/user' => 'user#home' ); # /user -> MyApp::User::home
727             $r->add( '/view' => 'User::view' ); # /view -> MyApp::User::view
728              
729             A Kelp application will automatically set this value to the name of the main
730             class. If you need to use a route located in another package, you must prefix
731             it with a plus sign:
732              
733             # Problem:
734              
735             $r->add( '/outside' => 'Outside::Module::route' );
736             # /outside -> MyApp::Outside::Module::route
737             # (most likely not what you want)
738              
739             # Solution:
740              
741             $r->add( '/outside' => '+Outside::Module::route' );
742             # /outside -> Outside::Module::route
743              
744             =head2 rebless
745              
746             Switch used to set whether the router should rebless the app into the
747             controller classes (subclasses of L</base>). Boolean value, false by default.
748              
749             =head2 pattern_obj
750              
751             A full class name of an object used for each pattern, L<Kelp::Routes::Pattern>
752             by default. Works the same as its counterpart L<Kelp/request_obj>.
753              
754             =head2 fatal
755              
756             A boolean. If set to true, errors in route definitions will crash the
757             application instead of just raising a warning. False by default.
758              
759             =head2 cache
760              
761             Routes will be cached in memory, so repeating requests will be dispatched much
762             faster. The default cache entries never expire, so it will continue to grow as
763             long as the process lives. It also stores full L<Kelp::Routes::Pattern>
764             objects, which is fast and light when stored in Perl but makes it cumbersome
765             when they are serialized.
766              
767             The C<cache> attribute can optionally be initialized with an instance of a
768             caching module with interface similar to L<CHI> and L<Cache>. This allows for
769             giving them expiration time and possibly sharing them between processes, but
770             extra care must be taken to properly serialize them. Patterns are sure to
771             contain hardly serializable code references and are way heavier when
772             serialized. The cache should probably be configured to have an in-memory L1
773             cache which will map a serialized route identifier (stored in the main cache)
774             to a pattern object registered in the router. The module interface should at
775             the very least provide the following methods:
776              
777             =head3 get($key)
778              
779             retrieve a key from the cache
780              
781             =head3 set($key, $value, $expiration)
782              
783             set a key in the cache
784              
785             =head3 clear()
786              
787             clear all cache
788              
789             The caching module should be initialized in the config file:
790              
791             # config.pl
792             {
793             modules_init => {
794             Routes => {
795             cache => Cache::Memory->new(
796             namespace => 'MyApp',
797             default_expires => '3600 sec'
798             );
799             }
800             }
801             }
802              
803             =head1 SUBROUTINES
804              
805             =head2 add
806              
807             Adds a new route definition to the routes array.
808              
809             $r->add( $path, $destination );
810              
811             C<$path> can be a path string, e.g. C<'/user/view'> or an ARRAY containing a
812             method and a path, e.g. C<[ PUT =E<gt> '/item' ]>.
813              
814             Returns an object on which you can call C<add> again. If you do, the original
815             route will become a bridge. It will work as if you included the extra routes in
816             the route's C<tree>.
817              
818             The route destination is very flexible. It can be one of these three things:
819              
820             =over
821              
822             =item
823              
824             A string name of a subroutine, for example C<"Users::item">. Using a C<#> sign
825             to replace C<::> is also allowed, in which case the name will get converted.
826             C<"users#item"> becomes C<"Users::item">.
827              
828             $r->add( '/home' => 'user#home' );
829              
830             =item
831              
832             A code reference.
833              
834             $r->add( '/system' => sub { return \%ENV } );
835              
836             =item
837              
838             A hashref with options.
839              
840             # GET /item/100 -> MyApp::Items::view
841             $r->add(
842             '/item/:id', {
843             to => 'items#view',
844             method => 'GET'
845             }
846             );
847              
848             See L</Destination Options> for details.
849              
850             =back
851              
852             =head3 Destination Options
853              
854             There are a number of options you can add to modify the behavior of the route,
855             if you specify a hashref for a destination:
856              
857             =head4 to
858              
859             Sets the destination for the route. It should be a subroutine name or CODE
860             reference.
861              
862             $r->add( '/home' => { to => 'users#home' } ); # /home -> MyApp::Users::home
863             $r->add( '/sys' => { to => sub { ... } }); # /sys -> execute code
864             $r->add( '/item' => { to => 'Items::handle' } ) ; # /item -> MyApp::Items::handle
865             $r->add( '/item' => { to => 'items#handle' } ); # Same as above
866              
867             =head4 method
868              
869             Specifies an HTTP method to be considered by L</match> when matching a route.
870              
871             # POST /item -> MyApp::Items::add
872             $r->add(
873             '/item' => {
874             method => 'POST',
875             to => 'items#add'
876             }
877             );
878              
879             A shortcut for the above is this:
880              
881             $r->add( [ POST => '/item' ] => 'items#add' );
882              
883             =head4 name
884              
885             Give the route a name, and you can always use it to build a URL later via the L</url>
886             subroutine.
887              
888             $r->add(
889             '/item/:id/:name' => {
890             to => 'items#view',
891             name => 'item'
892             }
893             );
894              
895             # Later
896             $r->url( 'item', id => 8, name => 'foo' ); # /item/8/foo
897              
898             =head4 check
899              
900             A hashref of checks to perform on the captures. It should contain capture
901             names and stringified regular expressions. Do not use C<^> and C<$> to denote
902             beginning and ending of the matched expression, because it will get embedded
903             in a bigger Regexp.
904              
905             $r->add(
906             '/item/:id/:name' => {
907             to => 'items#view',
908             check => {
909             id => '\d+', # id must be a digit
910             name => 'open|close' # name can be 'open' or 'close'
911             }
912             }
913             );
914              
915             =head4 defaults
916              
917             Set default values for optional placeholders.
918              
919             $r->add(
920             '/pages/?id' => {
921             to => 'pages#view',
922             defaults => { id => 2 }
923             }
924             );
925              
926             # /pages -> match ( id = 2 )
927             # /pages/ -> match ( id = 2 )
928             # /pages/4 -> match ( id = 4 )
929              
930             =head4 bridge
931              
932             If set to 1 this route will be treated as a bridge. Please see L</BRIDGES>
933             for more information.
934              
935             =head4 tree
936              
937             Creates a tree of sub-routes. See L</TREES> for more information and examples.
938              
939             =head2 url
940              
941             my $url = $r->url($path, @arguments);
942              
943             Builds an url from path and arguments. If the request is named a name can be specified instead.
944              
945             =head2 match
946              
947             Returns an array of L<Kelp::Routes::Pattern> objects that match the path
948             and HTTP method provided. Each object will contain a hash with the named
949             placeholders in L<Kelp::Routes::Pattern/named>, and an array with their
950             values in the order they were specified in the pattern in
951             L<Kelp::Routes::Pattern/param>.
952              
953             $r->add( '/:id/:name', "route" );
954             for my $pattern ( @{ $r->match('/15/alex') } ) {
955             $pattern->named; # { id => 15, name => 'alex' }
956             $pattern->param; # [ 15, 'alex' ]
957             }
958              
959             Routes that used regular expressions instead of patterns will only initialize
960             the C<param> array with the regex captures, unless those patterns are using
961             named captures in which case the C<named> hash will also be initialized.
962              
963             =head2 dispatch
964              
965             my $result = $r->dispatch($kelp, $route_pattern);
966              
967             Dispatches an instance of L<Kelp::Routes::Pattern> by running the route
968             destination specified in L<Kelp::Routes::Pattern/dest>. If dest is not set, it
969             will be computed using L</load_destination> with unformatted
970             L<Kelp::Routes::Pattern/to>.
971              
972             The C<$kelp> instance may be shallow-cloned and reblessed into another class if
973             it is a subclass of L</base> and L</rebless> is configured. Modifications made
974             to top-level attributes of C<$kelp> object will be gone after the action is
975             complete.
976              
977             =head2 build_pattern
978              
979             Override this method to do change the creation of the pattern. Same role as L<Kelp/build_request>.
980              
981             =head2 format_to
982              
983             Override this method to change the formatting process of L<Kelp::Routes::Pattern/to>. See code for details.
984              
985             =head2 load_destination
986              
987             Override this method to change the loading process of L<Kelp::Routes::Pattern/dest>. See code for details.
988              
989             =head2 wrap_psgi
990              
991             Override this method to change the way a Plack/PSGI application is extracted from a destination. See code for details.
992              
993             =head1 EXTENDING
994              
995             This is the default router class for each new Kelp application, but it doesn't
996             have to be. You can create your own subclass that better suits your needs. It's
997             generally enough to override the L</dispatch>, L</format_to> or
998             L</load_destination> methods.
999              
1000             =head1 ACKNOWLEDGEMENTS
1001              
1002             This module was inspired by L<Routes::Tiny>.
1003              
1004             =cut
1005