# NAME

Prancer

# SYNOPSIS

When using as part of a web application:

    ===> foobar.yml

    session:
        state:
            driver: Prancer::Session::State::Cookie
            options:
                session_key: PSESSION
        store:
            driver: Prancer::Session::Store::Storable
            options:
                dir: /tmp/prancer/sessions

    static:
        path: /static
        dir: /srv/www/resources

    ===> myapp.psgi

    #!/usr/bin/env perl

    use strict;
    use warnings;
    use Plack::Runner;

    # this just returns a PSGI application. $x can be wrapped with additional
    # middleware before sending it along to Plack::Runner.
    my $x = MyApp->new("/path/to/foobar.yml")->to_psgi_app();

    # run the psgi app through Plack and send it everything from @ARGV. this
    # way Plack::Runner will get options like what listening port to use and
    # application server to use -- Starman, Twiggy, etc.
    my $runner = Plack::Runner->new();
    $runner->parse_options(@ARGV);
    $runner->run($x);

    ===> MyApp.pm

    package MyApp;

    use strict;
    use warnings;

    use Prancer qw(config);

    sub initialize {
        my $self = shift;

        # in here we can initialize things like plugins
        # but this method is not required to be implemented

        return;
    }

    sub handler {
        my ($self, $env, $request, $response, $session) = @_;

        sub (GET + /) {
            $response->header("Content-Type" => "text/plain");
            $response->body("Hello, world!");
            return $response->finalize(200);
        }, sub (GET + /foo) {
            $response->header("Content-Type" => "text/plain");
            $response->body(sub {
                my $writer = shift;
                $writer->write("Hello, world!");
                $writer->close();
                return;
            });
        }
    }

    1;

If you save the above snippet as `myapp.psgi` and run it like this:

    plackup myapp.psgi

You will get "Hello, world!" in your browser. Or you can use Prancer as part of
a standalone command line application:

    #!/usr/bin/env perl

    use strict;
    use warnings;

    use Prancer::Core qw(config);

    # the advantage to using Prancer in a standalone application is the ability
    # to use a standard configuration and to load plugins for things like
    # loggers and database connectors and template engines.
    my $x = Prancer::Core->new("/path/to/foobar.yml");
    print "Hello, world!;

# DESCRIPTION

