File Coverage

blib/lib/DocLife.pm
Criterion Covered Total %
statement 59 81 72.8
branch 9 16 56.2
condition 6 11 54.5
subroutine 17 21 80.9
pod 2 9 22.2
total 93 138 67.3


line stmt bran cond sub pod time code
1             package DocLife;
2              
3 4     4   81295 use strict;
  4         10  
  4         146  
4 4     4   20 use warnings;
  4         9  
  4         170  
5             our $VERSION = '0.03';
6              
7 4     4   2127 use parent qw( Plack::Component );
  4         808  
  4         24  
8 4     4   97908 use Cwd 'abs_path';
  4         10  
  4         265  
9 4     4   25 use Digest::MD5;
  4         8  
  4         150  
10 4     4   24 use File::Find;
  4         8  
  4         323  
11 4     4   43 use File::Spec;
  4         7  
  4         94  
12 4     4   917 use URI::Escape;
  4         1462  
  4         849  
13 4     4   21713 use Path::Class;
  4         229570  
  4         311  
14 4     4   3938 use Plack::Request;
  4         149390  
  4         186  
15 4         29 use Plack::Util::Accessor qw(
16             base_url
17             root
18             suffix
19 4     4   4129 );
  4         1068  
20              
21             sub prepare_app {
22 15     15 1 81128 my ($self, $env) = @_;
23 15 100       84 $self->base_url('/') unless defined $self->base_url;
24 15   50     198 $self->root(dir(abs_path($self->root || './')));
25             }
26              
27             sub call {
28 15     15 1 2330 my ($self, $env) = @_;
29              
30 15         116 my $req = Plack::Request->new($env);
31 15         184 my $res = $req->new_response(200);
32 15         8827 $res->content_type('text/html; charset=UTF-8');
33              
34 15 50 66     586 if ($req->path eq '/') {
    100          
35 0         0 $self->toppage($req, $res);
36             }
37             elsif ($req->path=~m|\Q/../| or $req->path=~m|\Q//|) {
38 3         76 $self->forbidden($req, $res);
39             }
40             else {
41 12         393 $self->page($req, $res);
42             }
43 15         1151 $res->finalize;
44             }
45              
46             sub format {
47 3     3 0 7 my ($self, $req, $res, $file) = @_;
48 3         10 $res->content_type('text/plain; charset=UTF-8');
49 3         83 $res->body($file->slurp);
50             }
51              
52             sub page {
53 12     12 0 34 my ($self, $req, $res) = @_;
54              
55 12         65 my $file = file($self->root, $req->path);
56 12 100 100     1980 $file = file($self->root, $req->path . $self->suffix) if !-f $file and defined $self->suffix;
57 12 100       1850 if (-f $file) {
58 9         529 $self->format($req, $res, $file);
59             }
60             else {
61 3         153 $self->not_found($req, $res);
62             }
63             }
64              
65             sub toppage {
66 0     0 0 0 my ($self, $req, $res) = @_;
67              
68 0         0 my $body = $self->html_header;
69 0         0 my $suffix = $self->suffix;
70 0         0 my $root = $self->root;
71 0         0 my @files;
72             find( sub {
73 0 0   0   0 return unless -f $_;
74 0 0 0     0 return if length $suffix and $_!~m|\Q$suffix\E$|;
75 0         0 push @files, $File::Find::name;
76 0         0 }, $root );
77 0         0 $body.= "
    \n";
78 0         0 for my $file ( sort @files ) {
79 0         0 $file=~s|^\Q$root\E/?||;
80 0         0 my $url = $self->base_url . uri_escape($file);
81 0 0       0 if (length $suffix) {
82 0         0 $file=~s|\Q$suffix\E$||;
83             }
84 0         0 $body.= qq{
  • $file
  • \n};
    85             }
    86 0         0 $body.= "\n";
    87 0         0 $body.= $self->html_footer;
    88 0         0 $res->body($body);
    89             }
    90              
    91             sub forbidden {
    92 3     3 0 29 my ($self, $req, $res) = @_;
    93 3         15 $res->status(403);
    94 3         31 $res->body('Forbidden.');
    95             }
    96              
    97             sub not_found {
    98 3     3 0 10 my ($self, $req, $res) = @_;
    99 3         15 $res->status(404);
    100 3         24 $res->body('Not Found.');
    101             }
    102              
    103             sub html_header {
    104             <<"EOF"
    105            
    106            
    107            
    108             Index
    109            
    110            
    111             EOF
    112 0     0 0   }
    113              
    114             sub html_footer {
    115             <<"EOF"
    116            
    117            
    118             EOF
    119 0     0 0   }
    120              
    121             =head1 NAME
    122              
    123             DocLife - Document Viewer written in Perl, to run under Plack.
    124              
    125             =head1 SYNOPSIS
    126              
    127             # app.psgi
    128             use DocLife::Pod;
    129             DocLife::Pod->new( root => "./lib" );
    130              
    131             # one-liner
    132             plackup -MDocLife::Pod -e 'DocLife::Pod->new( root => "./lib" )->to_app'
    133              
    134             =head1 How To Mount
    135              
    136             need base_url option.
    137              
    138             # app.psgi
    139             use Plack::Builder;
    140             use DocLife::Pod;
    141             use DocLife::Markdown;
    142              
    143             my $pod_app = DocLife::Pod->new(
    144             root => '../lib',
    145             base_url => '/pod/'
    146             );
    147              
    148             my $doc_app = DocLife::Markdown->new(
    149             root => './doc',
    150             suffix => '.md',
    151             base_url => '/doc/'
    152             );
    153              
    154             builder {
    155             mount '/pod' => $pod_app;
    156             mount '/doc' => $doc_app;
    157             };
    158              
    159             =head1 CONFIGURATION
    160              
    161             =over 4
    162              
    163             =item root
    164              
    165             Document root directory. Defaults to the current directory.
    166              
    167             =back
    168              
    169             =over 4
    170              
    171             =item base_url
    172              
    173             Specifies a base URL for all URLs on a index page. Defaults to the `/`.
    174              
    175             =back
    176              
    177             =over 4
    178              
    179             =item suffix
    180              
    181             Show only files that match the suffix. No url suffix.
    182              
    183             =back
    184              
    185             =head1 SEE ALSO
    186              
    187             L
    188              
    189             =head1 COPYRIGHT
    190              
    191             Copyright 2013 Shinichiro Aska
    192              
    193             =head1 LICENSE
    194              
    195             This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
    196              
    197             =cut
    198              
    199             1;