File Coverage

blib/lib/App/sdview/Output/Pod.pm
Criterion Covered Total %
statement 105 115 91.3
branch 23 26 88.4
condition n/a
subroutine 16 18 88.8
pod 0 9 0.0
total 144 168 85.7


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2021-2023 -- leonerd@leonerd.org.uk
5              
6 2     2   908 use v5.26;
  2         7  
7 2     2   13 use warnings;
  2         4  
  2         66  
8              
9 2     2   10 use Object::Pad 0.800;
  2         17  
  2         88  
10              
11             package App::sdview::Output::Pod 0.12;
12             class App::sdview::Output::Pod
13             :does(App::sdview::Output)
14 2     2   1202 :strict(params);
  2         4  
  2         102  
15              
16 2     2   322 use constant format => "POD";
  2         5  
  2         5403  
17              
18             =head1 NAME
19              
20             C - generate POD output from L
21              
22             =head1 SYNOPSIS
23              
24             $ sdview README.md -o POD > README.pod
25              
26             =head1 DESCRIPTION
27              
28             This output module adds to L the ability to output text in POD
29             formatting. Given a POD file as input, the output should be relatively
30             similar, up to minor details like whitespacing. Given input in some other
31             format, it will do a reasonable job attempting to represent most of the
32             structure and formatting.
33              
34             =cut
35              
36             field $_printed_pod;
37              
38 2     2 0 5 method output_head1 ( $para ) { $self->_output_head( "=head1", $para ); }
  2         4  
  2         3  
  2         4  
  2         7  
39 1     1 0 2 method output_head2 ( $para ) { $self->_output_head( "=head2", $para ); }
  1         3  
  1         2  
  1         3  
  1         45  
40 0     0 0 0 method output_head3 ( $para ) { $self->_output_head( "=head3", $para ); }
  0         0  
  0         0  
  0         0  
  0         0  
41 0     0 0 0 method output_head4 ( $para ) { $self->_output_head( "=head4", $para ); }
  0         0  
  0         0  
  0         0  
  0         0  
42              
43 3         5 method _output_head ( $leader, $para )
  3         5  
  3         5  
  3         13  
44 3     3   9 {
45 3         12 $self->maybe_blank;
46              
47 3         10 $self->say( $leader, " ", $self->_convert_str( $para->text ) );
48 3         12 $_printed_pod = 1;
49             }
50              
51 5         7 method output_plain ( $para )
  5         6  
  5         9  
52 5     5 0 11 {
53 5 100       14 $self->say( "=pod" ), $_printed_pod = 1 unless $_printed_pod;
54 5         14 $self->maybe_blank;
55              
56 5         14 $self->say( $self->_convert_str( $para->text ) );
57             }
58              
59 1         3 method output_verbatim ( $para )
  1         2  
  1         1  
60 1     1 0 3 {
61 1 50       4 $self->say( "=pod" ), $_printed_pod = 1 unless $_printed_pod;
62 1         4 $self->maybe_blank;
63              
64 1         3 $self->say( " ", $_ ) for split m/\n/, $para->text;
65             }
66              
67 1     1 0 4 method output_list_bullet ( $para ) { $self->_output_list( $para ); }
  1         2  
  1         2  
  1         2  
  1         5  
68 1     1 0 3 method output_list_number ( $para ) { $self->_output_list( $para ); }
  1         3  
  1         2  
  1         2  
  1         3  
69 1     1 0 3 method output_list_text ( $para ) { $self->_output_list( $para ); }
  1         2  
  1         2  
  1         2  
  1         4  
70              
71 3         4 method _output_list ( $para )
  3         5  
  3         4  
72 3     3   6 {
73 3         8 $self->maybe_blank;
74              
75 3         10 $self->say( "=over ", $para->indent );
76 3         9 $self->say;
77              
78 3         10 my @items = $para->items;
79 3         12 foreach my $idx ( 0 .. $#items ) {
80 10         17 my $item = $items[$idx];
81              
82 10 100       25 if( $item->type ne "item" ) {
    100          
    100          
    50          
83             # Non-item has no leader
84             }
85             elsif( $para->listtype eq "bullet" ) {
86 3         10 $self->say( "=item *" );
87 3         7 $self->say;
88             }
89             elsif( $para->listtype eq "number" ) {
90 3         19 $self->say( sprintf "=item %d.", $idx + 1 );
91 3         8 $self->say;
92             }
93             elsif( $para->listtype eq "text" ) {
94 3         10 $self->say( sprintf "=item %s", $self->_convert_str( $item->term ) );
95 3         9 $self->say;
96             }
97              
98 10         28 $self->say( $self->_convert_str( $item->text ) );
99 10         25 $self->say;
100             }
101              
102 3         8 $self->say( "=back" );
103             }
104              
105 21         32 method _convert_str ( $s )
  21         29  
  21         28  
106 21     21   40 {
107 21         35 my $ret = "";
108              
109             # TODO: This sucks for nested tags
110 27         39 $s->iter_substr_nooverlap(
111 27     27   40 sub ( $substr, %tags ) {
  27         1542  
  27         36  
112             # Escape any literal '<'s that would otherwise break
113 27         59 my $pod = $substr =~ s/[A-Z]\K/gr;
114              
115 27         34 my $count = 1;
116 27         93 $count++ while index( $pod, ">"x$count ) > -1;
117              
118 27 100       80 my ( $open, $close ) =
119             ( $count == 1 ) ? ( "<", ">" ) : ( "<"x$count . " ", " " . ">"x$count );
120              
121 27 100       63 if( my $link = $tags{L} ) {
122             # TODO: This is even suckier than the bit in the parser
123 2 100       7 if( $link->{target} eq "https://metacpan.org/pod/$substr" ) {
124 1         3 $pod = "L$open$substr$close";
125             }
126             else {
127 1         20 $pod = "L$open$pod|$link->{target}$close";
128             }
129             }
130              
131 27 100       66 $pod = "C$open$pod$close" if $tags{C};
132 27 100       53 $pod = "B$open$pod$close" if $tags{B};
133 27 100       45 $pod = "I$open$pod$close" if $tags{I};
134 27 50       50 $pod = "F$open$pod$close" if $tags{F};
135              
136 27         78 $ret .= $pod;
137             }
138 21         130 );
139              
140 21         370 return $ret;
141             }
142              
143             =head1 TODO
144              
145             =over 4
146              
147             =item *
148              
149             Some handling of tables. POD does not (currently?) support tables, but at
150             least we could emit some kind of plain-text rendering of the contents.
151              
152             =back
153              
154             =cut
155              
156             =head1 AUTHOR
157              
158             Paul Evans
159              
160             =cut
161              
162             0x55AA;