File Coverage

blib/lib/Pickles/Context.pm
Criterion Covered Total %
statement 148 176 84.0
branch 20 34 58.8
condition 11 20 55.0
subroutine 35 43 81.4
pod 12 26 46.1
total 226 299 75.5


line stmt bran cond sub pod time code
1             package Pickles::Context;
2 10     10   238389 use strict;
  10         22  
  10         346  
3 10     10   57 use base qw(Class::Data::Inheritable);
  10         18  
  10         8611  
4 10     10   16130 use Plack::Util;
  10         105797  
  10         657  
5 10     10   7958 use Plack::Util::Accessor qw(env stash finished controller config dispatcher container);
  10         1927  
  10         89  
6 10     10   11399 use Class::Trigger qw(init pre_dispatch post_dispatch pre_render post_render pre_finalize post_finalize);
  10         13966  
  10         78  
7 10     10   8975 use String::CamelCase qw(camelize);
  10         5751  
  10         813  
8 10     10   58 use Carp ();
  10         17  
  10         166  
9 10     10   9902 use Try::Tiny;
  10         17523  
  10         612  
10 10     10   65 use Scalar::Util qw(blessed);
  10         28  
  10         738  
11              
12 10     10   3826 use Pickles::Util;
  10         30  
  10         563  
13 10     10   6205 use Pickles::Controller;
  10         29  
  10         3057  
