File Coverage

blib/lib/App/Aphra.pm
Criterion Covered Total %
statement 66 122 54.1
branch 3 32 9.3
condition 1 11 9.0
subroutine 19 28 67.8
pod 0 6 0.0
total 89 199 44.7


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             App::Aphra - A simple static sitebuilder in Perl.
4              
5             =head1 SYNOPSIS
6              
7             use App::Aphra;
8              
9             @ARGV = qw[build];
10              
11             my $app = App::Aphra->new;
12             $app->run;
13              
14             =head1 DESCRIPTION
15              
16             For now, you probably want to look at the command-line program L<aphra>
17             which does all you want and is far better documented.
18              
19             I'll improve this documentation in the future.
20              
21             =cut
22              
23             package App::Aphra;
24              
25 7     7   861918 use 5.014;
  7         30  
26              
27 7     7   4505 use Moose;
  7         3967417  
  7         80  
28 7     7   68109 use Template;
  7         182013  
  7         417  
29 7     7   5538 use Template::Provider::Pandoc;
  7         1612347  
  7         533  
30 7     7   2540 use FindBin '$Bin';
  7         4854  
  7         1001  
31 7     7   58 use File::Find;
  7         16  
  7         558  
32 7     7   7241 use Path::Tiny;
  7         109296  
  7         596  
33 7     7   6065 use Getopt::Long;
  7         103385  
  7         56  
34 7     7   1589 use Carp;
  7         14  
  7         666  
35 7     7   4026 use Clone 'clone';
  7         4315  
  7         576  
36 7     7   3513 use YAML::XS 'LoadFile';
  7         27592  
  7         556  
37 7     7   3707 use Sys::Hostname;
  7         10187  
  7         633  
38 7     7   4678 use URI;
  7         49582  
  7         309  
39              
40 7     7   3866 use App::Aphra::File;
  7         63  
  7         12908  
