File Coverage

blib/lib/App/WRT/Renderer.pm
Criterion Covered Total %
statement 62 68 91.1
branch 8 14 57.1
condition n/a
subroutine 10 10 100.0
pod 5 5 100.0
total 85 97 87.6


line stmt bran cond sub pod time code
1             package App::WRT::Renderer;
2              
3 2     2   439 use strict;
  2         5  
  2         57  
4 2     2   14 use warnings;
  2         4  
  2         52  
5 2     2   21 use 5.10.0;
  2         7  
6              
7 2     2   14 use Carp;
  2         13  
  2         116  
8 2     2   26 use File::Basename;
  2         3  
  2         1584  
9              
10             =pod
11              
12             =head1 NAME
13              
14             App::WRT::Renderer - render a wrt repo to publishable HTML
15              
16             =head1 SYNOPSIS
17              
18             use App::WRT;
19             use App::WRT::Renderer;
20              
21             my $wrt = App::WRT::new_from_file($config_file);
22             my $renderer = App::WRT::Renderer->new(
23             $wrt,
24             sub { say $_[0]; }
25             );
26              
27             $renderer->render();
28              
29             =head1 METHODS
30              
31             =over
32              
33             =item new($class, $entry_dir, $logger, $io)
34              
35             Get a new Renderer. Takes an instance of App::WRT, a logging callback, and a
36             App::WRT::FileIO or similar object to be used for the actual intake and
37             mangling of things on the filesystem.
38              
39             =cut
40              
41             sub new {
42 2     2 1 7 my $class = shift;
43 2         6 my ($wrt, $logger, $io) = @_;
44              
45 2 50       9 ref($logger) eq 'CODE' or
46             croak("Error: Renderer expects an anonymous function for logging");
47              
48 2         12 my %params = (
49             wrt => $wrt,
50             logger => $logger,
51             io => $io,
52             );
53              
54 2         5 my $self = \%params;
55 2         7 bless $self, $class;
56             }
57              
58              
59             =item write($path, $contents)
60              
61             Write $contents to $path, using the FileIO object passed into the constructor
62             above.
63              
64             =cut
65              
66             sub write {
67 60     60 1 140 my ($self, $file, $contents) = @_;
68 60         186 $self->{io}->file_put_contents($file, $contents)
69             }
70              
71              
72             =item render($class, $entry_dir)
73              
74             Render entries to F.
75              
76             =cut
77              
78             sub render {
79 2     2 1 9 my $self = shift;
80              
81 2         14 my $entry_dir = $self->{wrt}->{entry_dir};
82 2         5 my $publish_dir = $self->{wrt}->{publish_dir};
83              
84             # Ensure that publication path exists and is a directory:
85 2 50       79 if (-e $publish_dir) {
86 2 50       33 unless (-d $publish_dir) {
87 0         0 croak("$publish_dir exists but is not a directory");
88             }
89             } else {
90 0         0 $self->log("Attempting to create $publish_dir");
91 0 0       0 unless ($self->dir_make_logged($publish_dir)) {
92 0         0 croak("Could not create $publish_dir");
93             }
94             }
95              
96             # Handle the front page. With no entries given, display() will use the
97             # configured default, which is probably "new" unless the user has changed it.
98             $self->write(
99             "${publish_dir}/index.html",
100             $self->{wrt}->display()
101 2         21 );
102              
103             # Handle feed formats:
104 2         8 my $feed_alias = $self->{wrt}->{feed_alias};
105 2         20 my $xml_feed_content = $self->{wrt}->feed_print_recent();
106 2         386 my $json_feed_content = $self->{wrt}->feed_print_json_recent();
107 2         167 $self->write("${publish_dir}/${feed_alias}", $xml_feed_content);
108 2         12 $self->write("${publish_dir}/${feed_alias}.xml", $xml_feed_content);
109 2         11 $self->write("${publish_dir}/${feed_alias}.json", $json_feed_content);
110              
111             # Handle any other paths that aren't derived directly from files:
112 2         6 my @meta_paths = qw(all);
113              
114 2         8 my $rendered_count = 0;
115 2         4 my $copied_count = 0;
116 2         11 for my $target ($self->{wrt}->{entries}->all(), @meta_paths)
117             {
118             # Skip index files - these are the text content of an entry, not
119             # a sub-entry:
120 88 100       236 next if $target =~ m{/index$};
121              
122             # Lowercase and alphanumeric + underscores + dashes, no dots - an entry:
123 72 100       239 if ($self->{wrt}->{entries}->is_renderable($target)) {
124 52         173 $self->dir_make_logged("$publish_dir/$target");
125              
126 52         148 my $rendered = $self->{wrt}->display($target);
127              
128 52         134 my $target_file = "$publish_dir/$target/index.html";
129 52         596 $self->log("[write] $target_file " . length($rendered));
130 52         247 $self->write($target_file, $rendered);
131 52         73 $rendered_count++;
132 52         121 next;
133             }
134              
135             # A directory - no-op:
136 20 50       435 if (-d "$entry_dir/$target") {
137 0         0 $self->log("[directory] $entry_dir/$target");
138 0         0 next;
139             }
140              
141             # Some other file - a static asset of some kind:
142 20         652 my $dirname = dirname($target);
143 20         98 $self->log("[copy] archives/$target -> $publish_dir/$target");
144 20         217 $self->dir_make_logged("$publish_dir/$dirname");
145 20         80 $self->{io}->file_copy("$entry_dir/$target", "$publish_dir/$target");
146 20         35 $copied_count++;
147             }
148              
149 2         17 $self->log("rendered $rendered_count entries");
150 2         13 $self->log("copied $copied_count static files");
151              
152             # Presumed success:
153 2         14 return 1;
154             }
155              
156              
157             =item dir_make_logged($path)
158              
159             Make a directory path or log an error.
160              
161             =cut
162              
163             sub dir_make_logged {
164 72     72 1 113 my ($self, $path) = @_;
165 72         83 my $path_err;
166 72         164 $self->log("[create] $path");
167 72         297 $self->{io}->dir_make($path);
168             # XXX: surface these somehow
169             # $self->log(Dumper($path_err)) if @{ $path_err };
170             }
171              
172              
173             =item log(@log_items)
174              
175             Call logging callback with passed parameters.
176              
177             =cut
178              
179             sub log {
180 148     148 1 209 my ($self) = shift;
181 148         354 $self->{logger}->(@_);
182             }
183              
184             =back
185              
186             =cut
187              
188             1;