#!/usr/bin/env perl
use Kelp::Base -strict;
use Getopt::Long;
use File::Path 'make_path';
use Kelp::Template;
use File::Basename;
use File::Slurp 'write_file';
my $path = '.';
my $verbose = 1;
my $force = 0;
my $less = 0;
my $help = 0;
GetOptions(
"path=s" => \$path,
"verbose!" => \$verbose,
"force!" => \$force,
"less" => \$less,
"help" => \$help
);
my $name = $ARGV[0] || do { $help = 1; '' };
if ( $help ) {
my $usage = q[
Usage: Kelp [options] <name>
Options:
--path=s Path where to create the files
--less Create a Kelp::Less application files
--(no)verbose Display information
--force Force overwriting existing files
--help This help screen
];
say $usage;
exit;
}
# Remove the slash at the end
$path =~ s{/$}{};
# Get module path and name
my @parts = split( /::/, $name );
my $module_file = pop @parts;
my $module_path = join( '/', @parts );
# Template
my $files = do {
my $template = Kelp::Template->new();
my $output = $template->process(
\*DATA, {
module_file => $module_file,
module_path => $module_path,
path => $path,
name => $name,
less => $less
}
);
my %result = ();
my $key;
for my $line (split(/\n/, $output)) {
if ( $line =~ /^\s*\:(.+)/ ) {
$key = $1;
$result{$key} = [];
next;
}
if ( defined $key ) {
push @{$result{$key}}, $line, "\n";
}
else {
die "No filename for line [$line]";
}
}
\%result;
};
while ( my ( $filename, $lines ) = each %$files ) {
my $dir = $path . '/' . dirname($filename);
$filename = $path . '/' . $filename;
if ( !-d $dir ) {
_say("Creating folder: $dir");
make_path($dir);
}
if ( -e $filename && !$force) {
say "File $filename exists. Use --force to overwrite.";
next;
}
_say("Writing file: $filename");
write_file( $filename, $lines );
}
sub _say {
my $what = shift;
if ($verbose) {
say $what;
}
}
__DATA__
[% IF less -%]
:[% name %].psgi
use Kelp::Less;
module 'Logger::Simple';
get '/' => sub {
"Hello, world!";
};
run;
[% ELSE -%]
:app.psgi
use lib 'lib';
use [% name %];
my $app = [% name %]->new();
$app->run;
:lib/[% module_path %]/[% module_file %].pm
package [% name %];
use Kelp::Base 'Kelp';
sub build {
my $self = shift;
my $r = $self->routes;
$r->add( '/home', 'home' );
$r->add( '/config', sub { $_[0]->config_hash } );
}
sub home {
my $self = shift;
$self->template('home');
}
1;
:conf/config.pl
# Common settings
{
modules => [qw/Template JSON Logger/],
modules_init => {
# One log for errors and one for debug
Logger => {
outputs => [
[
'File',
name => 'debug',
filename => 'log/debug.log',
min_level => 'debug',
mode => '>>',
newline => 1,
binmode => ":encoding(UTF-8)"
], [
'File',
name => 'error',
filename => 'log/error.log',
min_level => 'error',
mode => '>>',
newline => 1,
binmode => ":encoding(UTF-8)"
],
]
},
# JSON prints pretty
JSON => {
pretty => 1
},
# Enable UTF-8 in Template
Template => {
encoding => 'utf8'
}
}
};
:conf/deployment.pl
# Options specific to deployment only
{
modules_init => {
# In deployment, only log the errors
Logger => {
outputs => [
[
'File',
name => 'error',
filename => 'log/error.log',
min_level => 'error',
mode => '>>',
newline => 1,
binmode => ":encoding(UTF-8)"
],
]
},
# Compress JSON output in deployment
JSON => {
pretty => 0
},
}
};
:conf/development.pl
# Options specific to development only
{
# Add StackTrace in development
"+middleware" => ['StackTrace'],
middleware_init => {
StackTrace => {
force => 1
}
}
};
:conf/test.pl
# Options specific to testing only
{
# No Logger when testing
"-modules" => ['Logger']
}
:views/home.tt
Hello, world!
:log/keep
keeper
:t/main.t
use Kelp::Base -strict;
use Kelp::Test;
use Test::More;
use HTTP::Request::Common;
use [% name %];
# Create an application object
my $app = [% name %]->new( mode => 'test' );
# Feed it into a test object
my $t = Kelp::Test->new( app => $app );
# Send a GET request to /home and test the response
$t->request( GET '/home' )
->code_is(200)
->content_type_is('text/html')
->content_like(qr/Hello, world!/);
done_testing;
[% END %]