41              
42             our $VERSION = '0.2.9';
43              
44             has commands => (
45             isa => 'HashRef',
46             is => 'ro',
47             default => sub { {
48             build => \&build,
49             serve => \&serve,
50             } },
51             );
52              
53             has config_defaults => (
54             isa => 'HashRef',
55             is => 'ro',
56             lazy_build => 1,
57             );
58              
59             sub _build_config_defaults {
60             return {
61 2     2   97 source => 'in',
62             fragments => 'fragments',
63             layouts => 'layouts',
64             wrapper => 'page',
65             target => 'docs',
66             extensions => {
67             tt => 'template',
68             md => 'markdown',
69             },
70             output => 'html',
71             };
72             }
73              
74             has config => (
75             isa => 'HashRef',
76             is => 'ro',
77             lazy_build => 1,
78             );
79              
80             sub _build_config {
81 2     2   49 my $self = shift;
82              
83 2         6 my %opts;
84 2         16 GetOptions(\%opts,
85             'source=s', 'fragments=s', 'layouts=s', 'wrapper=s',
86             'target=s', 'extensions=s%', 'output=s',
87             'version', 'help');
88              
89 2         3290 for (qw[version help]) {
90 4 50 0     21 $self->$_ and exit if $opts{$_};
91             }
92              
93 2         6 my %defaults = %{ $self->config_defaults };
  2         100  
94              
95 2         6 my %config;
96 2         8 for (keys %defaults) {
97 14   33     59 $config{$_} = $opts{$_} // $defaults{$_};
98             }
99              
100 2         80 return \%config;
101             }
102              
103             has site_vars => (
104             isa => 'HashRef',
105             is => 'ro',
106             lazy_build => 1,
107             );
108              
109             sub _build_site_vars {
110 1     1   3 my $self = shift;
111              
112 1         9 my $site_vars = {};
113              
114 1 50       104 if (-f 'site.yml') {
115 0         0 $site_vars = LoadFile('site.yml');
116             }
117              
118 1         43 return $site_vars;
119             }
120              
121             has include_path => (
122             isa => 'ArrayRef',
123             is => 'ro',
124             lazy_build => 1,
125             );
126              
127             sub _build_include_path {
128 1     1   3 my $self = shift;
129              
130 1         2 my $include_path;
131 1         3 foreach (qw[source fragments layouts]) {
132             push @$include_path, $self->config->{$_}
133 3 50       97 if exists $self->config->{$_};
134             }
135              
136 1         32 return $include_path;
137             }
138              
139             has template => (
140             isa => 'Template',
141             is => 'ro',
142             lazy_build => 1,
143             );
144              
145             sub _build_template {
146 1     1   3 my $self = shift;
147              
148 1         37 my $exts = clone $self->config->{extensions};
149 1         3 delete $exts->{tt};
150              
151             return Template->new(
152             ENCODING => 'utf8',
153             LOAD_TEMPLATES => [
154             Template::Provider::Pandoc->new(
155             INCLUDE_PATH => $self->include_path,
156             EXTENSIONS => $exts,
157             OUTPUT_FORMAT => $self->config->{output},
158             STRIP_FRONT_MATTER => 1,
159             ),
160             ],
161             VARIABLES => {
162             site => $self->site_vars,
163             aphra => $self,
164             },
165             INCLUDE_PATH => $self->include_path,
166             OUTPUT_PATH => $self->config->{target},
167             WRAPPER => $self->config->{wrapper},
168 1         59 );
169             }
170              
171             has uri => (
172             isa => 'URI',
173             is => 'ro',
174             lazy_build => 1,
175             );
176              
177             sub _build_uri {
178 0     0     my $self = shift;
179              
180 0 0         return URI->new($self->site_vars->{uri}) if $self->site_vars->{uri};
181              
182 0   0       my $host = $self->site_vars->{host} || hostname;
183 0   0       my $protocol = $self->site_vars->{protocol} || 'https';
184              
185 0           my $uri = "$protocol://$host";
186 0 0         $uri .= ':' . $self->site_vars->{port} if $self->site_vars->{port};
187 0           $uri .= '/';
188              
189 0           return URI->new($uri);
190             }
191              
192             sub run {
193 0     0 0   my $self = shift;
194              
195 0           $self->config;
196              
197 0 0         @ARGV or die "Must give a command\n";
198              
199 0           my $cmd = shift @ARGV;
200              
201 0 0         if (my $method = $self->commands->{$cmd}) {
202 0           $self->$method;
203             } else {
204 0           die "$cmd is not a valid command\n";
205             }
206             }
207              
208             sub build {
209 0     0 0   my $self = shift;
210              
211 0           my $src = $self->config->{source};
212              
213 0           path($self->config->{target})->remove_tree;
214 0           path($self->config->{target})->mkpath;
215              
216 0 0         -e $src or die "Cannot find $src\n";
217 0 0         -d $src or die "$src is not a directory\n";
218              
219 0 0         if ($self->site_vars->{redirects}) {
220 0           $self->make_redirects;
221             }
222              
223             find({ wanted => $self->_make_do_this, no_chdir => 1 },
224 0           $self->config->{source});
225             }
226              
227             sub _make_do_this {
228 0     0     my $self = shift;
229              
230             return sub {
231 0 0   0     return unless -f;
232              
233 0           my $f = App::Aphra::File->new({
234             app => $self, filename => $_,
235             });
236              
237 0           $f->process;
238 0           };
239             }
240              
241             sub make_redirects {
242 0     0 0   my $self = shift;
243 0           my $redirects = $self->site_vars->{redirects};
244              
245 0 0         return if !$redirects;
246 0 0         return if !@$redirects;
247              
248 0           my $target = $self->config->{target};
249              
250 0           for (@$redirects) {
251 0           my $from = $_->{from};
252 0 0         $from .= 'index.html' if $from =~ m|/$|;
253              
254 0           my $to = $_->{to};
255              
256 0           my $outdir = path("$target$from")->dirname;
257 0           path($outdir)->mkdir;
258              
259 0 0         open my $out_fh, '>', "$target$from"
260             or die "Cannot open '$target$from' for writing: $!\n";
261              
262 0           print $out_fh <<EOF;
263             <!DOCTYPE html>
264             <html>
265             <head>
266             <meta http-equiv="refresh" content="0; url=$to">
267             </head>
268             </html>
269             EOF
270              
271 0           close $out_fh;
272             }
273             }
274              
275             sub serve {
276 0     0 0   my $self = shift;
277              
278 0           require App::HTTPThis;
279 0 0         if ($@) {
280 0           croak "App::HTTPThis must be installed for 'serve' command";
281             }
282              
283 0           local @ARGV = $self->config->{target};
284 0           App::HTTPThis->new->run;
285             }
286              
287             has ver => (
288             is => 'ro',
289             default => $VERSION,
290             );
291              
292             sub version {
293 0     0 0   my $me = path($0)->basename;
294 0           say "\n$me version: $VERSION\n";
295             }
296              
297             sub help {
298 0     0 0   my $self = shift;
299 0           my $me = path($0)->basename;
300 0           $self->version;
301              
302 0           say <<ENDOFHELP;
303             $me is a simple static sitebuilder which uses the Template Toolkit to
304             process input templates and turn them into a web site.
305             ENDOFHELP
306             }
307              
308             __PACKAGE__->meta->make_immutable;
309              
310             1;
311              
312             =head1 AUTHOR
313              
314             Dave Cross <dave@perlhacks.com>
315              
316             =head1 COPYRIGHT AND LICENCE
317              
318             Copyright (c) 2017-2024, Magnum Solutions Ltd. All Rights Reserved.
319              
320             This library is free software; you can redistribute it and/or modify it
321             under the same terms as Perl itself.
322              
323             =cut