Prancer is yet another PSGI framework that provides routing and session
management as well as plugins for logging, database access, and template
engines. It does this by wrapping
[Web::Simple](https://metacpan.org/pod/Web::Simple) to handle routing and by
wrapping other libraries to bring easy access to things that need to be done in
web applications.

There are two parts to using Prancer for a web application: a package to
contain your application and a script to call your application. Both are
necessary.

The package containing your application should contain a line like this:

    use Prancer;

This modifies your application package such that it inherits from Prancer. It
also means that your package must implement the `handler` method and
optionally implement the `initialize` method. As Prancer inherits from
Web::Simple it will also automatically enable the `strict` and `warnings`
pragmas.

As mentioned, putting `use Prancer;` at the top of your package will require
you to implement the `handler` method, like this:

    sub handler {
        my ($self, $env, $request, $response, $session) = @_;

        # routing goes in here.
        # see Web::Simple for documentation on writing routing rules.
        sub (GET + /) {
            $response->header("Content-Type" => "text/plain");
            $response->body("Hello, world!");
            return $response->finalize(200);
        }
    }

The `$request` variable is a
[Prancer::Request](https://metacpan.org/pod/Prancer::Request) object. The
`$response` variable is a
[Prancer::Response](https://metacpan.org/pod/Prancer::Response) object. The
`$session` variable is a
[Prancer::Session](https://metacpan.org/pod/Prancer::Session) object. If there
is no configuration for sessions in any of your configuration files then
`$session` will be `undef`.

You may implement your own `new` method in your application but you **MUST**
call `$class->SUPER::new(@_);` to get the configuration file loaded and
any methods exported. As an alternative to implemeting `new` and remembering
to call `SUPER::new`, Prancer will make a call to `->initialize` at the
end of its own implementation of `new` so things that you might put in `new`
can instead be put into `initialize`, like this:

    sub initialize {
        my $self = shift;

        # this is where you can initialize things when your package is created

        return;
    }

By default, Prancer does not export anything into your package's namespace.
However, that doesn't mean that there is not anything that it _could_ export
were one to ask:

    use Prancer qw(config);

Importing `config` will make the keyword `config` available which gives
access to any configuration options loaded by Prancer.

The second part of the Prancer equation is the script that creates and calls
your package. This can be a pretty small and standard little script, like this:

    my $myapp = MyApp->new("/path/to/foobar.yml")
    my $psgi = $myapp->to_psgi_app();

`$myapp` is just an instance of your package. You can pass to `new` either
one specific configuration file or a directory containing lots of configuration
files. The functionality is documented in `Prancer::Config`.

`$psgi` is just a PSGI app that you can send to
[Plack::Runner](https://metacpan.org/pod/Plack::Runner) or whatever you use to
run PSGI apps. You can also wrap middleware around `$app`.

    my $psgi = $myapp->to_psgi_app();
    $psgi = Plack::Middleware::Runtime->wrap($psgi);

# CONFIGURATION

Prancer needs a configuration file. Ok, it doesn't _need_ a configuration file
file. By default, Prancer does not require any configuration. But it is less
useful without one. You _could_ always create your application like this:

    my $app = MyApp->new->to_psgi_app();

How Prancer loads configuration files is documented in
[Prancer::Config](https://metacpan.org/pod/Prancer::Config). Anything you put
into your configuration file is available to your application.

There are two special configuration keys reserved by Prancer. The key
`session` will configure Prancer's session as documented in
[Prancer::Session](https://metacpan.org/pod/Prancer::Session). The key `static`
will configure static file loading through
[Plack::Middleware::Static](https://metacpan.org/pod/Plack::Middleware::Static).

To configure static file loading you can add this to your configuration file:

    static:
        path: /static
        dir: /path/to/my/resources

The `dir` option is required to indicate the root directory for your static
resources. The `path` option indicates the web path to link to your static
resources. If no path is not provided then static files can be accessed under
`/static` by default.

# CREDITS

This module could have been written except on the shoulders of the following
giants:

- The name "Prancer" is a riff on the popular PSGI framework [Dancer](https://metacpan.org/pod/Dancer) and [Dancer2](https://metacpan.org/pod/Dancer2). [Prancer::Config](https://metacpan.org/pod/Prancer::Config) is derived directly from [Dancer2::Core::Role::Config](https://metacpan.org/pod/Dancer2::Core::Role::Config). Thank you to the Dancer/Dancer2 teams.
- [Prancer::Database](https://metacpan.org/pod/Prancer::Database) is derived from [Dancer::Plugin::Database](https://metacpan.org/pod/Dancer::Plugin::Database). Thank you to David Precious.
- [Prancer::Request](https://metacpan.org/pod/Prancer::Request), [Prancer::Request::Upload](https://metacpan.org/pod/Prancer::Request::Upload), [Prancer::Response](https://metacpan.org/pod/Prancer::Response), [Prancer::Session](https://metacpan.org/pod/Prancer::Session) and the session packages are but thin wrappers with minor modifications to [Plack::Request](https://metacpan.org/pod/Plack::Request), [Plack::Request::Upload](https://metacpan.org/pod/Plack::Request::Upload), [Plack::Response](https://metacpan.org/pod/Plack::Response), and [Plack::Middleware::Session](https://metacpan.org/pod/Plack::Middleware::Session). Thank you to Tatsuhiko Miyagawa.
- The entire routing functionality of this module is offloaded to [Web::Simple](https://metacpan.org/pod/Web::Simple). Thank you to Matt Trout for some great code that I am able to easily leverage.

# COPYRIGHT

Copyright 2013, 2014 Paul Lockaby. All rights reserved.

This library is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.

# SEE ALSO

- [Plack](https://metacpan.org/pod/Plack)
- [Web::Simple](https://metacpan.org/pod/Web::Simple)