File Coverage

blib/lib/Pod/Abstract/Filter/overlay.pm
Criterion Covered Total %
statement 15 60 25.0
branch 0 12 0.0
condition n/a
subroutine 5 6 83.3
pod 1 1 100.0
total 21 79 26.5


line stmt bran cond sub pod time code
1             package Pod::Abstract::Filter::overlay;
2 1     1   1238 use strict;
  1         3  
  1         46  
3 1     1   6 use warnings;
  1         2  
  1         60  
4              
5 1     1   7 use base qw(Pod::Abstract::Filter);
  1         2  
  1         123  
6 1     1   7 use Pod::Abstract;
  1         2  
  1         34  
7 1     1   5 use Pod::Abstract::BuildNode qw(node);
  1         2  
  1         890  
8              
9             our $VERSION = '0.26';
10              
11             =head1 NAME
12              
13             Pod::Abstract::Filter::overlay - Perform a method documentation overlay
14             on a Pod document.
15              
16             =head1 USAGE
17              
18             Use the C command to run this filter inline - for example:
19              
20             $ paf -p overlay sort summary Pod::Abstract::Filter::overlay
21              
22             Produces
23              
24             NAME
25             METHODS
26             \ =begin :overlay =overlay METHODS Some::Class::Or::File =end :overlay
27             filter
28             new
29             param
30             require_params
31             run
32             AUTHOR
33             COPYRIGHT AND LICENSE
34              
35             =begin :overlay
36              
37             =overlay METHODS Pod::Abstract::Filter
38              
39             =end :overlay
40              
41             =head1 METHODS
42              
43             =head2 filter
44              
45             Inspects the source document for a begin/end block named
46             ":overlay". The overlay block will be inspected for "=overlay"
47             commands, which should be structured like:
48              
49             =begin :overlay
50            
51             =overlay METHODS Some::Class::Or::File
52            
53             =end :overlay
54              
55             Each overlay is processed in order. It will add any headings for the
56             matched sections in the current document from the named source, for
57             any heading that is not already present in the given section.
58              
59             The main utility of this is to specify a superclass, so that all the
60             methods that are not documented in your subclass become documented by
61             the overlay. The C filter makes a good follow up.
62              
63             The start of overlaid sections will include:
64              
65             =for overlay from
66              
67             You can use these markers to set sections to be replaced by some other
68             document, or to repeat an overlay on an already processed Pod
69             file. Changes to existing marked sections are made in-place without
70             changing document order.
71              
72             =cut
73              
74             sub filter {
75 0     0 1   my $self = shift;
76 0           my $pa = shift;
77            
78 0           my ($overlay_list) = $pa->select("//begin[. =~ {^:overlay}](0)");
79 0 0         unless($overlay_list) {
80 0           die "No overlay defined in document\n";
81             }
82 0           my @overlays = $overlay_list->select("/overlay");
83 0           foreach my $overlay (@overlays) {
84 0           my $o_def = $overlay->body;
85 0           my ($section, $module) = split " ", $o_def;
86              
87             # This should be factored into a method.
88 0           my $ovr_module = $module; # Keep original value
89 0 0         unless(-r $module) {
90             # Maybe a module name?
91 0           $module =~ s/::/\//g;
92 0 0         $module .= '.pm' unless $module =~ m/.pm$/;
93 0           foreach my $path (@INC) {
94 0 0         if(-r "$path/$module") {
95 0           $module = "$path/$module";
96 0           last;
97             }
98             }
99             }
100 0           my $ovr_doc = Pod::Abstract->load_file($module);
101            
102 0           my ($t) = $pa->select("//[\@heading =~ {$section}](0)");
103 0           my ($o) = $ovr_doc->select("//[\@heading =~ {$section}](0)");
104              
105 0           my @t_headings = $t->select("/[\@heading]");
106 0           my @o_headings = $o->select("/[\@heading]");
107            
108             my %t_heading = map {
109 0           $_->param('heading')->pod => $_
  0            
110             } @t_headings;
111            
112 0           foreach my $hdg (@o_headings) {
113 0           my $hdg_text = $hdg->param('heading')->pod;
114 0 0         if($t_heading{$hdg_text}) {
115             my @overlay_from =
116 0           $t_heading{$hdg_text}->select(
117             "/for[. =~ {^overlay from }]");
118             my @from_current = grep {
119 0           substr($_->body, -(length $ovr_module)) eq $ovr_module
  0            
120             } @overlay_from;
121            
122 0 0         if(@from_current) {
123 0           my $dup = $hdg->duplicate;
124 0           my @overlay_from =
125             $hdg->select("/for[. =~ {^overlay from }]");
126 0           $_->detach foreach @overlay_from;
127            
128 0           $dup->unshift(node->for("overlay from $ovr_module"));
129            
130 0           $dup->insert_after($t_heading{$hdg_text});
131 0           $t_heading{$hdg_text}->detach;
132 0           $t_heading{$hdg_text} = $dup;
133             }
134             } else {
135 0           my $dup = $hdg->duplicate;
136            
137             # Remove existing overlay markers;
138 0           my @overlay_from =
139             $hdg->select("/for[. =~ {^overlay from }]");
140 0           $_->detach foreach @overlay_from;
141              
142 0           $dup->unshift(node->for("overlay from $ovr_module"));
143              
144 0           $t->push($dup);
145 0           $t_heading{$hdg_text} = $dup;
146             }
147             }
148             }
149 0           return $pa;
150             }
151              
152             =head1 AUTHOR
153              
154             Ben Lilburne
155              
156             =head1 COPYRIGHT AND LICENSE
157              
158             Copyright (C) 2009-2025 Ben Lilburne
159              
160             This program is free software; you can redistribute it and/or modify
161             it under the same terms as Perl itself.
162              
163             =cut
164              
165             1;