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 6     6   730258 use 5.014;
  6         23  
26              
27 6     6   3862 use Moose;
  6         3362926  
  6         64  
28 6     6   56021 use Template;
  6         129646  
  6         297  
29 6     6   2904 use Template::Provider::Pandoc;
  6         1350118  
  6         506  
30 6     6   2646 use FindBin '$Bin';
  6         4753  
  6         1076  
31 6     6   69 use File::Find;
  6         13  
  6         489  
32 6     6   6507 use Path::Tiny;
  6         108455  
  6         584  
33 6     6   5445 use Getopt::Long;
  6         92713  
  6         55  
34 6     6   1265 use Carp;
  6         14  
  6         481  
35 6     6   3436 use Clone 'clone';
  6         3882  
  6         488  
36 6     6   2830 use YAML::XS 'LoadFile';
  6         22531  
  6         477  
37 6     6   4260 use Sys::Hostname;
  6         8741  
  6         459  
38 6     6   4095 use URI;
  6         43840  
  6         330  
39              
40 6     6   3387 use App::Aphra::File;
  6         55  
  6         11045  
41              
42             our $VERSION = '0.2.8';
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   107 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   5 my $self = shift;
82              
83 2         5 my %opts;
84 2         19 GetOptions(\%opts,
85             'source=s', 'fragments=s', 'layouts=s', 'wrapper=s',
86             'target=s', 'extensions=s%', 'output=s',
87             'version', 'help');
88              
89 2         2146 for (qw[version help]) {
90 4 50 0     16 $self->$_ and exit if $opts{$_};
91             }
92              
93 2         4 my %defaults = %{ $self->config_defaults };
  2         80  
94              
95 2         6 my %config;
96 2         8 for (keys %defaults) {
97 14   33     49 $config{$_} = $opts{$_} // $defaults{$_};
98             }
99              
100 2         60 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         3 my $site_vars = {};
113              
114 1 50       82 if (-f 'site.yml') {
115 0         0 $site_vars = LoadFile('site.yml');
116             }
117              
118 1         47 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   2 my $self = shift;
129              
130 1         2 my $include_path;
131 1         4 foreach (qw[source fragments layouts]) {
132             push @$include_path, $self->config->{$_}
133 3 50       93 if exists $self->config->{$_};
134             }
135              
136 1         41 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         40 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         41 );
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