Coverage Summary

# File Coverage

blib/lib/Prancer.pm
Criterion | Covered | Total | %
--- | --- | --- | ---
statement | 51 | 152 | 33.6
branch | 0 | 32 | 0.0
condition | 0 | 18 | 0.0
subroutine | 17 | 33 | 51.5
pod | 6 | 7 | 85.7
total | 74 | 242 | 30.6

line | stmt | bran | cond | sub | pod | time | code
--- | --- | --- | --- | --- | --- | --- | ---
1 |  |  |  |  |  |  | package Prancer;
2 |  |  |  |  |  |  |
3 | 2 |  |  | 2 |  | 30521 | use strict;
| 2 |  |  |  |  | 4 |
| 2 |  |  |  |  | 64 |
4 | 2 |  |  | 2 |  | 4 | use warnings FATAL => 'all';
| 2 |  |  |  |  | 1 |
| 2 |  |  |  |  | 52 |
5 |  |  |  |  |  |  |
6 | 2 |  |  | 2 |  | 383 | use version;
| 2 |  |  |  |  | 1480 |
| 2 |  |  |  |  | 6 |
7 |  |  |  |  |  |  | our $VERSION = "0.02";
8 |  |  |  |  |  |  |
9 | 2 |  |  | 2 |  | 97 | use Exporter;
| 2 |  |  |  |  | 2 |
| 2 |  |  |  |  | 81 |
10 | 2 |  |  | 2 |  | 335 | use parent qw(Exporter);
| 2 |  |  |  |  | 393 |
| 2 |  |  |  |  | 5 |
11 |  |  |  |  |  |  |
12 |  |  |  |  |  |  | our @EXPORT_OK = qw(config logger template database);
13 |  |  |  |  |  |  | our %EXPORT_TAGS = ('all' => [ @EXPORT_OK ]);
14 |  |  |  |  |  |  |
15 | 2 |  |  | 2 |  | 121 | use Carp;
| 2 |  |  |  |  | 2 |
| 2 |  |  |  |  | 103 |
16 | 2 |  |  | 2 |  | 382 | use Module::Load ();
| 2 |  |  |  |  | 1458 |
| 2 |  |  |  |  | 35 |
17 | 2 |  |  | 2 |  | 643 | use Storable qw(dclone);
| 2 |  |  |  |  | 4116 |
| 2 |  |  |  |  | 109 |
18 | 2 |  |  | 2 |  | 459 | use Try::Tiny;
| 2 |  |  |  |  | 3519 |
| 2 |  |  |  |  | 84 |
19 |  |  |  |  |  |  |
20 | 2 |  |  | 2 |  | 429 | use Prancer::Config;
| 2 |  |  |  |  | 3 |
| 2 |  |  |  |  | 66 |
21 | 2 |  |  | 2 |  | 449 | use Prancer::Logger;
| 2 |  |  |  |  | 2 |
| 2 |  |  |  |  | 40 |
22 | 2 |  |  | 2 |  | 415 | use Prancer::Request;
| 2 |  |  |  |  | 3 |
| 2 |  |  |  |  | 53 |
23 | 2 |  |  | 2 |  | 432 | use Prancer::Response;
| 2 |  |  |  |  | 3 |
| 2 |  |  |  |  | 49 |
24 | 2 |  |  | 2 |  | 413 | use Prancer::Session;
| 2 |  |  |  |  | 2 |
| 2 |  |  |  |  | 40 |
25 | 2 |  |  | 2 |  | 388 | use Prancer::Context;
| 2 |  |  |  |  | 2 |
| 2 |  |  |  |  | 93 |
26 |  |  |  |  |  |  |
27 |  |  |  |  |  |  | sub new {
28 | 0 |  |  | 0 | 1 |  | my ($class, $config_path, $handler, @args) = @_;
29 |  |  |  |  |  |  |
30 |  |  |  |  |  |  | # already got an object
31 | 0 | 0 |  |  |  |  | return $class if ref($class);
32 |  |  |  |  |  |  |
33 |  |  |  |  |  |  | # this is a singleton
34 | 0 |  |  |  |  |  | my $instance = undef;
35 |  |  |  |  |  |  | {
36 | 2 |  |  | 2 |  | 4 | no strict 'refs';
| 2 |  |  |  |  | 2 |
| 2 |  |  |  |  | 211 |
| 0 |  |  |  |  |  |
37 | 0 |  |  |  |  |  | $instance = \${"$class\::_instance"};
| 0 |  |  |  |  |  |
38 | 0 | 0 |  |  |  |  | return $$instance if defined($$instance);
39 |  |  |  |  |  |  | }
40 |  |  |  |  |  |  |
41 | 0 |  |  |  |  |  | my $self = bless({
42 |  |  |  |  |  |  | '_handler' => $handler, # the name of the class that will implement the handler
43 |  |  |  |  |  |  | '_handler_args' => \@args, # any arguments that should be passed to the handler on creation
44 |  |  |  |  |  |  | }, $class);
45 |  |  |  |  |  |  |
46 |  |  |  |  |  |  | # load configuration
47 | 0 |  |  |  |  |  | $self->{'_config'} = Prancer::Config->load($config_path);
48 |  |  |  |  |  |  |
49 |  |  |  |  |  |  | # load the configured logger
50 | 0 |  |  |  |  |  | $self->{'_logger'} = Prancer::Logger->load($self->{'_config'}->remove('logger'));
51 |  |  |  |  |  |  |
52 | 0 |  |  |  |  |  | $$instance = $self;
53 | 0 |  |  |  |  |  | return $self;
54 |  |  |  |  |  |  | }
55 |  |  |  |  |  |  |
56 |  |  |  |  |  |  | # return an already created instance of ourselves or croak if one doesn't exist
57 |  |  |  |  |  |  | sub instance {
58 | 0 |  |  | 0 | 0 |  | my $class = __PACKAGE__;
59 |  |  |  |  |  |  |
60 |  |  |  |  |  |  | {
61 | 2 |  |  | 2 |  | 4 | no strict 'refs';
| 2 |  |  |  |  | 2 |
| 2 |  |  |  |  | 2054 |
| 0 |  |  |  |  |  |
62 | 0 |  |  |  |  |  | my $instance = \${"$class\::_instance"};
| 0 |  |  |  |  |  |
63 | 0 | 0 |  |  |  |  | return $$instance if defined($$instance);
64 |  |  |  |  |  |  | }
65 |  |  |  |  |  |  |
66 | 0 |  |  |  |  |  | croak "must create an instance of " . __PACKAGE__ . " before it may be used";
67 |  |  |  |  |  |  | }
68 |  |  |  |  |  |  |
69 |  |  |  |  |  |  | sub logger {
70 | 0 |  |  | 0 | 1 |  | my $self = instance();
71 | 0 |  |  |  |  |  | return $self->{'_logger'};
72 |  |  |  |  |  |  | }
73 |  |  |  |  |  |  |
74 |  |  |  |  |  |  | sub config {
75 | 0 |  |  | 0 | 1 |  | my $self = instance();
76 | 0 |  |  |  |  |  | return $self->{'_config'};
77 |  |  |  |  |  |  | }
78 |  |  |  |  |  |  |
79 |  |  |  |  |  |  | sub template {
80 | 0 |  |  | 0 | 1 |  | my $self = instance();
81 |  |  |  |  |  |  |
82 |  |  |  |  |  |  | # if the template object hasn't been initialized do it now
83 |  |  |  |  |  |  | # this will make this work well with CLI apps
84 | 0 |  |  |  |  |  | require Prancer::Template;
85 | 0 | 0 |  |  |  |  | $self->{'_template'} = Prancer::Template->load(config->remove('template')) unless defined($self->{'_template'});
86 |  |  |  |  |  |  |
87 | 0 |  |  |  |  |  | return $self->{'_template'}->render(@_);
88 |  |  |  |  |  |  | }
89 |  |  |  |  |  |  |
90 |  |  |  |  |  |  | sub database {
91 | 0 |  |  | 0 | 1 |  | my $self = instance();
92 | 0 |  | 0 |  |  |  | my $connection = shift || "default";
93 |  |  |  |  |  |  |
94 |  |  |  |  |  |  | # if the database object hasn't been initialized do it now
95 |  |  |  |  |  |  | # this will make this work well with CLI apps
96 | 0 |  |  |  |  |  | require Prancer::Database;
97 | 0 | 0 |  |  |  |  | $self->{'_database'} = Prancer::Database->load(config->remove('database')) unless defined($self->{'_database'});
98 |  |  |  |  |  |  |
99 | 0 | 0 |  |  |  |  | if (!defined($connection)) {
100 | 0 |  |  |  |  |  | logger->fatal("could not get connection to database: no connection name given");
101 | 0 |  |  |  |  |  | croak;
102 |  |  |  |  |  |  | }
103 | 0 | 0 |  |  |  |  | if (!exists($self->{'_database'}->{$connection})) {
104 | 0 |  |  |  |  |  | logger->fatal("could not get connection to database: no connection named '${connection}'");
105 | 0 |  |  |  |  |  | croak;
106 |  |  |  |  |  |  | }
107 |  |  |  |  |  |  |
108 | 0 |  |  |  |  |  | return $self->{'_database'}->{$connection}->handle();
109 |  |  |  |  |  |  | }
110 |  |  |  |  |  |  |
111 |  |  |  |  |  |  | sub run {
112 | 0 |  |  | 0 | 1 |  | my $self = shift;
113 |  |  |  |  |  |  |
114 |  |  |  |  |  |  | try {
115 | 0 |  |  | 0 |  |  | Module::Load::load($self->{'_handler'});
116 |  |  |  |  |  |  | } catch {
117 | 0 | 0 |  | 0 |  |  | logger->fatal("could not initialize handler: " . (defined($_) ? $_ : "unknown"));
118 | 0 |  |  |  |  |  | croak;
119 | 0 |  |  |  |  |  | };
120 |  |  |  |  |  |  |
121 |  |  |  |  |  |  | # pre-load the template engine
122 | 0 |  |  |  |  |  | require Prancer::Template;
123 | 0 |  |  |  |  |  | $self->{'_template'} = Prancer::Template->load(config->remove('template'));
124 |  |  |  |  |  |  |
125 |  |  |  |  |  |  | # pre-load the database engine
126 | 0 |  |  |  |  |  | require Prancer::Database;
127 | 0 |  |  |  |  |  | $self->{'_database'} = Prancer::Database->load(config->remove('database'));
128 |  |  |  |  |  |  |
129 |  |  |  |  |  |  | my $app = sub {
130 | 0 |  |  | 0 |  |  | my $env = shift;
131 |  |  |  |  |  |  |
132 |  |  |  |  |  |  | # create a context to pass to the request
133 | 0 |  |  |  |  |  | my $context = Prancer::Context->new(
134 |  |  |  |  |  |  | 'env' => $env,
135 |  |  |  |  |  |  | 'request' => Prancer::Request->new($env),
136 |  |  |  |  |  |  | 'response' => Prancer::Response->new($env),
137 |  |  |  |  |  |  | 'session' => Prancer::Session->new($env),
138 |  |  |  |  |  |  | );
139 |  |  |  |  |  |  |
140 | 0 |  |  |  |  |  | my $handler = $self->{'_handler'};
141 | 0 |  |  |  |  |  | my $copy = $handler->new($context, @{$self->{'_handler_args'}});
| 0 |  |  |  |  |  |
142 | 0 |  |  |  |  |  | return $copy->handle($env);
143 | 0 |  |  |  |  |  | };
144 |  |  |  |  |  |  |
145 |  |  |  |  |  |  | # capture warnings and logging messages and send them to the configured logger
146 | 0 |  |  |  |  |  | require Prancer::Middleware::Logger;
147 | 0 |  |  |  |  |  | $app = Prancer::Middleware::Logger->wrap($app);
148 |  |  |  |  |  |  |
149 |  |  |  |  |  |  | # enable user sessions
150 | 0 |  |  |  |  |  | $app = $self->_enable_sessions($app);
151 |  |  |  |  |  |  |
152 |  |  |  |  |  |  | # serve up static files if configured to do so
153 | 0 |  |  |  |  |  | $app = $self->_enable_static($app);
154 |  |  |  |  |  |  |
155 | 0 |  |  |  |  |  | return $app;
156 |  |  |  |  |  |  | }
157 |  |  |  |  |  |  |
158 |  |  |  |  |  |  | sub _enable_sessions {
159 | 0 |  |  | 0 |  |  | my ($self, $app) = @_;
160 |  |  |  |  |  |  |
161 | 0 |  |  |  |  |  | my $config = config->remove('session');
162 | 0 | 0 |  |  |  |  | if ($config) {
163 |  |  |  |  |  |  | try {
164 |  |  |  |  |  |  | # load the session state module first
165 |  |  |  |  |  |  | # this will probably be a cookie
166 | 0 |  |  | 0 |  |  | my $state_module = undef;
167 | 0 |  |  |  |  |  | my $state_options = undef;
168 | 0 | 0 | 0 |  |  |  | if (ref($config->{'state'}) && ref($config->{'state'}) eq "HASH") {
169 | 0 |  |  |  |  |  | $state_module = $config->{'state'}->{'driver'};
170 | 0 |  |  |  |  |  | $state_options = $config->{'state'}->{'options'};
171 |  |  |  |  |  |  | }
172 |  |  |  |  |  |  |
173 |  |  |  |  |  |  | # set defaults and then load the state module
174 | 0 |  | 0 |  |  |  | $state_options ||= {};
175 | 0 |  | 0 |  |  |  | $state_module ||= "Prancer::Session::State::Cookie";
176 | 0 |  |  |  |  |  | Module::Load::load($state_module);
177 |  |  |  |  |  |  |
178 |  |  |  |  |  |  | # set the default for the session name because the plack
179 |  |  |  |  |  |  | # default is stupid
180 | 0 |  | 0 |  |  |  | $state_options->{'session_key'} ||= "PSESSION";
181 |  |  |  |  |  |  |
182 |  |  |  |  |  |  | # load the store module second
183 | 0 |  |  |  |  |  | my $store_module = undef;
184 | 0 |  |  |  |  |  | my $store_options = undef;
185 | 0 | 0 | 0 |  |  |  | if (ref($config->{'store'}) && ref($config->{'store'}) eq "HASH") {
186 | 0 |  |  |  |  |  | $store_module = $config->{'store'}->{'driver'};
187 | 0 |  |  |  |  |  | $store_options = $config->{'store'}->{'options'};
188 |  |  |  |  |  |  | }
189 |  |  |  |  |  |  |
190 |  |  |  |  |  |  | # set defaults and then load the store module
191 | 0 |  | 0 |  |  |  | $store_options ||= {};
192 | 0 |  | 0 |  |  |  | $store_module ||= "Prancer::Session::Store::Memory";
193 | 0 |  |  |  |  |  | Module::Load::load($store_module);
194 |  |  |  |  |  |  |
195 | 0 |  |  |  |  |  | require Plack::Middleware::Session;
196 | 0 |  |  |  |  |  | $app = Plack::Middleware::Session->wrap($app,
197 |  |  |  |  |  |  | 'state' => $state_module->new($state_options),
198 |  |  |  |  |  |  | 'store' => $store_module->new($store_options),
199 |  |  |  |  |  |  | );
200 | 0 |  |  |  |  |  | logger->info("initialized session handler with state module ${state_module} and store module ${store_module}");
201 |  |  |  |  |  |  | } catch {
202 | 0 | 0 |  | 0 |  |  | my $error = (defined($_) ? $_ : "unknonw");
203 | 0 |  |  |  |  |  | logger->warn("could not initialize session handler: initialization error: ${error}");
204 | 0 |  |  |  |  |  | };
205 |  |  |  |  |  |  | } else {
206 | 0 |  |  |  |  |  | logger->warn("could not initialize session handler: no session handler configured");
207 |  |  |  |  |  |  | }
208 |  |  |  |  |  |  |
209 | 0 |  |  |  |  |  | return $app;
210 |  |  |  |  |  |  | }
211 |  |  |  |  |  |  |
212 |  |  |  |  |  |  | sub _enable_static {
213 | 0 |  |  | 0 |  |  | my ($self, $app) = @_;
214 |  |  |  |  |  |  |
215 | 0 |  |  |  |  |  | my $config = config->remove('static');
216 | 0 | 0 |  |  |  |  | if ($config) {
217 |  |  |  |  |  |  | try {
218 |  |  |  |  |  |  | # this intercepts requests for /static/* and checks to see if
219 |  |  |  |  |  |  | # the requested file exists in the configured path. if it does
220 |  |  |  |  |  |  | # it is served up. if it doesn't then the request will pass
221 |  |  |  |  |  |  | # through to the handler.
222 | 0 | 0 |  | 0 |  |  | die "no path is configured\n" unless defined($config->{'path'});
223 | 0 |  |  |  |  |  | my $path = Cwd::realpath($config->{'path'});
224 | 0 | 0 |  |  |  |  | die "${path} does not exist\n" unless (-e $path);
225 | 0 | 0 |  |  |  |  | die "${path} is not readable\n" unless (-r $path);
226 |  |  |  |  |  |  |
227 | 0 |  |  |  |  |  | require Plack::Middleware::Static;
228 |  |  |  |  |  |  | $app = Plack::Middleware::Static->wrap($app,
229 | 0 |  |  |  |  |  | 'path' => sub { s!^/static/!!x },
230 | 0 |  |  |  |  |  | 'root' => $path,
231 |  |  |  |  |  |  | 'pass_through' => 1,
232 |  |  |  |  |  |  | );
233 | 0 |  |  |  |  |  | logger->info("serving static files from ${path} at /static");
234 |  |  |  |  |  |  | } catch {
235 | 0 |  |  | 0 |  |  | logger->warn("could not initialize static file loader: initialization error: $_");
236 | 0 |  |  |  |  |  | };
237 |  |  |  |  |  |  | } else {
238 | 0 |  |  |  |  |  | logger->warn("could not initialize static file loader: not configured");
239 |  |  |  |  |  |  | }
240 |  |  |  |  |  |  |
241 | 0 |  |  |  |  |  | return $app;
242 |  |  |  |  |  |  | }
243 |  |  |  |  |  |  |
244 |  |  |  |  |  |  | 1;
245 |  |  |  |  |  |  |
246 |  |  |  |  |  |  | =head1 NAME
247 |  |  |  |  |  |  |
248 |  |  |  |  |  |  | Prancer - Another PSGI Framework
249 |  |  |  |  |  |  |
250 |  |  |  |  |  |  | =head1 SYNOPSIS
251 |  |  |  |  |  |  |
252 |  |  |  |  |  |  | Prancer is yet another PSGI framework. This one is designed to be a bit smaller
253 |  |  |  |  |  |  | and more out of the way than others but it could probably be described best as
254 |  |  |  |  |  |  | project derived from L<NIH syndrome|https://en.wikipedia.org/wiki/Not_Invented_Here>.
255 |  |  |  |  |  |  |
256 |  |  |  |  |  |  | Here's how it might be used:
257 |  |  |  |  |  |  |
258 |  |  |  |  |  |  | ==> myapp.psgi
259 |  |  |  |  |  |  |
260 |  |  |  |  |  |  | use Prancer;
261 |  |  |  |  |  |  | my $app = Prancer->new("/path/to/confdir", "MyApp");
262 |  |  |  |  |  |  | $app->run();
263 |  |  |  |  |  |  |
264 |  |  |  |  |  |  | ==> MyApp.pm
265 |  |  |  |  |  |  |
266 |  |  |  |  |  |  | package MyApp;
267 |  |  |  |  |  |  |
268 |  |  |  |  |  |  | use Prancer::Application qw(:all);
269 |  |  |  |  |  |  | use parent qw(Prancer::Application);
270 |  |  |  |  |  |  |
271 |  |  |  |  |  |  | sub handle {
272 |  |  |  |  |  |  | my $self = shift;
273 |  |  |  |  |  |  |
274 |  |  |  |  |  |  | mount('GET', '/', sub {
275 |  |  |  |  |  |  | context->header(set => 'Content-Type', value => 'text/plain');
276 |  |  |  |  |  |  | context->body("hello world");
277 |  |  |  |  |  |  | context->finalize(200);
278 |  |  |  |  |  |  | });
279 |  |  |  |  |  |  |
280 |  |  |  |  |  |  | return dispatch;
281 |  |  |  |  |  |  | }
282 |  |  |  |  |  |  |
283 |  |  |  |  |  |  | Full documentation can be found in L<Prancer::Manual>.
284 |  |  |  |  |  |  |
285 |  |  |  |  |  |  | =head1 INSTALLATION
286 |  |  |  |  |  |  |
287 |  |  |  |  |  |  | To install this module, run the following commands:
288 |  |  |  |  |  |  |
289 |  |  |  |  |  |  | perl Makefile.PL
290 |  |  |  |  |  |  | make
291 |  |  |  |  |  |  | make test
292 |  |  |  |  |  |  | make install
293 |  |  |  |  |  |  |
294 |  |  |  |  |  |  | If this ever makes it to CPAN you can install it with this simple command:
295 |  |  |  |  |  |  |
296 |  |  |  |  |  |  | perl -MCPAN -e 'install Prancer'
297 |  |  |  |  |  |  |
298 |  |  |  |  |  |  | These optional libraries will enhance the functionality of Prancer:
299 |  |  |  |  |  |  |
300 |  |  |  |  |  |  | =over 4
301 |  |  |  |  |  |  |
302 |  |  |  |  |  |  | =item L<Template>
303 |  |  |  |  |  |  |
304 |  |  |  |  |  |  | Without this the Prancer template interface will not work.
305 |  |  |  |  |  |  |
306 |  |  |  |  |  |  | =item L<DBI>
307 |  |  |  |  |  |  |
308 |  |  |  |  |  |  | Without this the Prancer database interface will not work. You also will need
309 |  |  |  |  |  |  | a database driver like L<DBD::Pg>.
310 |  |  |  |  |  |  |
311 |  |  |  |  |  |  | =item L<Plack::Middleware::Session>
312 |  |  |  |  |  |  |
313 |  |  |  |  |  |  | Without this the Prancer session support will not work. If you want to use the
314 |  |  |  |  |  |  | YAML session storage you will also need to have L<YAML> (preferably
315 |  |  |  |  |  |  | L<YAML::XS>) installed. If you want support to write sessions do the database
316 |  |  |  |  |  |  | you will also need L<DBI> installed along with a database driver like
317 |  |  |  |  |  |  | L<DBD::Pg>.
318 |  |  |  |  |  |  |
319 |  |  |  |  |  |  | =back
320 |  |  |  |  |  |  |
321 |  |  |  |  |  |  | =head1 EXPORTABLE
322 |  |  |  |  |  |  |
323 |  |  |  |  |  |  | The following methods are exportable: C<config>, C<logger>, C<database>,
324 |  |  |  |  |  |  | C<template>. They can all be exported at once using C<:all>.
325 |  |  |  |  |  |  |
326 |  |  |  |  |  |  | =head1 METHODS
327 |  |  |  |  |  |  |
328 |  |  |  |  |  |  | With the exception of C<-E<gt>new> and C<-E<gt>run>, all methods should be
329 |  |  |  |  |  |  | called in a static context. Additionally, with the same exception, all methods
330 |  |  |  |  |  |  | are exportable individually or with C<qw(:all)>.
331 |  |  |  |  |  |  |
332 |  |  |  |  |  |  | =over 4
333 |  |  |  |  |  |  |
334 |  |  |  |  |  |  | =item ->new CONFIG PACKAGE ARGS
335 |  |  |  |  |  |  |
336 |  |  |  |  |  |  | This will create your application. It takes two arguments:
337 |  |  |  |  |  |  |
338 |  |  |  |  |  |  | =over 4
339 |  |  |  |  |  |  |
340 |  |  |  |  |  |  | =item CONFIG
341 |  |  |  |  |  |  |
342 |  |  |  |  |  |  | This a path to a directory containing configuration files. How configuration
343 |  |  |  |  |  |  | files are loaded is detailed below.
344 |  |  |  |  |  |  |
345 |  |  |  |  |  |  | =item PACKAGE
346 |  |  |  |  |  |  |
347 |  |  |  |  |  |  | This is the name of a package that implements your application. The package
348 |  |  |  |  |  |  | named should extend L<Prancer::Application> though this is not enforced.
349 |  |  |  |  |  |  |
350 |  |  |  |  |  |  | =item ARGS
351 |  |  |  |  |  |  |
352 |  |  |  |  |  |  | After the name of the package, any number of arguments may be added. Any extra
353 |  |  |  |  |  |  | arguments are passed directly to the C<new> method on the named package when it
354 |  |  |  |  |  |  | is created for a request.
355 |  |  |  |  |  |  |
356 |  |  |  |  |  |  | =back
357 |  |  |  |  |  |  |
358 |  |  |  |  |  |  | =item ->run
359 |  |  |  |  |  |  |
360 |  |  |  |  |  |  | This starts your application. It takes no arguments.
361 |  |  |  |  |  |  |
362 |  |  |  |  |  |  | =item logger
363 |  |  |  |  |  |  |
364 |  |  |  |  |  |  | This gives access to the logger. For example:
365 |  |  |  |  |  |  |
366 |  |  |  |  |  |  | logger->info("Hello");
367 |  |  |  |  |  |  | logger->fatal("uh oh");
368 |  |  |  |  |  |  | logger->debug("here we are");
369 |  |  |  |  |  |  |
370 |  |  |  |  |  |  | =item config
371 |  |  |  |  |  |  |
372 |  |  |  |  |  |  | This gives access to the configuration. For example:
373 |  |  |  |  |  |  |
374 |  |  |  |  |  |  | config->has('foo');
375 |  |  |  |  |  |  | config->get('foo');
376 |  |  |  |  |  |  | config->set('foo', value => 'bar');
377 |  |  |  |  |  |  | config->remove('foo');
378 |  |  |  |  |  |  |
379 |  |  |  |  |  |  | Any changes to the configuration do not persist back to the actual
380 |  |  |  |  |  |  | configuration file. Additionally they do not persist between threads or
381 |  |  |  |  |  |  | processes.
382 |  |  |  |  |  |  |
383 |  |  |  |  |  |  | Whenever this method is used to get a configuration option and that option
384 |  |  |  |  |  |  | is reference, the reference will be cloned by Storable to prevent changes to
385 |  |  |  |  |  |  | one copy from affecting other uses. But this could have performance
386 |  |  |  |  |  |  | implications if you are routinely getting large data structures out if your
387 |  |  |  |  |  |  | configuration files.
388 |  |  |  |  |  |  |
389 |  |  |  |  |  |  | =item template
390 |  |  |  |  |  |  |
391 |  |  |  |  |  |  | This gives access to the configured template engine. For example:
392 |  |  |  |  |  |  |
393 |  |  |  |  |  |  | print template("foo.tt", {
394 |  |  |  |  |  |  | 'title' => 'foobar',
395 |  |  |  |  |  |  | 'var1' => 'val2',
396 |  |  |  |  |  |  | });
397 |  |  |  |  |  |  |
398 |  |  |  |  |  |  | If no template engines are configured then this method will always return
399 |  |  |  |  |  |  | C<undef>.
400 |  |  |  |  |  |  |
401 |  |  |  |  |  |  | =item database
402 |  |  |  |  |  |  |
403 |  |  |  |  |  |  | This gives access to the configured databases. For example:
404 |  |  |  |  |  |  |
405 |  |  |  |  |  |  | # handle to the database configured as 'default'
406 |  |  |  |  |  |  | my $dbh = database;
407 |  |  |  |  |  |  |
408 |  |  |  |  |  |  | # handle to the database configured as 'foo'
409 |  |  |  |  |  |  | my $dbh = database('foo');
410 |  |  |  |  |  |  |
411 |  |  |  |  |  |  | # prepare a statement on connection 'default'
412 |  |  |  |  |  |  | my $sth = database->prepare("SELECT * FROM foo");
413 |  |  |  |  |  |  |
414 |  |  |  |  |  |  | In all cases, C<$dbh> will be a reference to a L<DBI> handle and anything that
415 |  |  |  |  |  |  | can be done with L<DBI> can be done here.
416 |  |  |  |  |  |  |
417 |  |  |  |  |  |  | If no databases are configured then this method will always return C<undef>.
418 |  |  |  |  |  |  |
419 |  |  |  |  |  |  | =item session
420 |  |  |  |  |  |  |
421 |  |  |  |  |  |  | Configures the session handler. For example:
422 |  |  |  |  |  |  |
423 |  |  |  |  |  |  | session:
424 |  |  |  |  |  |  | state:
425 |  |  |  |  |  |  | driver: Prancer::Session::State::Cookie
426 |  |  |  |  |  |  | options:
427 |  |  |  |  |  |  | key: PSESSION
428 |  |  |  |  |  |  | store:
429 |  |  |  |  |  |  | driver: Prancer::Session::Store::YAML
430 |  |  |  |  |  |  | options:
431 |  |  |  |  |  |  | path: /tmp/prancer/sessions
432 |  |  |  |  |  |  |
433 |  |  |  |  |  |  | See L<Prancer::Session::State::Cookie>, L<Prancer::Session::Store::Memory>,
434 |  |  |  |  |  |  | L<Prancer::Session::Store::YAML> and L<Prancer::Session::Store::Database> for
435 |  |  |  |  |  |  | more options.
436 |  |  |  |  |  |  |
437 |  |  |  |  |  |  | =back
438 |  |  |  |  |  |  |
439 |  |  |  |  |  |  | =head1 CONFIGURATION
440 |  |  |  |  |  |  |
441 |  |  |  |  |  |  | One doesn't need to create any configuration to use Prancer but then Prancer
442 |  |  |  |  |  |  | wouldn't be very useful. Prancer uses L<Config::Any> to process configuration
443 |  |  |  |  |  |  | files so anything supported by that will be supported by this. It will load
444 |  |  |  |  |  |  | configuration files from given path set when your application initialized.
445 |  |  |  |  |  |  | First it will look for a file named C<config.ext> where C<ext> is something
446 |  |  |  |  |  |  | like C<yml> or C<ini>. Then it will look for a file named after the current
447 |  |  |  |  |  |  | environment like C<develoment.ext> or C<production.ext>. The environment is
448 |  |  |  |  |  |  | derived by looking first for an environment variable called C<ENVIRONMENT>,
449 |  |  |  |  |  |  | then for an environment variable called C<PLACK_ENV>. If neither of those exist
450 |  |  |  |  |  |  | then the default is C<development>. Configuration files will be merged such
451 |  |  |  |  |  |  | that the environment configuration file will take precedence over the global
452 |  |  |  |  |  |  | configuration file.
453 |  |  |  |  |  |  |
454 |  |  |  |  |  |  | Arbitrary configuration directives can be put into your configuration files
455 |  |  |  |  |  |  | and they can be accessed like this:
456 |  |  |  |  |  |  |
457 |  |  |  |  |  |  | config(get => 'foo');
458 |  |  |  |  |  |  |
459 |  |  |  |  |  |  | The configuration accessors will only give you configuration directives found
460 |  |  |  |  |  |  | at the root of the configuration file. So if you use any data structures you
461 |  |  |  |  |  |  | will have to decode them yourself. For example, if you create a YAML file like
462 |  |  |  |  |  |  | this:
463 |  |  |  |  |  |  |
464 |  |  |  |  |  |  | foo:
465 |  |  |  |  |  |  | bar1: asdf
466 |  |  |  |  |  |  | bar2: fdsa
467 |  |  |  |  |  |  |
468 |  |  |  |  |  |  | Then you will only be able to get the value to C<bar1> like this:
469 |  |  |  |  |  |  |
470 |  |  |  |  |  |  | my $foo = config(get => 'foo')->{'bar1'};
471 |  |  |  |  |  |  |
472 |  |  |  |  |  |  | =head2 Reserved Configuration Options
473 |  |  |  |  |  |  |
474 |  |  |  |  |  |  | To support the components of Prancer, these keys are used:
475 |  |  |  |  |  |  |
476 |  |  |  |  |  |  | =over 4
477 |  |  |  |  |  |  |
478 |  |  |  |  |  |  | =item logger
479 |  |  |  |  |  |  |
480 |  |  |  |  |  |  | Configures the logging system. For example:
481 |  |  |  |  |  |  |
482 |  |  |  |  |  |  | logger:
483 |  |  |  |  |  |  | driver: Prancer::Logger::WhateverLogger
484 |  |  |  |  |  |  | options:
485 |  |  |  |  |  |  | level: debug
486 |  |  |  |  |  |  |
487 |  |  |  |  |  |  | For the console logger, see L<Prancer::Logger::Console> for more options.
488 |  |  |  |  |  |  |
489 |  |  |  |  |  |  | =item template
490 |  |  |  |  |  |  |
491 |  |  |  |  |  |  | Configures the templating system. For example:
492 |  |  |  |  |  |  |
493 |  |  |  |  |  |  | template:
494 |  |  |  |  |  |  | driver: Prancer::Template::WhateverEngine
495 |  |  |  |  |  |  | options:
496 |  |  |  |  |  |  | template_dir: /srv/www/site/templates
497 |  |  |  |  |  |  | encoding: utf8
498 |  |  |  |  |  |  | start_tag: "<%"
499 |  |  |  |  |  |  | end_tag: "%>"
500 |  |  |  |  |  |  |
501 |  |  |  |  |  |  | For the Template Toolkit plugin, see L<Prancer::Template::TemplateToolkit> for
502 |  |  |  |  |  |  | more options.
503 |  |  |  |  |  |  |
504 |  |  |  |  |  |  | =item database
505 |  |  |  |  |  |  |
506 |  |  |  |  |  |  | Configures database connections. For example:
507 |  |  |  |  |  |  |
508 |  |  |  |  |  |  | database:
509 |  |  |  |  |  |  | default:
510 |  |  |  |  |  |  | driver: Prancer::Database::Driver::WhateverDriver
511 |  |  |  |  |  |  | options:
512 |  |  |  |  |  |  | username: test
513 |  |  |  |  |  |  | password: test
514 |  |  |  |  |  |  | database: test
515 |  |  |  |  |  |  |
516 |  |  |  |  |  |  | See L<Prancer::Database> for more options.
517 |  |  |  |  |  |  |
518 |  |  |  |  |  |  | =item static
519 |  |  |  |  |  |  |
520 |  |  |  |  |  |  | Configures a directory where static documents can be found and served using
521 |  |  |  |  |  |  | L<Plack::Middleware::Static>. For example:
522 |  |  |  |  |  |  |
523 |  |  |  |  |  |  | static:
524 |  |  |  |  |  |  | path: /srv/www/site/static
525 |  |  |  |  |  |  |
526 |  |  |  |  |  |  | The only configuration option for static documents is C<path>. If this path
527 |  |  |  |  |  |  | is not defined your application will not start. If this path does not point
528 |  |  |  |  |  |  | to a directory that is readable your application will not start.
529 |  |  |  |  |  |  |
530 |  |  |  |  |  |  | =back
531 |  |  |  |  |  |  |
532 |  |  |  |  |  |  | =head1 CREDITS
533 |  |  |  |  |  |  |
534 |  |  |  |  |  |  | Large portions of this library were taken from the following locations and
535 |  |  |  |  |  |  | projects:
536 |  |  |  |  |  |  |
537 |  |  |  |  |  |  | =over 4
538 |  |  |  |  |  |  |
539 |  |  |  |  |  |  | =item
540 |  |  |  |  |  |  |
541 |  |  |  |  |  |  | HTTP status code documentation taken from L<Wikipedia|http://www.wikipedia.org>.
542 |  |  |  |  |  |  |
543 |  |  |  |  |  |  | =item
544 |  |  |  |  |  |  |
545 |  |  |  |  |  |  | L<Prancer::Config> is derived directly from L<Dancer2::Core::Role::Config>.
546 |  |  |  |  |  |  | Thank you to the L<Dancer2|https://github.com/PerlDancer/Dancer2> team.
547 |  |  |  |  |  |  |
548 |  |  |  |  |  |  | =item
549 |  |  |  |  |  |  |
550 |  |  |  |  |  |  | L<Prancer::Request>, L<Prancer::Request::Upload> and L<Prancer::Response> are
551 |  |  |  |  |  |  | but thin wrappers to and reimplementations of L<Plack::Request>,
552 |  |  |  |  |  |  | L<Plack::Request::Upload> and L<Prancer::Response>. Thank you to Tatsuhiko
553 |  |  |  |  |  |  | Miyagawa.
554 |  |  |  |  |  |  |
555 |  |  |  |  |  |  | =item
556 |  |  |  |  |  |  |
557 |  |  |  |  |  |  | L<Prancer::Database> is derived directly from L<Dancer::Plugin::Database>.
558 |  |  |  |  |  |  | Thank you to David Precious.
559 |  |  |  |  |  |  |
560 |  |  |  |  |  |  | =back
561 |  |  |  |  |  |  |
562 |  |  |  |  |  |  | =head1 COPYRIGHT
563 |  |  |  |  |  |  |
564 |  |  |  |  |  |  | Copyright 2013, 2014 Paul Lockaby. All rights reserved.
565 |  |  |  |  |  |  |
566 |  |  |  |  |  |  | This library is free software; you can redistribute it and/or modify it under
567 |  |  |  |  |  |  | the same terms as Perl itself.
568 |  |  |  |  |  |  |
569 |  |  |  |  |  |  | =cut
570 |  |  |  |  |  |  |