File Coverage

blib/lib/Pod/L10N/Html/Util.pm
Criterion Covered Total %
statement 87 100 87.0
branch 21 34 61.7
condition 3 8 37.5
subroutine 16 17 94.1
pod 8 8 100.0
total 135 167 80.8


line stmt bran cond sub pod time code
1             package Pod::L10N::Html::Util;
2 22     22   6501 use strict;
  22         43  
  22         994  
3 22     22   127 use Exporter 'import';
  22         40  
  22         2385  
4              
5             our $VERSION = 1.10; # Please keep in synch with lib/Pod/Html.pm
6             $VERSION = eval $VERSION;
7             our @EXPORT_OK = qw(
8             anchorify
9             html_escape
10             htmlify
11             process_command_line
12             relativize_url
13             trim_leading_whitespace
14             unixify
15             usage
16             );
17              
18 22     22   139 use Config;
  22         40  
  22         1003  
19 22     22   111 use File::Spec;
  22         40  
  22         651  
20 22     22   114 use File::Spec::Unix;
  22         36  
  22         773  
21 22     22   18186 use Getopt::Long;
  22         351039  
  22         265  
22 22     22   20322 use Pod::Simple::XHTML;
  22         421264  
  22         3303  
23 22     22   13103 use Text::Tabs;
  22         21368  
  22         3531  
24 22     22   12095 use locale; # make \w work right in non-ASCII lands
  22         19953  
  22         136  
