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!