File Coverage

blib/lib/Pod/Elemental/Transformer/Stenciller.pm
Criterion Covered Total %
statement 139 141 98.5
branch 21 40 52.5
condition 1 5 20.0
subroutine 16 16 100.0
pod n/a
total 177 202 87.6


line stmt bran cond sub pod time code
1 1     1   962850 use Stenciller::Standard;
  2         384999  
  2         146  
2 1     1   9307 use strict;
  1         2  
  1         26  
3 1     1   4 use warnings;
  1         4  
  1         48  
4              
5             our $VERSION = '0.0101'; # VERSION:
6             # PODNAME: Pod::Elemental::Transformer::Stenciller
7             # ABSTRACT: Injects content from textfiles transformed with Stenciller
8 1     1   504 use Stenciller;
  1         1018891  
  1         65  
9              
10 1     1   10807 class Pod::Elemental::Transformer::Stenciller
  1     1   28  
  1     1   8  
  1         2  
  1         64  
  1         5  
  1         2  
  1         9  
  1         298  
  1         2  
  1         7  
  1         54  
  1         1  
  1         66  
  1         4  
  1         1  
  1         86  
  1         31  
  1         4  
  1         1  
  1         11  
  1         3729  
  1         3  
  1         10  
  1         5894  
  1         1  
  1         11  
  1         3266  
  1         2  
  1         10  
  1         73  
  1         1  
  1         15  
  1         201  
  1         2  
  1         7  
  1         1003  
  1         2  
  1         8  
  1         4559  
  1         9  
  1         59  
  1         6  
  1         1  
  1         52  
  1         5  
  1         1  
  1         46  
  1         3  
  1         1  
  1         144  
  1         8  
  1         3714  
  1         17  
  1         128  
  1         5249  