25              
26             =head1 NAME
27              
28             Pod::Html::Util - helper functions for Pod-Html
29              
30             =head1 SUBROUTINES
31              
32             B While these functions are importable on request from
33             F, they are specifically intended for use within (a) the
34             F distribution (modules and test programs) shipped as part of the
35             Perl 5 core and (b) other parts of the core such as the F
36             program. These functions may be modified or relocated within the core
37             distribution -- or removed entirely therefrom -- as the core's needs evolve.
38             Hence, you should not rely on these functions in situations other than those
39             just described.
40              
41             =cut
42              
43             =head2 C
44              
45             Process command-line switches (options). Returns a reference to a hash. Will
46             provide usage message if C<--help> switch is present or if parameters are
47             invalid.
48              
49             Calling this subroutine may modify C<@ARGV>.
50              
51             =cut
52              
53             sub process_command_line {
54 31     31 1 301 my %opts = map { $_ => undef } (qw|
  558         2961  
55             backlink cachedir css flush
56             header help htmldir htmlroot
57             index infile outfile poderrors
58             podpath podroot quiet recurse
59             title verbose
60             |);
61 31 50       4830 unshift @ARGV, split ' ', $Config{pod2html} if $Config{pod2html};
62 31         665 my $result = GetOptions(\%opts,
63             'backlink!',
64             'cachedir=s',
65             'css=s',
66             'flush',
67             'help',
68             'header!',
69             'htmldir=s',
70             'htmlroot=s',
71             'index!',
72             'infile=s',
73             'outfile=s',
74             'poderrors!',
75             'podpath=s',
76             'podroot=s',
77             'quiet!',
78             'recurse!',
79             'title=s',
80             'verbose!',
81             );
82 31 100       111077 usage("-", "invalid parameters") if not $result;
83 30 100       217 usage("-") if defined $opts{help}; # see if the user asked for help
84 29         158 $opts{help} = ""; # just to make -w shut-up.
85 29         247 return \%opts;
86             }
87              
88             =head2 C
89              
90             Display customary Pod::Html usage information on STDERR.
91              
92             =cut
93              
94             sub usage {
95 2     2 1 5 my $podfile = shift;
96 2 100       20 warn "$0: $podfile: @_\n" if @_;
97 2         57 die <
98             Usage: $0 --help --htmldir= --htmlroot=
99             --infile= --outfile=
100             --podpath=:...: --podroot=
101             --cachedir= --flush --recurse --norecurse
102             --quiet --noquiet --verbose --noverbose
103             --index --noindex --backlink --nobacklink
104             --header --noheader --poderrors --nopoderrors
105             --css= --title=
106              
107             --[no]backlink - turn =head1 directives into links pointing to the top of
108             the page (off by default).
109             --cachedir - directory for the directory cache files.
110             --css - stylesheet URL
111             --flush - flushes the directory cache.
112             --[no]header - produce block header/footer (default is no headers).
113             --help - prints this message.
114             --htmldir - directory for resulting HTML files.
115             --htmlroot - http-server base directory from which all relative paths
116             in podpath stem (default is /).
117             --[no]index - generate an index at the top of the resulting html
118             (default behaviour).
119             --infile - filename for the pod to convert (input taken from stdin
120             by default).
121             --outfile - filename for the resulting html file (output sent to
122             stdout by default).
123             --[no]poderrors - include a POD ERRORS section in the output if there were
124             any POD errors in the input (default behavior).
125             --podpath - colon-separated list of directories containing library
126             pods (empty by default).
127             --podroot - filesystem base directory from which all relative paths
128             in podpath stem (default is .).
129             --[no]quiet - suppress some benign warning messages (default is off).
130             --[no]recurse - recurse on those subdirectories listed in podpath
131             (default behaviour).
132             --title - title that will appear in resulting html file.
133             --[no]verbose - self-explanatory (off by default).
134              
135             END_OF_USAGE
136              
137             }
138              
139             =head2 C
140              
141             Ensure that F's internals and tests handle paths consistently
142             across Unix, Windows and VMS.
143              
144             =cut
145              
146             sub unixify {
147 561     561 1 6089687 my $full_path = shift;
148 561 100       2749 return '' unless $full_path;
149 514 100       1805 return $full_path if $full_path eq '/';
150              
151 506         13002 my ($vol, $dirs, $file) = File::Spec->splitpath($full_path);
152 506 50       4759 my @dirs = $dirs eq File::Spec->curdir()
153             ? (File::Spec::Unix->curdir())
154             : File::Spec->splitdir($dirs);
155 506 50 33     2946 if (defined($vol) && $vol) {
156 0 0       0 $vol =~ s/:$// if $^O eq 'VMS';
157 0 0       0 $vol = uc $vol if $^O eq 'MSWin32';
158              
159 0 0       0 if( $dirs[0] ) {
160 0         0 unshift @dirs, $vol;
161             }
162             else {
163 0         0 $dirs[0] = $vol;
164             }
165             }
166 506 100       3168 unshift @dirs, '' if File::Spec->file_name_is_absolute($full_path);
167 506 100       1455 return $file unless scalar(@dirs);
168 483         3992 $full_path = File::Spec::Unix->catfile(File::Spec::Unix->catdir(@dirs),
169             $file);
170 483 50       1965 $full_path =~ s|^\/|| if $^O eq 'MSWin32'; # C:/foo works, /C:/foo doesn't
171 483 50       1306 $full_path =~ s/\^\././g if $^O eq 'VMS'; # unescape dots
172 483         1872 return $full_path;
173             }
174              
175             =head2 C
176              
177             Convert an absolute URL to one relative to a base URL.
178             Assumes both end in a filename.
179              
180             =cut
181              
182             sub relativize_url {
183 26     26 1 1824 my ($dest, $source) = @_;
184              
185             # Remove each file from its path
186 26         320 my ($dest_volume, $dest_directory, $dest_file) =
187             File::Spec::Unix->splitpath( $dest );
188 26         239 $dest = File::Spec::Unix->catpath( $dest_volume, $dest_directory, '' );
189              
190 26         385 my ($source_volume, $source_directory, $source_file) =
191             File::Spec::Unix->splitpath( $source );
192 26         165 $source = File::Spec::Unix->catpath( $source_volume, $source_directory, '' );
193              
194 26         74 my $rel_path = '';
195 26 50       101 if ($dest ne '') {
196 26         2490 $rel_path = File::Spec::Unix->abs2rel( $dest, $source );
197             }
198              
199 26 50 33     216 if ($rel_path ne '' && substr( $rel_path, -1 ) ne '/') {
200 26         65 $rel_path .= "/$dest_file";
201             } else {
202 0         0 $rel_path .= "$dest_file";
203             }
204              
205 26         109 return $rel_path;
206             }
207              
208             =head2 C
209              
210             Make text safe for HTML.
211              
212             =cut
213              
214             sub html_escape {
215 29     29 1 91 my $rest = $_[0];
216 29         148 $rest =~ s/&/&/g;
217 29         174 $rest =~ s/
218 29         107 $rest =~ s/>/>/g;
219 29         72 $rest =~ s/"/"/g;
220 29         121 return $rest;
221             }
222              
223             =head2 C
224              
225             htmlify($heading);
226              
227             Converts a pod section specification to a suitable section specification
228             for HTML. Note that we keep spaces and special characters except
229             C<", ?> (Netscape problem) and the hyphen (writer's problem...).
230              
231             =cut
232              
233             sub htmlify {
234 0     0 1 0 my( $heading) = @_;
235 0         0 $heading =~ s/(\s+)/ /g;
236 0         0 $heading =~ s/\s+\Z//;
237 0         0 $heading =~ s/\A\s+//;
238             # The hyphen is a disgrace to the English language.
239             # $heading =~ s/[-"?]//g;
240 0         0 $heading =~ s/["?]//g;
241 0         0 $heading = lc( $heading );
242 0         0 return $heading;
243             }
244              
245             =head2 C
246              
247             anchorify(@heading);
248              
249             Similar to C, but turns non-alphanumerics into underscores. Note
250             that C is not exported by default.
251              
252             =cut
253              
254             sub anchorify {
255 13     13 1 405536 my ($anchor) = @_;
256 13         31 $anchor =~ s/"/_/g; # Replace double quotes with underscores
257 13         24 $anchor =~ s/_$//; # ... but strip any final underscore
258 13         26 $anchor =~ s/[<>&']//g; # Strip the remaining HTML special characters
259 13         31 $anchor =~ s/^\s+//; s/\s+$//; # Strip white space.
  13         23  
260 13         29 $anchor =~ s/^([^a-zA-Z]+)$/pod$1/; # Prepend "pod" if no valid chars.
261 13         27 $anchor =~ s/^[^a-zA-Z]+//; # First char must be a letter.
262 13         41 $anchor =~ s/[^-a-zA-Z0-9_:.]+/-/g; # All other chars must be valid.
263 13         47 $anchor =~ s/[-:.]+$//; # Strip trailing punctuation.
264 13         50 $anchor =~ s/\W/_/g;
265 13         83 return $anchor;
266             }
267              
268             =head2 C
269              
270             Remove any level of indentation (spaces or tabs) from each code block
271             consistently. Adapted from:
272             https://metacpan.org/source/HAARG/MetaCPAN-Pod-XHTML-0.002001/lib/Pod/Simple/Role/StripVerbatimIndent.pm
273              
274             =cut
275              
276             sub trim_leading_whitespace {
277 8     8 1 49612 my ($para) = @_;
278              
279             # Start by converting tabs to spaces
280 8         95 @$para = Text::Tabs::expand(@$para);
281              
282             # Find the line with the least amount of indent, as that's our "base"
283 8         820 my @indent_levels = (sort(map { $_ =~ /^( *)./mg } @$para));
  24         163  
284 8   50     36 my $indent = $indent_levels[0] || "";
285              
286             # Remove the "base" amount of indent from each line
287 8         24 foreach (@$para) {
288 24         226 $_ =~ s/^\Q$indent//mg;
289             }
290              
291 8         32 return;
292             }
293              
294             1;
295