14              
15             __PACKAGE__->mk_classdata(__components => {});
16             __PACKAGE__->mk_classdata(__plugins => {});
17              
18             __PACKAGE__->mk_classdata(request_class => '+Pickles::Request');
19             __PACKAGE__->mk_classdata(response_class => '+Pickles::Response');
20             __PACKAGE__->mk_classdata(view_class => 'View');
21              
22             # shortcut for container.
23             sub register {
24 0     0 1 0 my $self = shift;
25 0 0       0 Carp::croak( $self. '->register is deprecated. Use container profile file instead. See Pickles::Container for detail.' ) unless blessed( $self );
26 0         0 $self->container->register( @_ );
27             }
28              
29             sub get {
30 6     6 1 47 my $self = shift;
31 6         28 $self->container->get( @_ );
32             }
33              
34             sub load_plugins {
35 2     2 1 21103 my( $class, @plugins ) = @_;
36 2         8 for my $plugin( @plugins ) {
37 2         14 my $plugin_class = Plack::Util::load_class( $plugin, 'Pickles::Plugin' );
38 2         292424 $plugin_class->install( $class );
39 2         52 $class->__plugins->{$plugin} = $plugin_class;
40             }
41             }
42              
43             sub plugins {
44 0     0 0 0 my $class = shift;
45 0         0 values %{$class->__plugins};
  0         0  
46             }
47              
48             sub has_plugin {
49 0     0 0 0 my( $pkg, $name ) = @_;
50 0         0 $pkg->__plugins->{$name};
51             }
52              
53             sub add_method {
54 1     1 0 20 my( $pkg, $method, $code ) = @_;
55             {
56 10     10   55 no strict 'refs';
  10         24  
  10         18934  
  1         2  
57 1         2 *{"$pkg\::$method"} = $code;
  1         9  
58             }
59             }
60              
61             sub load {
62 14     14 0 28 my( $self, $component ) = @_;
63 14         95 my $loaded =
64             Plack::Util::load_class( $self->$component(), $self->appname );
65 14         249 $loaded;
66             }
67              
68             sub new {
69 8     8 0 12339 my $class = shift;
70 8         13 my %args;
71 8 100 66     55 if ( @_ == 1 && ref $_[0] eq 'HASH' ) {
72 3         10 $args{env} = $_[0];
73             }
74             else {
75 5         17 %args = @_;
76             }
77 8 50       28 Carp::croak(q{$env is required}) unless $args{env};
78 8         105 my $self = bless {
79             controller => undef,
80             stash => +{},
81             finished => 0,
82             %args,
83             }, $class;
84 8         69 $self->call_trigger('init');
85 8         511 $self;
86             }
87              
88             sub appname {
89 21     21 1 112408 my $self = shift;
90 21 50       82 my $class = ref $self ? ref $self : $self;
91 21         87 Pickles::Util::appname( $class );
92             }
93              
94             sub request {
95 36     36 1 47 my $self = shift;
96 36   66     258 $self->{_request} ||= do {
97 8         47 my $class = $self->load('request_class');
98 8         90 $class->new( $self->env );
99             };
100             }
101 36     36 1 1069 sub req { shift->request(@_); }
102              
103             sub response {
104 29     29 1 36 my $self = shift;
105 29   66     188 $self->{_response} ||= do {
106 4         14 my $class = $self->load('response_class');
107 4         39 $class->new( 200 );
108             };
109             }
110 29     29 1 994 sub res { shift->response(@_); }
111              
112             sub match {
113 16     16 0 19 my $self = shift;
114 16         49 my $dispatcher = $self->dispatcher;
115 16   66     109 $self->{_match} ||= $dispatcher->match( $self->req );
116             }
117              
118             sub render {
119 2     2 1 5 my( $self, $view_class ) = @_;
120 2 50       8 if ( $view_class ) {
121 0         0 $view_class = Plack::Util::load_class( $view_class, $self->appname );
122             }
123             else {
124 2         7 $view_class = $self->load('view_class');
125             }
126 2         5 my $view;
127 2     2   22 try { $view = $self->__components->{"$view_class"} };
  2         68  
128 2 50       55 if (! $view) {
129 2         16 $self->__components->{"$view_class"} = ($view = $view_class->new);
130             }
131 2         31 $self->res->content_type( $view->content_type );
132 2         77 my $body = $view->render( $self );
133 2         11 $self->res->body( $body );
134 2         23 $self->finished(1);
135             }
136              
137             sub dispatch {
138 4     4 0 30 my $self = shift;
139              
140 4         28 my $guard = $self->container->new_scope;
141              
142 4         26 $self->_prepare;
143 4         43 my $controller_class = $self->controller_class;
144 4         23 my $action = $self->action;
145 4 50 33     30 unless ( $controller_class && $self->validate_action( $action ) ) {
146 0         0 $self->handle_not_found;
147 0         0 return $self->finalize;
148             }
149 4         8 my $controller;
150 4     4   35 try { $controller = $self->__components->{"$controller_class"} };
  4         100  
151 4 100       86 if (! $controller) {
152 3         40 $self->__components->{"$controller_class"} = ($controller = $controller_class->new);
153             }
154 4         43 $controller->init( $self );
155 4         31 $self->controller( $controller );
156              
157             try {
158 4     4   129 $self->call_trigger('pre_dispatch');
159 4         288 $controller->execute( $action, $self );
160 4         12 $self->call_trigger('post_dispatch');
161             }
162             catch {
163 0 0   0   0 unless (/^PICKLES_EXCEPTION_ABORT/) {
164 0         0 local $SIG{__DIE__} = 'DEFAULT';
165 0         0 die $_;
166             }
167 4         55 };
168 4 100       351 unless ( $self->finished ) {
169 2         26 $self->call_trigger('pre_render');
170 2         155 $self->render;
171 2         25 $self->call_trigger('post_render');
172             }
173 4         321 return $self->finalize;
174             }
175              
176 0     0 1 0 sub abort { die 'PICKLES_EXCEPTION_ABORT'; }
177              
178             sub _prepare {
179 4     4   9 my $self = shift;
180 4         14 my $path = $self->req->path_info;
181 4 100       40 $path .= 'index' if $path =~ m{/$};
182 4         20 $path =~ s{^/}{};
183 4         26 $self->stash->{'VIEW_TEMPLATE'} = $path;
184             }
185              
186             sub finalize {
187 4     4 0 9 my $self = shift;
188 4         16 $self->call_trigger('pre_finalize');
189 4         258 my $result = $self->res->finalize;
190 4         378 $self->call_trigger('post_finalize');
191 4         237 $result;
192             }
193              
194             sub uri_for {
195 5     5 1 495 my( $self, @args ) = @_;
196             # Plack::App::URLMap
197 5         16 my $req = $self->req;
198 5         25 my $uri = $req->base;
199 5 100 66     931 my $params =
200             ( scalar @args && ref $args[$#args] eq 'HASH' ? pop @args : {} );
201 5         19 my @path = split '/', $uri->path;
202 5 100       66 unless ( $args[0] =~ m{^/} ) {
203 2         5 push @path, split( '/', $self->req->path_info );
204             }
205 5         20 push @path, @args;
206 5         12 my $path = join '/', @path;
207 5         8 $path =~ s|/{2,}|/|g; # xx////xx -> xx/xx
208 5         19 $uri->path( $path );
209 5         208 $uri->query_form( $params );
210 5         407 $uri;
211             }
212              
213             sub handle_not_found {
214 0     0 0 0 my $self = shift;
215 0         0 $self->res->status( 404 );
216 0         0 $self->not_found;
217 0         0 $self->finished(1);
218             }
219              
220             sub not_found {
221 0     0 0 0 my $self = shift;
222 0         0 $self->res->content_type('text/html');
223 0         0 $self->res->body(<<'HTML');
224            
225            
226             404
227            
228            
229            

404 File Not Found

230            
231            
232             HTML
233             }
234              
235             sub redirect {
236 0     0 1 0 my( $self, $url, $code ) = @_;
237 0   0     0 $code ||= 302;
238 0         0 $self->res->status( $code );
239 0 0       0 $url = ($url =~ m{^https?://}) ? $url : $self->uri_for( $url );
240 0         0 $self->res->headers->header(Location => $url);
241 0         0 $self->finished(1);
242             }
243              
244             sub controller_class {
245 4     4 0 6 my $self = shift;
246 4         14 my $match = $self->match;
247 4         13 my $controller = $match->{controller};
248 4 50       13 return unless $controller;
249 4         18 my $class = Plack::Util::load_class(
250             'Controller::'. camelize( $controller ),
251             $self->appname
252             );
253 4         77 $class;
254             }
255              
256             my %_reserved_actions =
257             map { $_ => 1 }
258             grep { defined &{"Pickles::Controller::$_"} }
259             keys %{Pickles::Controller::};
260              
261             sub validate_action {
262 4     4 0 9 my( $self, $action ) = @_;
263 4 50       19 return unless defined $action;
264 4 50       14 return if $_reserved_actions{$action};
265 4         30 return $action =~ m{^[a-z][a-zA-Z0-9_]*$};
266             }
267              
268             sub action {
269 4     4 0 8 my $self = shift;
270 4         12 my $match = $self->match;
271 4         12 $match->{action};
272             }
273              
274             sub args {
275 8     8 0 21 my $self = shift;
276 8         24 my $match = $self->match;
277 8         38 $match->{args};
278             }
279              
280             1;
281              
282             __END__