File Coverage

blib/lib/Pod/Weaver/Section/AllowOverride.pm
Criterion Covered Total %
statement 47 48 97.9
branch 14 18 77.7
condition 3 6 50.0
subroutine 8 8 100.0
pod 0 2 0.0
total 72 82 87.8


line stmt bran cond sub pod time code
1             #---------------------------------------------------------------------
2             package Pod::Weaver::Section::AllowOverride;
3             #
4             # Copyright 2012 Christopher J. Madsen
5             #
6             # Author: Christopher J. Madsen <perl@cjmweb.net>
7             # Created: 31 May 2012
8             #
9             # This program is free software; you can redistribute it and/or modify
10             # it under the same terms as Perl itself.
11             #
12             # This program is distributed in the hope that it will be useful,
13             # but WITHOUT ANY WARRANTY; without even the implied warranty of
14             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the
15             # GNU General Public License or the Artistic License for more details.
16             #
17             # ABSTRACT: Allow POD to override a Pod::Weaver-provided section
18             #---------------------------------------------------------------------
19              
20 2     2   502591 use 5.010;
  2         6  
21 2     2   750 use Moose;
  2         429519  
  2         15  
22             with qw(Pod::Weaver::Role::Transformer Pod::Weaver::Role::Section);
23              
24             our $VERSION = '0.05';
25             # This file is part of Pod-Weaver-Section-AllowOverride 0.05 (May 5, 2014)
26              
27 2     2   13190 use namespace::autoclean;
  2         7831  
  2         17  
28 2     2   118 use Moose::Util::TypeConstraints;
  2         3  
  2         21  
29 2     2   5438 use Pod::Elemental::MakeSelector qw(make_selector);
  2         3747  
  2         15  
