File Coverage

blib/lib/Kelp.pm
Criterion Covered Total %
statement 162 167 97.0
branch 42 52 80.7
condition 15 23 65.2
subroutine 44 46 95.6
pod 22 24 91.6
total 285 312 91.3


line stmt bran cond sub pod time code
1             package Kelp;
2              
3 39     39   319861 use Kelp::Base;
  39         113  
  39         273  
4              
5 39     39   385 use Carp qw/ longmess croak /;
  39         81  
  39         5232  
6 39     39   25037 use FindBin;
  39         60444  
  39         4587  
7 39     39   290 use Try::Tiny;
  39         76  
  39         2366  
8 39     39   21708 use Sys::Hostname;
  39         55998  
  39         2671  
9 39     39   292 use Plack::Util;
  39         90  
  39         1024  
10 39     39   247 use Class::Inspector;
  39         73  
  39         1121  
11 39     39   209 use List::Util qw(any);
  39         73  
  39         2807  
12 39     39   218 use Scalar::Util qw(blessed);
  39         109  
  39         158986  
13              
14             our $VERSION = '2.22';
15              
16             # Basic attributes
17             attr -host => hostname;
18             attr mode => $ENV{KELP_ENV} // $ENV{PLACK_ENV} // 'development';
19             attr -path => $FindBin::Bin;
20             attr -name => sub { (ref($_[0]) =~ /(\w+)$/) ? $1 : 'Noname' };
21             attr request_obj => 'Kelp::Request';
22             attr response_obj => 'Kelp::Response';
23             attr context_obj => 'Kelp::Context';
24             attr middleware_obj => 'Kelp::Middleware';
25              
26             # Debug
27             attr long_error => $ENV{KELP_LONG_ERROR} // 0;
28              
29             # The charset is set to UTF-8 by default in config module.
30             # No default here because we want to support 'undef' charset
31             attr charset => sub { $_[0]->config('charset') };
32             attr request_charset => sub { $_[0]->config('request_charset') };
33              
34             # Name the config module
35             attr config_module => 'Config';
36              
37             # Undocumented.
38             # Used to unlock the undocumented features of the Config module.
39             attr __config => undef;
40              
41             attr -loaded_modules => sub { {} };
42              
43             # Current context of the application - tracks the state application is in,
44             # especially when it comes to managing controller instances.
45             attr context => \&build_context;
46              
47             # registered application encoder modules
48             attr encoder_modules => sub { {} };
49              
50             # Initialization
51             sub new
52             {
53 52     52 1 7590591 my $self = shift->SUPER::new(@_);
54              
55 52         395 Kelp::Util::_DEBUG(1 => 'Loading essential modules...');
56              
57             # Always load these modules, but allow client to override
58 52         274 $self->_load_config();
59 51         275 $self->_load_routes();
60              
61 51         302 Kelp::Util::_DEBUG(1 => 'Loading modules from config...');
62              
63             # Load the modules from the config
64 51 100       254 if (defined(my $modules = $self->config('modules'))) {
65 49         248 $self->load_module($_) for (@$modules);
66             }
67              
68 51         260 Kelp::Util::_DEBUG(1 => 'Calling build method...');
69              
70 51         212 $self->build();
71 51         217 return $self;
72             }
73              
74             sub new_anon
75             {
76 6     6 1 445732 state $last_anon = 0;
77 6         16 my $class = shift;
78              
79             # make sure we don't eval something dodgy
80 6 100 66     108 die "invalid class for new_anon"
      100        
      66        
81             if ref $class # not a string
82             || !$class # not an empty string, undef or 0
83             || !Class::Inspector->loaded($class) # not a loaded class
84             || !$class->isa(__PACKAGE__) # not a correct class
85             ;
86              
87 4         235 my $anon_class = "Kelp::Anonymous::$class" . ++$last_anon;
88 4         10 my $err = do {
89 4         6 local $@;
90 4     2   628 my $eval_status = eval qq[
  2     1   19  
  2     1   5  
  2         19  
  1         9  
  1         2  
  1         10  
  1         10  
  1         2  
  1         10  
91             {
92             package $anon_class;
93             use parent -norequire, '$class';
94              
95             sub _real_class { '$class' }
96             }
97             1;
98             ];
99 4 50       44 $@ || !$eval_status;
100             };
101              
102 4 50       18 if ($err) {
103 0 0       0 die "Couldn't create anonymous Kelp instance: " .
104             (length $err > 1 ? $err : 'unknown error');
105             }
106              
107 4         38 return $anon_class->new(@_);
108             }
109              
110             sub _load_config
111             {
112 54     54   129 my $self = shift;
113 53         275 $self->load_module($self->config_module, extra => $self->__config);
114              
115 52         285 Kelp::Util::_DEBUG(config => 'Merged configuration: ', $self->config_hash);
116             }
117              
118             sub _load_routes
119             {
120 51     52   110 my $self = shift;
121 51         194 $self->load_module('Routes');
122             }
123              
124             # Create a shallow copy of the app, optionally blessed into a
125             # different subclass.
126             sub _clone
127             {
128 17     18   23 my $self = shift;
129 17   33     49 my $subclass = shift || ref($self);
130              
131 17 50       41 ref $self or croak '_clone requires instance';
132 17         356 return bless {%$self}, $subclass;
133             }
134              
135             sub load_module
136             {
137 203     203 1 38600 my ($self, $name, %args) = @_;
138              
139             # A module name with a leading + indicates it's already fully
140             # qualified (i.e., it does not need the Kelp::Module:: prefix).
141 203 100       828 my $prefix = $name =~ s/^\+// ? undef : 'Kelp::Module';
142              
143             # Make sure the module was not already loaded
144 203 50       752 return if $self->loaded_modules->{$name};
145              
146 203         1047 my $class = Plack::Util::load_class($name, $prefix);
147 202         4885 my $module = $self->loaded_modules->{$name} = $class->new(app => $self);
148              
149             # When loading the Config module itself, we don't have
150             # access to $self->config yet. This is why we check if
151             # config is available, and if it is, then we pull the
152             # initialization hash.
153 202         496 my $args_from_config = {};
154 202 100       1188 if ($self->can('config')) {
155 163   100     1071 $args_from_config = $self->config("modules_init.$name") // {};
156             }
157              
158 202         2033 Kelp::Util::_DEBUG(modules => "Loading $class module with args: ", {%$args_from_config, %args});
159              
160 202         1177 $module->build(%$args_from_config, %args);
161 201         945 return $module;
162             }
163              
164             # Override this one to add custom initializations
165             sub build
166       42 1   {
167             }
168              
169             # Override to use a custom context object
170             sub build_context
171             {
172 30     30 1 217 return Kelp::Util::load_package($_[0]->context_obj)->new(
173             app => $_[0],
174             );
175             }
176              
177             # Override to use a custom request object
178             sub build_request
179             {
180 252     252 1 1103 return Kelp::Util::load_package($_[0]->request_obj)->new(
181             app => $_[0],
182             env => $_[1],
183             );
184             }
185              
186             sub req
187             {
188 644     644 1 2084 my $self = shift;
189 644         1650 return $self->context->req(@_);
190             }
191              
192             # Override to use a custom response object
193             sub build_response
194             {
195 246     246 1 907 return Kelp::Util::load_package($_[0]->response_obj)->new(
196             app => $_[0],
197             );
198             }
199              
200             sub res
201             {
202 1068     1068 1 2268 my $self = shift;
203 1068         2363 return $self->context->res(@_);
204             }
205              
206             # Override to change what happens before the route is handled
207             sub before_dispatch
208             {
209 261     261 1 568 my ($self, $destination) = @_;
210              
211             # Log info about the route
212 261 100       1322 if ($self->can('logger')) {
213 1         3 my $req = $self->req;
214              
215 1         6 $self->info(
216             sprintf "%s: %s - %s %s - %s",
217             ref $self,
218             $req->address, $req->method,
219             $req->path, $destination
220             );
221             }
222             }
223              
224             # Override to change what happens when nothing gets rendered
225             sub after_unrendered
226             {
227 8     8 1 25 my ($self, $match) = @_;
228              
229             # render 404 if only briges matched
230 8 100       42 if ($match->[-1]->bridge) {
231 5         14 $self->res->render_404;
232             }
233              
234             # or die with error
235             else {
236 3         11 die $match->[-1]->to
237             . " did not render for method "
238             . $self->req->method;
239             }
240             }
241              
242             # Override to manipulate the end response
243             sub before_finalize
244             {
245 228     228 1 422 my $self = shift;
246 228         660 $self->res->header('X-Framework' => 'Perl Kelp');
247             }
248              
249             # Override this to wrap more middleware around the app
250             sub run
251             {
252 251     251 1 570 my $self = shift;
253 251     251   1325 my $app = sub { $self->psgi(@_) };
  251         228644  
254              
255 251         1260 Kelp::Util::_DEBUG(1 => 'Running the application...');
256              
257 251         986 my $middleware = Kelp::Util::load_package($self->middleware_obj)->new(
258             app => $self,
259             );
260              
261 251         1072 return $middleware->wrap($app);
262             }
263              
264             sub _psgi_internal
265             {
266 243     243   622 my ($self, $match) = @_;
267 243         673 my $req = $self->req;
268 243         582 my $res = $self->res;
269              
270             # Go over the entire route chain
271 243         607 for my $route (@$match) {
272              
273             # Dispatch
274 266         677 $req->named($route->named);
275 266         880 $req->route_name($route->name);
276 266         1137 my $data = $self->routes->dispatch($self, $route);
277              
278 238 100       4772 if ($route->bridge) {
    100          
279              
280             # Is it a bridge? Bridges must return a true value to allow the
281             # rest of the routes to run. They may also have rendered
282             # something, in which case trust that and don't render 403 (but
283             # still end the execution chain)
284              
285 33 100       97 if (!$data) {
286 4 100       13 $res->render_403 unless $res->rendered;
287             }
288             }
289             elsif (defined $data) {
290              
291             # If the non-bridge route returned something, then analyze it and render it
292              
293             # Handle delayed response if CODE
294 189 100       649 return $data if ref $data eq 'CODE';
295 188 100       632 $res->render($data) unless $res->rendered;
296             }
297              
298             # Do not go any further if we got a render
299 233 100       643 last if $res->rendered;
300             }
301              
302             # If nothing got rendered
303 210 100       559 if (!$res->rendered) {
304 9         29 $self->context->run_method(after_unrendered => ($match));
305             }
306              
307 207         795 return $self->finalize;
308             }
309              
310             sub NEXT_APP
311             {
312             return sub {
313 261     261   536 (shift @{$_[0]->{'kelp.execution_chain'}})->($_[0]);
  261         975  
314 260     260 1 1785 };
315             }
316              
317             sub psgi
318             {
319 251     251 0 737 my ($self, $env) = @_;
320              
321             # Initialize the app object state
322 251         1198 $self->context->clear;
323 251         1083 my $req = $self->req($self->build_request($env));
324 251         3896 my $res = $self->res($self->build_response);
325              
326             # Get route matches
327 251         1499 my $match = $self->routes->match($req->path, $req->method);
328              
329             # None found? Short-circuit and show 404
330 251 100       938 if (!@$match) {
331 8         43 $res->render_404;
332 8         32 return $self->finalize;
333             }
334              
335             return try {
336             $env->{'kelp.execution_chain'} = [
337 271         2394 (grep { defined } map { $_->psgi_middleware } @$match),
  271         954  
338 243         838 sub { $self->_psgi_internal($match) },
339 243     243   11194 ];
340              
341 243         983 return Kelp->NEXT_APP->($env);
342             }
343             catch {
344 35     35   3390 my $exception = $_;
345              
346             # CONTEXT CHANGE: we need to clear response state because anything that
347             # was rendered beforehand is no longer valid. Body and code will be
348             # replaced automatically with render methods, but headers must be
349             # cleared explicitly
350 35         114 $res->headers->clear;
351              
352 35 100 100     803 if (blessed $exception && $exception->isa('Kelp::Exception')) {
353              
354             # only log it as an error if the body is present
355 10 50 33     29 $self->logger('error', $exception->body)
356             if $self->can('logger') && defined $exception->body;
357              
358 10         33 $res->render_exception($exception);
359             }
360             else {
361 25 50       94 my $message = $self->long_error ? longmess($exception) : $exception;
362              
363             # Log error
364 25 50       114 $self->logger('critical', $message) if $self->can('logger');
365              
366             # Render an application erorr (hides details on production)
367 25         100 $res->render_500($exception);
368             }
369              
370 35         134 return $self->finalize;
371 243         2979 };
372             }
373              
374             sub finalize
375             {
376 250     250 0 422 my $self = shift;
377              
378             # call it with current context, so that it will get controller's hook if
379             # possible
380 250         738 $self->context->run_method(before_finalize => ());
381              
382 250         13622 return $self->res->finalize;
383             }
384              
385             #----------------------------------------------------------------
386             # Request and Response shortcuts
387             #----------------------------------------------------------------
388             sub param
389             {
390 71     71 1 840 my $self = shift;
391 71         208 unshift @_, $self->req;
392              
393             # goto will allow carp show the correct caller
394 71         389 goto $_[0]->can('param');
395             }
396              
397 0     0 1 0 sub session { shift->req->session(@_) }
398              
399             sub stash
400             {
401 2     2 1 5 my $self = shift;
402 2 100       10 @_ ? $self->req->stash->{$_[0]} : $self->req->stash;
403             }
404              
405             sub named
406             {
407 21     21 1 108 my $self = shift;
408 21 50       56 @_ ? $self->req->named->{$_[0]} : $self->req->named;
409             }
410              
411             #----------------------------------------------------------------
412             # Utility
413             #----------------------------------------------------------------
414              
415             sub is_production
416             {
417 36     36 1 55 my $self = shift;
418 36     58   224 return any { lc $self->mode eq $_ } qw(deployment production);
  58         158  
419             }
420              
421             sub url_for
422             {
423 7     7 1 23 my ($self, $name, @args) = @_;
424 7         14 my $result = $name;
425 7     7   61 try { $result = $self->routes->url($name, @args) };
  7         2105  
426 7         122 return $result;
427             }
428              
429             sub abs_url
430             {
431 0     0 1 0 my ($self, $name, @args) = @_;
432 0         0 my $url = $self->url_for($name, @args);
433 0         0 return URI->new_abs($url, $self->config('app_url'))->as_string;
434             }
435              
436             sub get_encoder
437             {
438 69     69 1 5860 my ($self, $type, $name) = @_;
439              
440 69   33     274 my $encoder = $self->encoder_modules->{$type} //
441             croak "No $type encoder";
442              
443 69         380 return $encoder->get_encoder($name);
444             }
445              
446             1;
447              
448             __END__
449              
450             =pod
451              
452             =head1 NAME
453              
454             Kelp - A web framework light, yet rich in nutrients.
455              
456             =head1 SYNOPSIS
457              
458             package MyApp;
459             use parent 'Kelp';
460              
461             # bootstrap your application
462             sub build {
463             my ($self) = @_;
464              
465             my $r = $self->routes;
466              
467             $r->add('/simple/route', 'route_handler');
468             $r->add('/route/:name', {
469             to => 'namespace::controller::action',
470             ... # other options, see Kelp::Routes
471             });
472             }
473              
474             # example route handler
475             sub route_handler {
476             my ($kelp_instance, @route_parameters) = @_;
477              
478             return 'text to be rendered';
479             }
480              
481             1;
482              
483             =head1 DESCRIPTION
484              
485             Kelp is a light, modular web framework built on top of Plack.
486              
487             This document lists all the methods and attributes available in the main
488             instance of a Kelp application, passed as a first argument to route handling
489             routines. If you're just getting started, you may be more interested in the
490             following documentation pages:
491              
492             See L<Kelp::Manual> for a complete reference.
493              
494             See L<Kelp::Manual::Cookbook> for solutions to common problems.
495              
496             =head1 REASONS TO USE KELP
497              
498             =over
499              
500             =item
501              
502             B<Plack ecosystem>. Kelp isn't just compatible with L<Plack>, it's built on top
503             of it. Your application can be supported by a collection of already available Plack
504             components.
505              
506             =item
507              
508             B<Advanced Routing>. Create intricate, yet simple ways to capture HTTP requests
509             and route them to their designated code. Use explicit and optional named
510             placeholders, wildcards, or just regular expressions.
511              
512             =item
513              
514             B<Flexible Configuration>. Use different configuration file for each
515             environment, e.g. development, deployment, etc. Merge a temporary configuration
516             into your current one for testing and debugging purposes.
517              
518             =item
519              
520             B<Enhanced Logging>. Log messages at different levels of emergency. Log to a
521             file, screen, or anything supported by L<Log::Dispatch>.
522              
523             =item
524              
525             B<Powerful Rendering>. Use the built-in auto-rendering logic, or the template
526             module of your choice to return rich text, html and JSON responses.
527              
528             =item
529              
530             B<JSON encoder/decoder>. Kelp can handle JSON-formatted requests and responses
531             automatically, making working with JSON much more enjoyable. On top of that, it
532             uses L<JSON::MaybeXS> to choose the best (fastest, most secure) backend
533             available.
534              
535             =item
536              
537             B<Extendable Core>. Kelp has straightforward code and uses pluggable modules
538             for everything. This allows anyone to extend it or add a module for a custom
539             interface. Writing Kelp modules is easy.
540              
541             =item
542              
543             B<Sleek Testing>. Kelp takes Plack::Test and wraps it in an object oriented
544             class of convenience methods. Testing is done via sending requests to your
545             routes, then analyzing the response.
546              
547             =back
548              
549             =head1 ATTRIBUTES
550              
551             =head2 host
552              
553             Gets the current hostname.
554              
555             sub some_route {
556             my $self = shift;
557             if ( $self->host eq 'prod-host' ) {
558             ...
559             }
560             }
561              
562             =head2 mode
563              
564             Sets or gets the current mode. The mode is important for the app to know what
565             configuration file to merge into the main configuration. See
566             L<Kelp::Module::Config> for more information.
567              
568             my $app = MyApp->new( mode => 'development' );
569             # conf/config.pl and conf/development.pl are merged with priority
570             # given to the second one.
571              
572             =head2 context_obj
573              
574             Provide a custom package name to define the ::Context object. Defaults to
575             L<Kelp::Context>.
576              
577             =head2 middleware_obj
578              
579             Provide a custom package name to define the middleware object. Defaults to
580             L<Kelp::Middleware>.
581              
582             =head2 request_obj
583              
584             Provide a custom package name to define the ::Request object. Defaults to
585             L<Kelp::Request>.
586              
587             =head2 response_obj
588              
589             Provide a custom package name to define the ::Response object. Defaults to
590             L<Kelp::Response>.
591              
592             =head2 config_module
593              
594             Sets of gets the class of the configuration module to be loaded on startup. The
595             default value is C<Config>, which will cause the C<Kelp::Module::Config> to get
596             loaded. See the documentation for L<Kelp::Module::Config> for more information
597             and for an example of how to create and use other config modules.
598              
599             =head2 loaded_modules
600              
601             A hashref containing the names and instances of all loaded modules. For example,
602             if you have these two modules loaded: Template and JSON, then a dump of
603             the C<loaded_modules> hash will look like this:
604              
605             {
606             Template => Kelp::Module::Template=HASH(0x208f6e8),
607             JSON => Kelp::Module::JSON=HASH(0x209d454)
608             }
609              
610             This can come in handy if your module does more than just registering a new method
611             into the application. Then, you can use its object instance to access that
612             additional functionality.
613              
614              
615             =head2 path
616              
617             Gets the current path of the application. That would be the path to C<app.psgi>
618              
619             =head2 name
620              
621             Gets or sets the name of the application. If not set, the name of the main
622             class will be used.
623              
624             my $app = MyApp->new( name => 'Twittar' );
625              
626             =head2 charset
627              
628             Gets or sets the output encoding charset of the app. It will be C<UTF-8>, if
629             not set to anything else. The charset can also changed in the config files.
630              
631             If the charset is explicitly configured to be C<undef> or false, the
632             application won't do any automatic encoding of responses, unless you set it by
633             explicitly calling L<Kelp::Response/charset>.
634              
635             =head2 request_charset
636              
637             Same as L</charset>, but only applies to the input. Request data will be
638             decoded using this charset or charset which came with the request.
639              
640             If the request charset is explicitly configured to be C<undef> or false, the
641             application won't do any automatic decoding of requests, B<even if message came
642             with a charset>.
643              
644             For details, see L<Kelp::Request/ENCODING>.
645              
646             =head2 long_error
647              
648             When a route dies, Kelp will by default display a short error message. Set this
649             attribute to a true value if you need to see a full stack trace of the error.
650             The C<KELP_LONG_ERROR> environment variable can also set this attribute.
651              
652             =head2 req
653              
654             This attribute only makes sense if called within a route definition. It will
655             contain a reference to the current L<Kelp::Request> instance.
656              
657             sub some_route {
658             my $self = shift;
659             if ( $self->req->is_json ) {
660             ...
661             }
662             }
663              
664             This attribute is a proxy to the same attribute in L</context>.
665              
666             =head2 res
667              
668             This attribute only makes sense if called within a route definition. It will
669             contain a reference to the current L<Kelp::Response> instance.
670              
671             sub some_route {
672             my $self = shift;
673             $self->res->json->render( { success => 1 } );
674             }
675              
676             This attribute is a proxy to the same attribute in L</context>.
677              
678             =head2 context
679              
680             This holds application's context. Its usage is advanced and only useful for
681             controller logic, but may allow for some introspection into Kelp.
682              
683             For example, if you have a route in a controller and need to get the original
684             Kelp app object, you may call this:
685              
686             sub some_route {
687             my $controller = shift;
688             my $app = $controller->context->app;
689             }
690              
691             =head2 encoder_modules
692              
693             A hash reference of registered encoder modules. Should only be interacted with
694             through L</get_encoder> or inside encoder module's code.
695              
696             =head1 METHODS
697              
698             =head2 new
699              
700             my $the_only_kelp = KelpApp->new;
701              
702             A standard constructor. B<Cannot> be called multiple times: see L</new_anon>.
703              
704             =head2 new_anon
705              
706             my $kelp1 = KelpApp->new_anon(config => 'conf1');
707             my $kelp2 = KelpApp->new_anon(config => 'conf2');
708              
709             B<Deprecated>. This only solves the problem in a basic scenario and has a
710             critical bug when it comes to subclassing and reblessing the app. The
711             C<new_anon> constructor itself will not be removed, but its internals will be
712             modified to use a more robust implementation method. It is not guaranteed to
713             work exactly the same for your use case with the new method. It's usually
714             better to treat every Kelp app like a singleton since that's how it was
715             designed.
716              
717             A constructor that can be called repeatedly. Cannot be mixed with L</new>.
718              
719             It works by creating a new anonymous class extending the class of your
720             application and running I<new> on it. C<ref $kelp> will return I<something
721             else> than the name of your Kelp class, but C<< $kelp->isa('KelpApp') >> will
722             be true. This will likely be useful during testing or when running multiple
723             instances of the same application with different configurations.
724              
725             =head2 build
726              
727             On its own, the C<build> method doesn't do anything. It is called by the
728             constructor, so it can be overridden to add route destinations and
729             initializations.
730              
731             package MyApp;
732              
733             sub build {
734             my $self = shift;
735             my $r = $self->routes;
736              
737             # Load some modules
738             $self->load_module("MongoDB");
739             $self->load_module("Validate");
740              
741             # Add all route destinations
742             $r->add("/one", "one");
743             ...
744              
745             }
746              
747             =head2 load_module
748              
749             C<load_module($name, %options)>
750              
751             Used to load a module. All modules should be under the C<Kelp::Module::>
752             namespace. If they are not, their class name must be prepended with C<+>.
753              
754             $self->load_module("Redis", server => '127.0.0.1');
755             # Will look for and load Kelp::Module::Redis
756              
757             Options for the module may be specified after its name, or in the
758             C<modules_init> hash in the config. Precedence is given to the
759             inline options.
760             See L<Kelp::Module> for more information on making and using modules.
761              
762             =head2 build_context
763              
764             This method is used to build the context. By default, it's used lazily by
765             L</context_obj> attribute. It can be overridden to modify how context is built.
766              
767             =head2 build_request
768              
769             This method is used to create the request object for each HTTP request. It
770             returns an instance of the class defined in the request_obj attribute (defaults to
771             L<Kelp::Request>), initialized with the current request's environment. You can
772             override this method to use a custom request module if you need to do something
773             interesting. Though there is a provided attribute that can be used to overide
774             the class of the object used.
775              
776             package MyApp;
777             use MyApp::Request;
778              
779             sub build_request {
780             my ( $self, $env ) = @_;
781             return MyApp::Request->new( app => $app, env => $env );
782             }
783              
784             # Now each request will be handled by MyApp::Request
785              
786             =head2 build_response
787              
788             This method creates the response object, e.g. what an HTTP request will return.
789             By default the object created is L<Kelp::Response> though this can be
790             overwritten via the respone_obj attribute. Much like L</build_request>, the
791             response can also be overridden to use a custom response object if you need
792             something completely custom.
793              
794             =head2 before_dispatch
795              
796             Override this method to modify the behavior before a route is handled. The
797             default behavior is to log access (if C<logger> is available).
798              
799             package MyApp;
800              
801             sub before_dispatch {
802             my ( $self, $destination ) = @_;
803              
804             # default access logging is disabled
805             }
806              
807             The C<$destination> param will depend on the routes implementation used. The
808             default router will pass the unchanged L<Kelp::Routes::Pattern/to>. If
809             possible, it will be run on the controller object (allowing overriding
810             C<before_dispatch> on controller classes).
811              
812             =head2 after_unrendered
813              
814             Override this method to control what's going to happen when a route has been
815             found but it did not render anything. The default behavior is to render page
816             404 (if only bridges are found) or throw an error.
817              
818             This hook will get passed an array reference to all matched routes, so you can
819             inspect them at will to decide what to do. It's strongly recommended to still
820             render 404 if the last match is a bridge (as is default).
821              
822             sub after_unrendered {
823             my ( $self, $matches ) = @_;
824              
825             if ($matches->[-1]->bridge) {
826             $self->res->render_404;
827             }
828             else {
829             # do something custom
830             }
831             }
832              
833             =head2 before_finalize
834              
835             Override this method to modify the response object just before it gets
836             finalized.
837              
838             package MyApp;
839              
840             sub before_finalize {
841             my $self = shift;
842             $self->res->set_header("X-App-Name", "MyApp");
843             }
844              
845             ...
846              
847             The above is an example of how to insert a custom header into the response of
848             every route.
849              
850              
851             =head2 run
852              
853             This method builds and returns the PSGI app. You can override it to get more
854             control over PSGI representation of the app.
855              
856             =head2 param
857              
858             A shortcut to C<$self-E<gt>req-E<gt>param>:
859              
860             sub some_route {
861             my $self = shift;
862             if ( $self->param('age') > 18 ) {
863             $self->can_watch_south_path(1);
864             }
865             }
866              
867             This function can be tricky to use because of context sensivity. See
868             L<Kelp::Request/param> for more information and examples.
869              
870             =head2 session
871              
872             A shortcut to C<$self-E<gt>req-E<gt>session>. Take a look at L<Kelp::Request/session>
873             for more information and examples.
874              
875             =head2 stash
876              
877             Provides safe access to C<$self-E<gt>req-E<gt>stash>. When called without
878             arguments, it will return the stash hash. If called with a single argument, it
879             will return the value of the corresponding key in the stash.
880             See L<Kelp::Request/stash> for more information and examples.
881              
882             =head2 named
883              
884             Provides safe access to C<$self-E<gt>req-E<gt>named>. When called without
885             arguments, it will return the named hash. If called with a single argument, it
886             will return the value of the corresponding key in the named hash.
887             See L<Kelp::Request/named> for more information and examples.
888              
889             =head2 url_for
890              
891             A safe shortcut to C<$self-E<gt>routes-E<gt>url>. Builds a URL from path and
892             arguments.
893              
894             sub build {
895             my $self = shift;
896             $self->routes->add("/:name/:id", { name => 'name', to => sub {
897             ...
898             }});
899             }
900              
901             sub check {
902             my $self = shift;
903             my $url_for_name = $self->url_for('name', name => 'jake', id => 1003);
904             $self->res->redirect_to( $url_for_name );
905             }
906              
907             =head2 abs_url
908              
909             Same as L</url_for>, but returns the full absolute URI for the current
910             application (based on configuration).
911              
912             =head2 is_production
913              
914             Returns whether the application is in production mode. Checks if L</mode> is
915             either C<deployment> or C<production>.
916              
917             =head2 get_encoder
918              
919             my $json_encoder = $self->get_encoder('json');
920              
921             Gets an instance of a given encoder. It takes two arguments:
922              
923             =over
924              
925             =item * type of the encoder module (eg. C<json>)
926              
927             =item * optional name of the encoder (default is C<default>)
928              
929             =back
930              
931             It will get extra config (if available) from C<encoders.TYPE.NAME>
932             configuration hash. Will instantiate the encoder just once and then reuse it.
933             Croaks when there is no such encoder type.
934              
935             Example new JSON encoder type defined in config:
936              
937             encoders => {
938             json => {
939             not_very_pretty => {
940             pretty => 0,
941             },
942             },
943             },
944              
945             =head2 NEXT_APP
946              
947             Helper method for giving Kelp back the control over PSGI application. It must
948             be used when declaring route-level middleware. It is context-independent and
949             can be called from C<Kelp> package.
950              
951             use Plack::Builder;
952              
953             builder {
954             enable 'SomeMiddleware';
955             Kelp->NEXT_APP;
956             }
957              
958             Internally, it uses C<kelp.execution_chain> PSGI environment to dynamically
959             construct a wrapped PSGI app without too much overhead.
960              
961             =head1 AUTHOR
962              
963             Stefan Geneshky - minimal <at> cpan.org
964              
965             =head1 LICENSE
966              
967             This module and all the modules in this package are governed by the same license
968             as Perl itself.
969              
970             =cut
971