File Coverage

blib/lib/App/sdview/Output/Pod.pm
Criterion Covered Total %
statement 106 116 91.3
branch 26 28 92.8
condition n/a
subroutine 16 18 88.8
pod 0 9 0.0
total 148 171 86.5


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   984 use v5.26;
  2         8  
7 2     2   12 use warnings;
  2         4  
  2         72  
8              
9 2     2   13 use Object::Pad 0.800;
  2         14  
  2         106  
10              
11             package App::sdview::Output::Pod 0.13;
12             class App::sdview::Output::Pod
13             :does(App::sdview::Output)
14 2     2   1143 :strict(params);
  2         4  
  2         101  
15              
16 2     2   323 use constant format => "POD";
  2         4  
  2         5173  
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             As an extension it will output underline formatting using the C...E>
35             code, which is recognised by L.
36              
37             =cut
38              
39             field $_printed_pod;
40              
41 2     2 0 5 method output_head1 ( $para ) { $self->_output_head( "=head1", $para ); }
  2         3  
  2         4  
  2         3  
  2         7  
42 1     1 0 5 method output_head2 ( $para ) { $self->_output_head( "=head2", $para ); }
  1         4  
  1         2  
  1         2  
  1         4  
43 0     0 0 0 method output_head3 ( $para ) { $self->_output_head( "=head3", $para ); }
  0         0  
  0         0  
  0         0  
  0         0  
44 0     0 0 0 method output_head4 ( $para ) { $self->_output_head( "=head4", $para ); }
  0         0  
  0         0  
  0         0  
  0         0  
45              
46 3         5 method _output_head ( $leader, $para )
  3         4  
  3         6  
  3         4  
47 3     3   5 {
48 3         11 $self->maybe_blank;
49              
50 3         10 $self->say( $leader, " ", $self->_convert_str( $para->text ) );
51 3         14 $_printed_pod = 1;
52             }
53              
54 7         10 method output_plain ( $para )
  7         12  
  7         8  
55 7     7 0 14 {
56 7 100       18 $self->say( "=pod" ), $_printed_pod = 1 unless $_printed_pod;
57 7         17 $self->maybe_blank;
58              
59 7         18 $self->say( $self->_convert_str( $para->text ) );
60             }
61              
62 1         2 method output_verbatim ( $para )
  1         3  
  1         1  
63 1     1 0 3 {
64 1 50       5 $self->say( "=pod" ), $_printed_pod = 1 unless $_printed_pod;
65 1         4 $self->maybe_blank;
66              
67 1         3 $self->say( " ", $_ ) for split m/\n/, $para->text;
68             }
69              
70 1     1 0 4 method output_list_bullet ( $para ) { $self->_output_list( $para ); }
  1         3  
  1         1  
  1         2  
  1         4  
71 1     1 0 2 method output_list_number ( $para ) { $self->_output_list( $para ); }
  1         3  
  1         4  
  1         2  
  1         4  
72 1     1 0 3 method output_list_text ( $para ) { $self->_output_list( $para ); }
  1         3  
  1         1  
  1         2  
  1         4  
73              
74 3         4 method _output_list ( $para )
  3         6  
  3         5  
75 3     3   7 {
76 3         32 $self->maybe_blank;
77              
78 3         16 $self->say( "=over ", $para->indent );
79 3         11 $self->say;
80              
81 3         14 my @items = $para->items;
82 3         12 foreach my $idx ( 0 .. $#items ) {
83 10         18 my $item = $items[$idx];
84              
85 10 100       28 if( $item->type ne "item" ) {
    100          
    100          
    50          
86             # Non-item has no leader
87             }
88             elsif( $para->listtype eq "bullet" ) {
89 3         8 $self->say( "=item *" );
90 3         9 $self->say;
91             }
92             elsif( $para->listtype eq "number" ) {
93 3         21 $self->say( sprintf "=item %d.", $idx + 1 );
94 3         10 $self->say;
95             }
96             elsif( $para->listtype eq "text" ) {
97 3         9 $self->say( sprintf "=item %s", $self->_convert_str( $item->term ) );
98 3         9 $self->say;
99             }
100              
101 10         28 $self->say( $self->_convert_str( $item->text ) );
102 10         26 $self->say;
103             }
104              
105 3         17 $self->say( "=back" );
106             }
107              
108 23         32 method _convert_str ( $s )
  23         31  
  23         28  
109 23     23   38 {
110 23         36 my $ret = "";
111              
112             # TODO: This sucks for nested tags
113 29         44 $s->iter_substr_nooverlap(
114 29     29   36 sub ( $substr, %tags ) {
  29         1712  
  29         42  
115             # Escape any literal '<'s that would otherwise break
116 29         67 my $pod = $substr =~ s/[A-Z]\K/gr;
117              
118 29         38 my $count = 1;
119 29         99 $count++ while index( $pod, ">"x$count ) > -1;
120              
121 29 100       77 my ( $open, $close ) =
122             ( $count == 1 ) ? ( "<", ">" ) : ( "<"x$count . " ", " " . ">"x$count );
123              
124 29 100       61 if( my $link = $tags{link} ) {
125             # TODO: This is even suckier than the bit in the parser
126 2 100       9 if( $link->{target} eq "https://metacpan.org/pod/$substr" ) {
127 1         3 $pod = "L$open$substr$close";
128             }
129             else {
130 1         20 $pod = "L$open$pod|$link->{target}$close";
131             }
132             }
133              
134 29 100       66 $pod = "C$open$pod$close" if $tags{monospace};
135 29 100       51 $pod = "B$open$pod$close" if $tags{bold};
136 29 100       49 $pod = "I$open$pod$close" if $tags{italic};
137 29 100       93 $pod = "F$open$pod$close" if $tags{file};
138 29 100       56 $pod = "U$open$pod$close" if $tags{underline};
139              
140 29         89 $ret .= $pod;
141             }
142 23         154 );
143              
144 23         415 return $ret;
145             }
146              
147             =head1 TODO
148              
149             =over 4
150              
151             =item *
152              
153             Some handling of tables. POD does not (currently?) support tables, but at
154             least we could emit some kind of plain-text rendering of the contents.
155              
156             =back
157              
158             =cut
159              
160             =head1 AUTHOR
161              
162             Paul Evans
163              
164             =cut
165              
166             0x55AA;