30              
31             #=====================================================================
32              
33              
34             has header_re => (
35             is => 'ro',
36             isa => 'Str',
37             lazy => 1,
38             default => sub {'^' . quotemeta(shift->plugin_name) . '$' },
39             );
40              
41              
42             has action => (
43             is => 'ro',
44             isa => enum([ qw(replace prepend append) ]),
45             default => 'replace',
46             );
47              
48              
49             has match_anywhere => (
50             is => 'ro',
51             isa => 'Bool',
52             default => 0,
53             );
54              
55             has _override_with => (
56             is => 'rw',
57             does => 'Pod::Elemental::Node',
58             );
59              
60             #---------------------------------------------------------------------
61             # Return a sub that matches a node against header_re:
62              
63             has _section_matcher => (
64             is => 'ro',
65             isa => 'CodeRef',
66             lazy => 1,
67             builder => '_build_section_matcher',
68             init_arg => undef,
69             );
70              
71             sub _build_section_matcher
72             {
73 10     10   16 my $self = shift;
74              
75 10         422 my $header_re = $self->header_re;
76              
77 10         132 return make_selector(qw(-command head1 -content) => qr/$header_re/);
78             } # end _build_section_matcher
79              
80             #---------------------------------------------------------------------
81             # Look for a matching section in the original POD, and remove it temporarily:
82              
83             sub transform_document
84             {
85 10     10 0 49026 my ($self, $document) = @_;
86              
87 10         434 my $match = $self->_section_matcher;
88 10         295 my $children = $document->children;
89              
90 10         68 for my $i (0 .. $#$children) {
91 9 50       198 if ($match->( $children->[$i] )) {
92             # Found matching section. Store & remove it:
93 9         1827 $self->_override_with( splice @$children, $i, 1 );
94 9         34 last;
95             } # end if this is the section we're looking for
96             } # end for $i indexing @$children
97             } # end transform_document
98              
99             #---------------------------------------------------------------------
100             # If we found a section in the original POD,
101             # use it instead of the one now in the document:
102              
103             sub weave_section
104             {
105 10     10 0 26468 my ($self, $document, $input) = @_;
106              
107 10         404 my $override = $self->_override_with;
108 10 100       30 return unless $override;
109              
110 9         406 my $section_matcher = $self->_section_matcher;
111 9         255 my $children = $document->children;
112 9         47 my $prev;
113              
114 9 100       371 if ($self->match_anywhere) {
115 6         12 my $pos = @$children;
116 6         11 while (1) {
117 9 50       468 $self->log_fatal(["No section matching /%s/", $self->header_re])
118             unless $pos--;
119 9 100       190 last if $section_matcher->( $children->[$pos] );
120             }
121 6         936 $prev = splice @$children, $pos, 1, $override;
122             } else {
123 3 50 33     73 if (@$children and $section_matcher->( $children->[-1] )) {
124 3         474 $prev = pop @$children;
125             } else {
126 0         0 $self->log(["The previous section did not match /%s/, won't override it",
127             $self->header_re]);
128             }
129              
130 3         8 push @$children, $override;
131             } # end else must override immediately preceding section
132              
133 9         371 for my $action ($self->action) {
134 9 100 66     142 last if $action eq 'replace' or not $prev; # nothing more to do
135              
136 6         181 my $prev_content = $prev->children;
137              
138 6 100       43 if ( $action eq 'prepend') {
    50          
139 3         5 push @{ $override->children }, @$prev_content
  3         90  
140             } elsif ($action eq 'append') {
141 3         4 unshift @{ $override->children }, @$prev_content
  3         88  
142             }
143             } # end for $self->action
144             } # end weave_section
145              
146             #=====================================================================
147             # Package Return Value:
148              
149             __PACKAGE__->meta->make_immutable;
150             1;
151              
152             __END__
153              
154             =pod
155              
156             =head1 NAME
157              
158             Pod::Weaver::Section::AllowOverride - Allow POD to override a Pod::Weaver-provided section
159              
160             =head1 VERSION
161              
162             This document describes version 0.05 of
163             Pod::Weaver::Section::AllowOverride, released May 5, 2014.
164              
165             =head1 SYNOPSIS
166              
167             [Authors]
168             [AllowOverride]
169             header_re = ^AUTHORS?$
170             action = replace ; this is the default
171             match_anywhere = 0 ; this is the default
172              
173             =head1 DESCRIPTION
174              
175             Sometimes, you might want to override a normally-generic section in
176             one of your modules. This section plugin replaces the preceding
177             section with the corresponding section taken from your POD (if it
178             exists). If your POD doesn't contain a matching section, then the
179             Pod::Weaver-provided one will be used.
180              
181             Both the original section in your POD and the section provided by
182             Pod::Weaver must match the C<header_re>. Also, this plugin must
183             immediately follow the section you want to replace (unless you set
184             C<match_anywhere> to a true value).
185              
186             It's a similar idea to L<Pod::Weaver::Role::SectionReplacer>, except
187             that it works the other way around. SectionReplacer replaces the
188             section from your POD with a section provided by Pod::Weaver.
189              
190             =head1 ATTRIBUTES
191              
192             =head2 header_re
193              
194             This regular expression is used to select the section you want to
195             override. It's matched against the section name from the C<=head1>
196             line. The default is an exact match with the name of this plugin.
197             (e.g. if the plugin name is AUTHOR, the default would be C<^AUTHOR$>)
198              
199             =head2 action
200              
201             This controls what to do when both a Pod::Weaver-provided section and
202             a POD-provided section are found. It must be one of the following values:
203              
204             =over 4
205              
206             =item replace
207              
208             Replace the Pod::Weaver-provided section with the POD-provided one.
209             (This is the default.)
210              
211             =item prepend
212              
213             Place the POD-provided section at the beginning of the
214             Pod::Weaver-provided one. The POD-provided header is used, and the
215             Pod::Weaver-provided header is discarded.
216              
217             =item append
218              
219             Place the POD-provided section at the end of the
220             Pod::Weaver-provided one. The POD-provided header is used, and the
221             Pod::Weaver-provided header is discarded.
222              
223             =back
224              
225             =head2 match_anywhere
226              
227             By default, AllowOverride must immediately follow the section to be
228             overriden in your F<weaver.ini>. If you set C<match_anywhere> to a
229             true value, then it can come anywhere after the section to be
230             overriden (i.e. there can be other sections in between).
231             AllowOverride will search backwards for a section matching
232             C<header_re>, and die if there is no such section.
233              
234             This is useful if the section you want to override comes from a bundle.
235              
236             =head1 SEE ALSO
237              
238             L<Pod::Weaver::Role::SectionReplacer>,
239             L<Pod::Weaver::PluginBundle::ReplaceBoilerplate>
240              
241             =for Pod::Coverage transform_document
242             weave_section
243              
244             =head1 BUGS
245              
246             Please report any bugs or feature requests to bug-pod-weaver-section-allowoverride@rt.cpan.org or through the web interface at:
247             http://rt.cpan.org/Public/Dist/Display.html?Name=Pod-Weaver-Section-AllowOverride
248              
249             =head1 AUTHOR
250              
251             Christopher J. Madsen <perl@cjmweb.net>
252              
253             =head1 SOURCE
254              
255             The development version is on github at L<http://github.com/madsen/pod-weaver-section-allowoverride>
256             and may be cloned from L<git://github.com/madsen/pod-weaver-section-allowoverride.git>
257              
258             =head1 COPYRIGHT AND LICENSE
259              
260             This software is copyright (c) 2014 by Christopher J. Madsen.
261              
262             This is free software; you can redistribute it and/or modify it under
263             the same terms as the Perl 5 programming language system itself.
264              
265             =cut