One of my small projects (10 Years Later, Only 250 SLOC) is a mostly static website generated by some backend programs. (Some of the UI is JavaScript, but it's all data-driven.)
I've spent plenty of time tweaking the page generation, and as such I need to know how things look after running through all of the data-driven templates. While I could deploy to a live web server after running the "Regenerate the desired pages" program, I pulled out the Plack hammer.
Remember how stupidly simple Plack is? A Plack application is just a function. Plack comes with some demonstration applications which are a page or two of code apiece—including the almost exactly right Plack::App::File. You can even run it as a Plack one-liner.
I wanted something a little more: a program I could run with a single argument, the name of the directory root from which to serve files. Something like:
$ plackfile .
$ plackfile root/static/
... would do. This took only a few lines of code:
#!/usr/bin/env perl
use Plack::Runner;
my $app = Plack::App::IndexFile->new({ root => shift })->to_app;
my $runner = Plack::Runner->new;
$runner->parse_options( '--access-log' => '/dev/null', @ARGV );
$runner->run( $app );
package Plack::App::IndexFile;
use parent 'Plack::App::File';
sub locate_file
{
my ($self, $env) = @_;
my $path = $env->{PATH_INFO} || '';
return $self->SUPER::locate_file( $env ) unless $path && $path =~ m{/$};
$env->{PATH_INFO} .= 'index.html';
return $self->SUPER::locate_file( $env );
}
Plack::Runner is the module at the core of plackup
, and Plack::App::File is a Plack core application which serves static files beneath a root directory.
Unfortunately, Plack::App::File
doesn't default to
index.html when the user requests a directory, so I had to override
its locate_file()
method to add this behavior. It's a touch
fragile, as a better approach would be to let P::A::F take an extra optional
coderef constructor parameter to use as a last resort when the user has
requested a directory. Still, this works.
The only other interesting part of this code is the argument handling.
Plack::Runner
takes the same arguments as the plackup
file, but this code defaults to redirecting the access log normally printed to
STDOUT to /dev/null. This is quieter, which matches my normal
purposes, but it's overrideable if necessary.
Two minutes of work on my part (plus 10 writing this post) will save me a tremendous amount of time. Hopefully it will do the same for you.
This is really nifty and i can't remember how often i hacked together something stupid for such a purpose.
Two things to note:
The Plack::App::File link is broken.
Are you intending to submit a pull req to Plack::App::File? :)
Looks like you've re-implemented weborf in Plack :)
Very fun and useful!
I played with Plack::File::Directory too, making a fake cherokee static file server in front of it.
It looks better than the original, and is definitely more perlish ;-) .