11             using Moose
12             with Pod::Elemental::Transformer, Stenciller::Utils :ro {
13              
14 1     1   10812 use Carp 'croak';
  1         2  
  1         42  
15 1     1   647 use Module::Loader;
  1         12143  
  1         234  
16              
17 1         15 has directory => (
18             is => 'ro',
19             isa => Dir,
20             coerce => 1,
21             required => 1,
22             documentation => 'Path to directory where the stencil files are.'
23             );
24             has settings => (
25             isa => HashRef,
26             traits => ['Hash'],
27 0         0 default => sub { {} },
28 1         5777 handles => {
29             get_setting => 'get',
30             set_setting => 'set',
31             all_settings => 'elements',
32             },
33             documentation_default => '{ }',
34             documentation_order => 0,
35             documentation => 'If a plugin takes more attributes..',
36             );
37             has plugins => (
38             isa => HashRef,
39 1         33 default => sub { {} },
40 1         28126 documentation_default => '{ }',
41             documentation_order => 0,
42             init_arg => undef,
43             traits => ['Hash'],
44             handles => {
45             get_plugin => 'get',
46             set_plugin => 'set',
47             },
48             documentation_order => 0,
49             );
50 1         9144 has stencillers => (
51             is => 'ro',
52             isa => HashRef,
53             traits => ['Hash'],
54             init_arg => undef,
55             handles => {
56             get_stenciller_for_filename => 'get',
57             set_stenciller_for_filename => 'set',
58             },
59             documentation_order => 0,
60             );
61             has loader => (
62             is => 'ro',
63             isa => Object,
64             init_arg => undef,
65 1         9 default => sub { Module::Loader->new },
66 1         8429 documentation_order => 0,
67             );
68 1 50   1   2464 around BUILDARGS($next: $class, @args) {
  1 50   1   2  
  1 50       191  
  1 50       3575  
  1         3  
  1         3  
  1         8  
  1         2  
  1         4  
  1         8  
69 1 50       6492 my $args = ref $args[0] eq 'HASH' ? $args[0] : { @args };
70              
71 1         6 $class->$next(
72             directory => delete $args->{'directory'},
73             settings => $args
74             );
75             }
76              
77 1 50   1   1551 method transform_node($main_node) {
  1 50   1   1  
  1 50       546  
  1         11  
  1         4  
  1         3  
  1         2  
  1         40  
78              
79 4         26 NODE:
80 4         121 foreach my $node (@{ $main_node->children }) {
81 4         11 my $content = $node->content;
82 1         5 my $start = substr($content, 0, 11, '');
83 1 100       10 next NODE if $start ne ':stenciller';
84              
85 1         2 $content =~ s{^\h+}{}; # remove leading whitespace
86 1 50       4 next if $content !~ m{([^\h\v]+)}; # the next sequence of non-space is the wanted plugin name
87              
88 1         8 my $wanted_plugin = $1;
89 1         4 my $plugin_name = $self->ensure_plugin($wanted_plugin);
90              
91 1         34 (undef, my($filename, $possible_hash)) = split /\h+/ => $content, 3;
92 1         221 chomp $filename;
93 1 50 33     17 my $node_settings = defined $possible_hash && $possible_hash =~ m{\{.*\}} ? $self->eval_to_hashref($possible_hash, $filename) : {};
94              
95 1         49 my $stenciller = $self->get_stenciller_for_filename($filename);
96              
97 1 50       12448 if(!Stenciller->check($stenciller)) {
98 1         94 $stenciller = Stenciller::->new(filepath => path($self->directory)->child($filename));
99 1 50 0     57 carp sprintf '! no stencils in %s/%s - skipping', $self->directory, $filename and return '' if !$stenciller->has_stencils;
100              
101 1         2251 $self->set_stenciller_for_filename($filename => $stenciller);
102             }
103              
104 1         178 my $transformed_content = $stenciller->transform(plugin_name => $plugin_name,
105             constructor_args => $self->settings,
106             transform_args => { %$node_settings, require_in_extra => { key => 'to_pod', value => 1, default => 1 } },
107             );
108 1         4 $transformed_content =~ s{[\v\h]+$}{};
109 1         3 $node->content($transformed_content);
110              
111             }
112             }
113 1 50   1   1902 method ensure_plugin(Str $plugin_name) {
  1 50   1   2  
  1 50   1   138  
  1 50       4  
  1 50       1  
  1         173  
  1         5  
  1         3  
  1         4  
  1         1  
  1         12  
  1         1  
  1         38  
  1         19  
114 1 50       28 return $self->get_plugin($plugin_name) if $self->get_plugin($plugin_name);
115              
116 1         57252 my $plugin_class = sprintf 'Stenciller::Plugin::%s', $plugin_name;
117 0         0 $self->loader->load($plugin_class);
118              
119 1 50       213 if(!$plugin_class->does('Stenciller::Transformer')) {
120 1         30 croak("[$plugin_name] doesn't do the Stenciller::Transformer role. Quitting.");
121             }
122             $self->set_plugin($plugin_name => $plugin_name);
123             return $plugin_name;
124             }
125             }
126              
127             1;
128              
129             __END__
130              
131             =pod
132              
133             =encoding UTF-8
134              
135             =head1 NAME
136              
137             Pod::Elemental::Transformer::Stenciller - Injects content from textfiles transformed with Stenciller
138              
139             =head1 VERSION
140              
141             Version 0.0101, released 2015-02-13.
142              
143              
144              
145             =head1 SYNOPSIS
146              
147             # in weaver.ini
148             [-Transformer / Stenciller]
149             transformer = Stenciller
150             directory = path/to/stencildir
151              
152             =head1 DESCRIPTION
153              
154             This transformer uses a special command in pod files to inject content from elsewhere via a L<Stenciller> transformer plugin.
155              
156             =head2 Example
157              
158             1. Start with the C<weaver.ini> from the L</"synopsis">.
159              
160             2. Add a textfile, in C<path/to/stencildir/file-with-stencils.stencil>:
161              
162             == stencil { } ==
163              
164             Header text
165              
166             --input--
167              
168             Input text
169              
170             --end input--
171              
172             Between text
173              
174             --output--
175              
176             Output text
177              
178             --end output--
179              
180             Footer text
181              
182             3. Add a Perl module:
183              
184             package A::Test::Module;
185              
186             1;
187              
188             __END__
189              
190             =pod
191              
192             =head1 NAME
193              
194             =head1 DESCRIPTION
195              
196             :stenciller ToUnparsedText file-with-stencils.stencil
197              
198             The last line in the Perl module will cause the textfile to be parsed with L<Stenciller>, and then transformed using the L<Stenciller::Plugin::ToUnparsedText> plugin.
199              
200             It would be rendered like this (between I<begin> and I<end>):
201              
202             I<begin>
203              
204             Header text
205              
206             Input text
207              
208             Between text
209              
210             Output text
211              
212             Footer text
213              
214             I<end>
215              
216             =head2 Pod hash
217              
218             It is possible to filter stencils by index with an optional hash in the module:
219              
220             :stenciller ToUnparsedText 1-test.stencil { stencils => [0, 2..4] }
221              
222             This will only include the stencils with index 0, 2, 3 and 4 from C<1-test.stencil>.
223              
224             =head2 Stencil hash
225              
226             This module checks for the C<to_pod> key in the stencil hash. If it is true (or doesn't exist) it is included in the transformation.
227              
228             However, any stencil excluded by the L</"Pod hash"> is already disregarded. It is probably least confusing to choose one of these places to do all filtering.
229              
230             =head1 ATTRIBUTES
231              
232              
233             =head2 directory
234              
235             =begin HTML
236              
237             <table cellpadding="0" cellspacing="0">
238             <tr><td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;"><a href="https://metacpan.org/pod/Types::Path::Tiny#Dir">Dir</a>
239              
240             </td>
241             <td style="padding-right: 6px; padding-left: 6px; border-right: 1px solid #b8b8b8; white-space: nowrap;">required</td>
242             <td style="padding-left: 6px; padding-right: 6px; white-space: nowrap;">read-only</td></tr>
243             </table>
244              
245             <p>Path to directory where the stencil files are.</p>
246              
247             =end HTML
248              
249             =head1 SEE ALSO
250              
251             =over 4
252              
253             =item *
254              
255             L<Stenciller>
256              
257             =item *
258              
259             L<Stenciller::Plugin::ToUnparsedText>
260              
261             =item *
262              
263             L<Pod::Weaver>
264              
265             =back
266              
267             =head1 SOURCE
268              
269             L<https://github.com/Csson/p5-Pod-Elemental-Transformer-Stenciller>
270              
271             =head1 HOMEPAGE
272              
273             L<https://metacpan.org/release/Pod-Elemental-Transformer-Stenciller>
274              
275             =head1 AUTHOR
276              
277             Erik Carlsson <info@code301.com>
278              
279             =head1 COPYRIGHT AND LICENSE
280              
281             This software is copyright (c) 2015 by Erik Carlsson <info@code301.com>.
282              
283             This is free software; you can redistribute it and/or modify it under
284             the same terms as the Perl 5 programming language system itself.
285              
286             =cut