NAME

Kelp::Less - Quick prototyping with Kelp

SYNOPSIS

use Kelp::Less;

get '/person/:name' => sub {
    "Hello " . named 'name';
};

run;

DESCRIPTION

This class exists to provide a way for quick and sloppy prototyping of a web application. It is a wrapper for Kelp, which imports several keywords, making it easier and less verbose to create a quick web app.

It's called Less, because there is less typing involved, and because it is suited for smaller, less complicated web projects. We encourage you to use it anywhere you see fit, however for mid-size and big applications we recommend that you use the fully structured Kelp. This way you can take advantage of its powerful router, initialization and testing capabilities.

QUICK START

Each web app begins with use Kelp::Less;. This automatically imports strict, warnings, v5.10 as well as several useful functions. You can pass any parameters to the constructor at the use statement:

use Kelp::Less mode => 'development';

The above is equivalent to:

use Kelp;
my $app = Kelp->new( mode => 'development' );

After that, you could add any initializations and attributes. For example, connect to a database or setup cache. Kelp::Less exports attr, so you can use it to register attributes to your app.

# Connect to DBI and CHI right away
attr dbh => sub {
    DBI->connect( @{ app->config('database') } );
};

attr cache => sub {
    CHI->new( @{ app->config('cache') } );
};

# Another lazy attribute.
attr version => sub {
    app->dbh->selectrow_array("SELECT version FROM vars");
};

# Later:
app->dbh->do(...);
app->cache->get(...);
if ( app->version ) { ... }

Now is a good time to add routes. Routes are added via the "route" keyword and they are automatically registered in your app. A route needs two parameters - path and destination. These are exactly equivalent to "add" in Kelp::Routes, and you are encouraged to read its POD to get familiar with how to define routes. Here are a few examples for the impatient:

# Add a 'catch-all-methods' route and send it to an anonymous sub
route '/hello/:name' => sub {
    return "Hello " . named('name');
};

# Add a POST route
route [ POST => '/edit/:id' ] => sub {
    # Do something with named('id')
};

# Route that runs an existing sub in your code
route '/login' => 'login';
sub login {
    ...
}

Each route subroutine receives $self and all named placeholders.

route '/:id/:page' => sub {
    my ( $self, $id, $page ) = @_;
};

Here, $self is the app object and it can be used the same way as in a full Kelp route. For the feeling of magic and eeriness, Kelp::Lite aliases app to $self, so the former can be used as a full substitute to the latter. See the exported keywords section for more information.

After you have added all of your routes, it is time to run the app. This is done via a single command:

run;

It returns PSGI ready subroutine, so you can immediately deploy your new app via Plack:

> plackup myapp.psgi
HTTP::Server::PSGI: Accepting connections at http://0:5000/

KEYWORDS

The following list of keywords are exported to allow for less typing in Kelp::Less:

app

This a full alias for $self. It is the application object, and an instance of the Kelp class. You can use it for anything you would use $self inside a route.

route '/die' => sub {
    app->res->code(500);
};

attr

Assigns lazy or active attributes (using Kelp::Base) to app. Use it to initialize your application.

attr mongo => MongoDB::MongoClient->new( ... );

route

Adds a route to app. It is an alias to $self->routes->add, and requires the exact same parameters. See Kelp::Routes for reference.

route '/get-it' => sub { "got it" };

get, post, put, del

These are shortcuts to route restricted to the corresponding HTTP method.

get '/data'  => sub { "Only works with GET" };
post '/data' => sub { "Only works with POST" };
put '/data'  => sub { "Only works with PUT" };
del '/data'  => sub { "Only works with DELETE" };

param

An alias for $self->param that gets the GET or POST parameters. When used with no arguments, it will return an array with the names of all http parameters. Otherwise, it will return the value of the requested http parameter.

get '/names' => sub {
    my @names = param;
    # Now @names contains the names of the params
};

get '/value' => sub {
    my $id = param 'id';
    # Now $is contains the value of 'id'
};

stash

An alias for $self->stash. The stash is a concept originally conceived by the developers of Catalyst. It's a hash that you can use to pass data from one route to another.

# Create a bridge route that checks if the user is authenticated, and saves
# the username in the stash.
get '/user' => { bridge => 1, to => sub {
    return stash->{username} = app->authenticate();
}};

# This route is run after the above bridge, so we know that we have an
# authenticated user and their username in the stash.
get '/user/welcome' => sub {
    return "Hello " . stash 'username';
};

With no arguments stash returns the entire stash hash. A single argument is interpreted as the key to the stash hash and its value is returned accordingly.

named

An alias for $self->named. The named hash contains the names and values of the named placeholders from the current route's path. Much like the stash, with no arguments it returns the entire named hash, and with a single argument it returns the value for the corresponding key in the hash.

get '/:name/:id' => sub {
    my $name = named 'name';
    my $id = name 'id';
};

In the above example a GET request to /james/1000 will initialize $name with "james" and $id with 1000.

req

An alias for $self->req, this provides quick access to the Kelp::Request object for the current route.

# Inside a route
if ( req->is_ajax ) {
    ...
}

res

An alias for $self->res, this is a shortcut for the Kelp::Response object for the current route.

# Inside a route
res->code(403);
res->json->render({ message => "Forbidden" });

template

A shortcut to $self->res->template. Renders a template using the currently loaded template module. Note that a Kelp::Less application does not by default load a template module, so you will have to load it yourself.

use Kelp::Less;

module 'Template', path => 'views';

get '/hello/:name' => sub {
    template 'hello.tt', { name => named 'name' };
};

view

A shortcut for "template".

get '/hello/:name' => sub {
    view 'hello.tt', { name => named 'name' };
};

run

Creates and returns a PSGI ready subroutine, and makes the app ready for Plack.

module

Loads a Kelp module. The module options may be specified after the module name.

module 'JSON::XS', pretty => 1;

config

Provides procedural interface to the configuration.

get '/hello' => sub {
    my $baz = config('bar.foo.baz');
};

TESTING

When writing a Kelp::Less app, we don't have a separate class to initialize and feed into a Kelp::Test object, because all of our code is contained in the app.psgi file. In this case, the Kelp::Test object can be initialized with the name of the PSGI file in the psgi argument.

# t/main.t
use Kelp::Test;

my $t = Kelp::Test->new( psgi => 'app.psgi' );
# Do some tests ...

Since you don't have control over the creation of the Kelp object, if you need to specify a different mode for testing, you can use the PLACK_ENV environmental variable:

> PLACK_ENV=test prove -l

This will enable the conf/test.pl configuration, which you should tailor to your testing needs.

ACKNOWLEDGEMENTS

This module's interface was inspired by Dancer, which in its turn was inspired by Sinatra, so Viva La Open Source!