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   408 use strict;
  2         4  
  2         52  
4 2     2   10 use warnings;
  2         4  
  2         53  
5 2     2   41 use 5.10.0;
  2         9  
6              
7 2     2   10 use Carp;
  2         3  
  2         136  
8 2     2   13 use File::Basename;
  2         4  
  2         1434  
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 5 my $class = shift;
43 2         7 my ($wrt, $logger, $io) = @_;
44              
45 2 50       10 ref($logger) eq 'CODE' or
46             croak("Error: Renderer expects an anonymous function for logging");
47              
48 2         9 my %params = (
49             wrt => $wrt,
50             logger => $logger,
51             io => $io,
52             );
53              
54 2         4 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 105 my ($self, $file, $contents) = @_;
68 60         154 $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         7 my $publish_dir = $self->{wrt}->{publish_dir};
83              
84             # Ensure that publication path exists and is a directory:
85 2 50       54 if (-e $publish_dir) {
86 2 50       29 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 and Atom feed:
97 2         18 $self->write("${publish_dir}/index.html", $self->{wrt}->display('new'));
98              
99             # Handle feed formats:
100 2         4 my $feed_alias = $self->{wrt}->{feed_alias};
101 2         11 my $xml_feed_content = $self->{wrt}->feed_print_recent();
102 2         390 my $json_feed_content = $self->{wrt}->feed_print_json_recent();
103 2         154 $self->write("${publish_dir}/${feed_alias}", $xml_feed_content);
104 2         11 $self->write("${publish_dir}/${feed_alias}.xml", $xml_feed_content);
105 2         12 $self->write("${publish_dir}/${feed_alias}.json", $json_feed_content);
106              
107             # Handle any other paths that aren't derived directly from files:
108 2         6 my @meta_paths = qw(all);
109              
110 2         6 my $rendered_count = 0;
111 2         4 my $copied_count = 0;
112 2         9 for my $target ($self->{wrt}->{entries}->all(), @meta_paths)
113             {
114             # Skip index files - these are the text content of an entry, not
115             # a sub-entry:
116 88 100       221 next if $target =~ m{/index$};
117              
118             # Lowercase and alphanumeric + underscores + dashes, no dots - an entry:
119 72 100       198 if ($self->{wrt}->{entries}->is_renderable($target)) {
120 52         163 $self->dir_make_logged("$publish_dir/$target");
121              
122 52         125 my $rendered = $self->{wrt}->display($target);
123              
124 52         120 my $target_file = "$publish_dir/$target/index.html";
125 52         542 $self->log("[write] $target_file " . length($rendered));
126 52         221 $self->write($target_file, $rendered);
127 52         61 $rendered_count++;
128 52         114 next;
129             }
130              
131             # A directory - no-op:
132 20 50       432 if (-d "$entry_dir/$target") {
133 0         0 $self->log("[directory] $entry_dir/$target");
134 0         0 next;
135             }
136              
137             # Some other file - a static asset of some kind:
138 20         598 my $dirname = dirname($target);
139 20         86 $self->log("[copy] archives/$target -> $publish_dir/$target");
140 20         116 $self->dir_make_logged("$publish_dir/$dirname");
141 20         70 $self->{io}->file_copy("$entry_dir/$target", "$publish_dir/$target");
142 20         37 $copied_count++;
143             }
144              
145 2         15 $self->log("rendered $rendered_count entries");
146 2         14 $self->log("copied $copied_count static files");
147              
148             # Presumed success:
149 2         16 return 1;
150             }
151              
152              
153             =item dir_make_logged($path)
154              
155             Make a directory path or log an error.
156              
157             =cut
158              
159             sub dir_make_logged {
160 72     72 1 116 my ($self, $path) = @_;
161 72         81 my $path_err;
162 72         147 $self->log("[create] $path");
163 72         265 $self->{io}->dir_make($path);
164             # XXX: surface these somehow
165             # $self->log(Dumper($path_err)) if @{ $path_err };
166             }
167              
168              
169             =item log(@log_items)
170              
171             Call logging callback with passed parameters.
172              
173             =cut
174              
175             sub log {
176 148     148 1 190 my ($self) = shift;
177 148         308 $self->{logger}->(@_);
178             }
179              
180             =back
181              
182             =cut
183              
184             1;