File Coverage

blib/lib/Perl/Critic/Utils/POD.pm
Criterion Covered Total %
statement 116 134 86.5
branch 36 54 66.6
condition n/a
subroutine 28 36 77.7
pod 19 19 100.0
total 199 243 81.8


line stmt bran cond sub pod time code
1             package Perl::Critic::Utils::POD;
2              
3 40     40   10486 use 5.010001;
  40         167  
4 40     40   223 use strict;
  40         80  
  40         960  
5 40     40   222 use warnings;
  40         165  
  40         1393  
6              
7 40     40   245 use English qw< -no_match_vars >;
  40         104  
  40         323  
8              
9 40     40   37540 use Pod::PlainText ();
  40         264347  
  40         1019  
10 40     40   296 use Pod::Select ();
  40         99  
  40         888  
11              
12             # TODO: non-fatal generic?
13 40     40   616 use Perl::Critic::Exception::Fatal::Generic qw< throw_generic >;
  40         99  
  40         2494  
14 40     40   16101 use Perl::Critic::Exception::IO qw< throw_io >;
  40         127  
  40         750  
15 40     40   2250 use Perl::Critic::Utils qw< :characters >;
  40         112  
  40         1749  
16              
17 40     40   7625 use Exporter 'import';
  40         99  
  40         94251  
18              
19             our $VERSION = '1.150';
20              
21             #-----------------------------------------------------------------------------
22              
23             our @EXPORT_OK = qw(
24             get_pod_file_for_module
25             get_raw_pod_section_from_file
26             get_raw_pod_section_from_filehandle
27             get_raw_pod_section_from_string
28             get_raw_pod_section_for_module
29             get_pod_section_from_file
30             get_pod_section_from_filehandle
31             get_pod_section_from_string
32             get_pod_section_for_module
33             trim_raw_pod_section
34             trim_pod_section
35             get_raw_module_abstract_from_file
36             get_raw_module_abstract_from_filehandle
37             get_raw_module_abstract_from_string
38             get_raw_module_abstract_for_module
39             get_module_abstract_from_file
40             get_module_abstract_from_filehandle
41             get_module_abstract_from_string
42             get_module_abstract_for_module
43             );
44              
45             our %EXPORT_TAGS = (
46             all => \@EXPORT_OK,
47             );
48              
49             #-----------------------------------------------------------------------------
50              
51             sub get_pod_file_for_module {
52 1306     1306 1 2141 my ($module_name) = @_;
53              
54             # No File::Spec: %INC always uses forward slashes.
55 1306         6461 (my $relative_path = $module_name) =~ s< :: ></>xmsg;
56 1306         2722 $relative_path .= '.pm';
57              
58 1306 100       5848 my $absolute_path = $INC{$relative_path} or return;
59              
60 1305         8669 (my $pod_path = $absolute_path) =~ s< [.] [^.]+ \z><.pod>xms;
61 1305 50       21446 return $pod_path if -f $pod_path;
62              
63 1305         5992 return $absolute_path;
64             }
65              
66             #-----------------------------------------------------------------------------
67              
68             sub get_raw_pod_section_from_file {
69 0     0 1 0 my ($file_name, $section_name) = @_;
70              
71 0         0 return _get_pod_section_from_file(
72             $file_name,
73             $section_name,
74             Pod::Select->new(),
75             );
76             }
77              
78             #-----------------------------------------------------------------------------
79              
80             sub get_raw_pod_section_from_filehandle {
81 0     0 1 0 my ($file_handle, $section_name) = @_;
82              
83 0         0 return _get_pod_section_from_filehandle(
84             $file_handle,
85             $section_name,
86             Pod::Select->new(),
87             );
88             }
89              
90             #-----------------------------------------------------------------------------
91              
92             sub get_raw_pod_section_from_string {
93 7     7 1 10263 my ($source, $section_name) = @_;
94              
95 7         93 return _get_pod_section_from_string(
96             $source,
97             $section_name,
98             Pod::Select->new(),
99             );
100             }
101              
102             #-----------------------------------------------------------------------------
103              
104             sub get_raw_pod_section_for_module {
105 0     0 1 0 my ($module_name, $section_name) = @_;
106              
107 0 0       0 my $file_name = get_pod_file_for_module($module_name)
108             or throw_generic qq<Could not find POD for "$module_name".>;
109              
110 0         0 return get_raw_pod_section_from_file($file_name, $section_name);
111             }
112              
113             #-----------------------------------------------------------------------------
114              
115             sub get_pod_section_from_file {
116 2     2 1 6 my ($file_name, $section_name) = @_;
117              
118 2         52 return _get_pod_section_from_file(
119             $file_name,
120             $section_name,
121             Pod::PlainText->new(),
122             );
123             }
124              
125             #-----------------------------------------------------------------------------
126              
127             sub get_pod_section_from_filehandle {
128 0     0 1 0 my ($file_handle, $section_name) = @_;
129              
130 0         0 return _get_pod_section_from_filehandle(
131             $file_handle,
132             $section_name,
133             Pod::PlainText->new(),
134             );
135             }
136              
137             #-----------------------------------------------------------------------------
138              
139             sub get_pod_section_from_string {
140 7     7 1 3832 my ($source, $section_name) = @_;
141              
142 7         94 return _get_pod_section_from_string(
143             $source,
144             $section_name,
145             Pod::PlainText->new(),
146             );
147             }
148              
149             #-----------------------------------------------------------------------------
150              
151             sub get_pod_section_for_module {
152 3     3 1 8 my ($module_name, $section_name) = @_;
153              
154 3 100       9 my $file_name = get_pod_file_for_module($module_name)
155             or throw_generic qq<Could not find POD for "$module_name".>;
156              
157 2         8 return get_pod_section_from_file($file_name, $section_name);
158             }
159              
160             #-----------------------------------------------------------------------------
161              
162             sub _get_pod_section_from_file {
163 2     2   68 my ($file_name, $section_name, $parser) = @_;
164              
165 2 50       128 open my $file_handle, '<', $file_name
166             or throw_io
167             message => qq<Could not open "$file_name": $ERRNO>,
168             file_name => $file_name,
169             errno => $ERRNO;
170              
171 2         11 my $content =
172             _get_pod_section_from_filehandle(
173             $file_handle, $section_name, $parser,
174             );
175              
176 2 50       29 close $file_handle
177             or throw_io
178             message => qq<Could not close "$file_name": $ERRNO>,
179             file_name => $file_name,
180             errno => $ERRNO;
181              
182 2         51 return $content;
183             }
184              
185             #-----------------------------------------------------------------------------
186              
187             sub _get_pod_section_from_filehandle {
188 1336     1336   2684 my ($file_handle, $section_name, $parser) = @_;
189              
190 1336         9059 $parser->select($section_name);
191              
192 1336         344503 my $content = $EMPTY;
193 1336 50       15687 open my $content_handle, '>', \$content
194             or throw_generic "error opening scalar: $OS_ERROR";
195              
196 1336         564857 $parser->parse_from_filehandle( $file_handle, $content_handle );
197              
198 1336 50       1854757 close $content_handle or throw_generic "Failed to close in memory file: $OS_ERROR";
199              
200 1336 100       4218 return if $content eq $EMPTY;
201 1328         3605 return $content;
202             }
203              
204             #-----------------------------------------------------------------------------
205              
206             sub _get_pod_section_from_string {
207 14     14   176 my ($source, $section_name, $parser) = @_;
208              
209 14 50   3   213 open my $source_handle, '<', \$source
  3         26  
  3         6  
  3         30  
210             or throw_generic "error opening scalar: $OS_ERROR";
211              
212 14         977 my $content = _get_pod_section_from_filehandle(
213             $source_handle, $section_name, $parser,
214             );
215              
216 14 50       42 close $source_handle or throw_generic "Failed to close in memory file: $OS_ERROR";
217              
218 14         50 return $content;
219             }
220              
221             #-----------------------------------------------------------------------------
222              
223             sub trim_raw_pod_section {
224 11     11 1 1556 my ($pod) = @_;
225              
226 11 50       30 return if not defined $pod;
227              
228 11         56 $pod =~ s< \A =head1 \b [^\n]* \n $ ><>xms;
229 11         46 $pod =~ s< \A \s+ ><>xms;
230 11         56 $pod =~ s< \s+ \z ><>xms;
231              
232 11         29 return $pod;
233             }
234              
235             #-----------------------------------------------------------------------------
236              
237             sub trim_pod_section {
238 1315     1315 1 4422 my ($pod) = @_;
239              
240 1315 50       2691 return if not defined $pod;
241              
242 1315         7157 $pod =~ s< \A [^\n]* \n ><>xms;
243 1315         3314 $pod =~ s< \A \s* \n ><>xms;
244 1315         7477 $pod =~ s< \s+ \z ><>xms;
245              
246 1315         2861 return $pod;
247             }
248              
249             #-----------------------------------------------------------------------------
250              
251             sub get_raw_module_abstract_from_file {
252 0     0 1 0 my ($file_name) = @_;
253              
254             return
255 0         0 _get_module_abstract_from_file(
256             $file_name,
257             Pod::Select->new(),
258             \&trim_raw_pod_section,
259             );
260             }
261              
262             #-----------------------------------------------------------------------------
263              
264             sub get_raw_module_abstract_from_filehandle {
265 0     0 1 0 my ($file_handle) = @_;
266              
267             return
268 0         0 _get_module_abstract_from_filehandle(
269             $file_handle,
270             Pod::Select->new(),
271             \&trim_raw_pod_section,
272             );
273             }
274              
275             #-----------------------------------------------------------------------------
276              
277             sub get_raw_module_abstract_from_string {
278 9     9 1 5932 my ($source) = @_;
279              
280             return
281 9         85 _get_module_abstract_from_string(
282             $source,
283             Pod::Select->new(),
284             \&trim_raw_pod_section,
285             );
286             }
287              
288             #-----------------------------------------------------------------------------
289              
290             sub get_raw_module_abstract_for_module {
291 0     0 1 0 my ($module_name) = @_;
292              
293 0 0       0 my $file_name = get_pod_file_for_module($module_name)
294             or throw_generic qq<Could not find POD for "$module_name".>;
295              
296 0         0 return get_raw_module_abstract_from_file($file_name);
297             }
298              
299             #-----------------------------------------------------------------------------
300              
301             sub get_module_abstract_from_file {
302 1303     1303 1 2512 my ($file_name) = @_;
303              
304             return
305 1303         13352 _get_module_abstract_from_file(
306             $file_name,
307             Pod::PlainText->new(),
308             \&trim_pod_section,
309             );
310             }
311              
312             #-----------------------------------------------------------------------------
313              
314             sub get_module_abstract_from_filehandle {
315 0     0 1 0 my ($file_handle) = @_;
316              
317             return
318 0         0 _get_module_abstract_from_filehandle(
319             $file_handle,
320             Pod::PlainText->new(),
321             \&trim_pod_section,
322             );
323             }
324              
325             #-----------------------------------------------------------------------------
326              
327             sub get_module_abstract_from_string {
328 8     8 1 5403 my ($source) = @_;
329              
330             return
331 8         87 _get_module_abstract_from_string(
332             $source,
333             Pod::PlainText->new(),
334             \&trim_pod_section,
335             );
336             }
337              
338             #-----------------------------------------------------------------------------
339              
340             sub get_module_abstract_for_module {
341 1303     1303 1 2257 my ($module_name) = @_;
342              
343 1303 50       2872 my $file_name = get_pod_file_for_module($module_name)
344             or throw_generic qq<Could not find POD for "$module_name".>;
345              
346 1303         3550 return get_module_abstract_from_file($file_name);
347             }
348              
349             #-----------------------------------------------------------------------------
350              
351             sub _get_module_abstract_from_file {
352 1303     1303   28183 my ($file_name, $parser, $trimmer) = @_;
353              
354 1303 50       58016 open my $file_handle, '<', $file_name
355             or throw_io
356             message => qq<Could not open "$file_name": $ERRNO>,
357             file_name => $file_name,
358             errno => $ERRNO;
359              
360 1303         5333 my $module_abstract =
361             _get_module_abstract_from_filehandle(
362             $file_handle, $parser, $trimmer,
363             );
364              
365 1303 50       19806 close $file_handle
366             or throw_io
367             message => qq<Could not close "$file_name": $ERRNO>,
368             file_name => $file_name,
369             errno => $ERRNO;
370              
371 1303         28208 return $module_abstract;
372             }
373              
374             #-----------------------------------------------------------------------------
375              
376             sub _get_module_abstract_from_filehandle { ## no critic (RequireFinalReturn)
377 1320     1320   2976 my ($file_handle, $parser, $trimmer) = @_;
378              
379 1320         3150 my $name_section =
380             _get_pod_section_from_filehandle( $file_handle, 'NAME', $parser );
381 1320 100       3034 return if not $name_section;
382              
383 1318         2922 $name_section = $trimmer->($name_section);
384 1318 100       3091 return if not $name_section;
385              
386             # Testing for parser class, blech. But it's a lot simpler and it's all
387             # hidden in the implementation.
388 1316 100       3663 if ('Pod::Select' eq ref $parser) {
389 7 100       33 if ( $name_section =~ m< \n >xms ) {
390 1         7 throw_generic
391             qq<Malformed NAME section in "$name_section". >
392             . q<It must be on a single line>;
393             }
394             }
395             else {
396 1309         10138 $name_section =~ s< \s+ >< >xmsg;
397              
398             # Ugh. Pod::PlainText splits up module names.
399 1309 100       7801 if (
400             $name_section =~ m<
401             \A
402             \s*
403             (
404             \w [ \w:]+ \w
405             )
406             (
407             \s*
408             -
409             .*
410             )?
411             \z
412             >xms
413             ) {
414 1308         4643 my ($module_name, $rest) = ($1, $2);
415              
416 1308         4059 $module_name =~ s/ [ ] //xms;
417              
418 1308 100       4018 $name_section = $module_name . ( $rest ? $rest : $EMPTY );
419             }
420             }
421              
422 1315 100       6519 if (
423             $name_section =~ m<
424             \A
425             \s*
426             [\w:]+ # Module name.
427             \s+
428             - # The required single hyphen.
429             \s+
430             (
431             \S # At least one non-whitespace.
432             (?: .* \S)? # Everything up to the last non-whitespace.
433             )
434             \s*
435             \z
436             >xms
437             ) {
438 1307         2697 my $module_abstract = $1;
439 1307         3409 return $module_abstract;
440             }
441              
442 8 100       60 if (
443             $name_section =~ m<
444             \A
445             \s*
446             [\w:]+ # Module name.
447             (?: \s* - )? # The single hyphen is now optional.
448             \s*
449             \z
450             >xms
451             ) {
452 4         12 return;
453             }
454              
455 4         25 throw_generic qq<Malformed NAME section in "$name_section".>;
456             }
457              
458             #-----------------------------------------------------------------------------
459              
460             sub _get_module_abstract_from_string {
461 17     17   190 my ($source, $parser, $trimmer) = @_;
462              
463 17 50       255 open my $source_handle, '<', \$source
464             or throw_generic "error opening scalar: $OS_ERROR";
465              
466 17         46 my $module_abstract = _get_module_abstract_from_filehandle(
467             $source_handle, $parser, $trimmer,
468             );
469              
470 12 50       33 close $source_handle or throw_generic "Failed to close in memory file: $OS_ERROR";
471              
472 12         45 return $module_abstract;
473             }
474              
475             #-----------------------------------------------------------------------------
476              
477             1;
478              
479             __END__
480              
481             #-----------------------------------------------------------------------------
482              
483             =pod
484              
485             =for stopwords
486              
487             =head1 NAME
488              
489             Perl::Critic::Utils::POD - Utility functions for dealing with POD.
490              
491              
492             =head1 SYNOPSIS
493              
494             use Perl::Critic::Utils::POD qw< get_pod_section_from_file >;
495              
496             my $synopsis =
497             get_pod_section_from_file('Perl/Critic/Utils/POD.pm', 'SYNOPSIS');
498              
499             my $see_also =
500             get_pod_section_from_filehandle($file_handle, 'SEE ALSO');
501              
502              
503             my $see_also_content = trim_pod_section($see_also);
504              
505              
506             # "Utility functions for dealing with POD."
507             my $module_abstract =
508             get_module_abstract_from_file('Perl/Critic/Utils/POD.pm');
509              
510             my $module_abstract =
511             get_module_abstract_from_filehandle($file_handle);
512              
513              
514             =head1 DESCRIPTION
515              
516             Provides means of accessing chunks of POD.
517              
518              
519             =head1 INTERFACE SUPPORT
520              
521             This is considered to be a public module. Any changes to its
522             interface will go through a deprecation cycle.
523              
524              
525             =head1 IMPORTABLE SUBROUTINES
526              
527             =over
528              
529             =item C<get_pod_file_for_module( $module_name )>
530              
531             Figure out where to find the POD for the parameter.
532              
533             This depends upon the module already being loaded; it will not find
534             the path for arbitrary modules.
535              
536             If there is a file with a ".pod" extension next to the real module
537             location, it will be returned in preference to the actual module.
538              
539              
540             =item C<get_raw_pod_section_from_file( $file_name, $section_name )>
541              
542             Retrieves the specified section of POD (i.e. something marked by
543             C<=head1>) from the file. This is uninterpreted; escapes are not
544             processed and any sub-sections will be present. E.g. if the content
545             contains "CZ<><$x>", the return value will contain "CZ<><$x>".
546              
547             Returns nothing if no such section is found.
548              
549             Throws a L<Perl::Critic::Exception::IO|Perl::Critic::Exception::IO> if
550             there's a problem with the file.
551              
552              
553             =item C<get_raw_pod_section_from_filehandle( $file_handle, $section_name )>
554              
555             Does the same as C<get_raw_pod_section_from_file()>, but with a file
556             handle.
557              
558              
559             =item C<get_raw_pod_section_from_string( $source, $section_name )>
560              
561             Does the same as C<get_raw_pod_section_from_file()>, but with a string
562             that contains the raw POD.
563              
564              
565             =item C<get_raw_pod_section_for_module( $module_name, $section_name )>
566              
567             Does the same as C<get_raw_pod_section_from_file()>, but with a module
568             name.
569              
570             Throws a
571             L<Perl::Critic::Exception::Generic|Perl::Critic::Exception::Generic>
572             if a file containing POD for the module can't be found.
573              
574              
575             =item C<get_pod_section_from_file( $file_name, $section_name )>
576              
577             Retrieves the specified section of POD (i.e. something marked by
578             C<=head1>) from the file. This is interpreted into plain text.
579              
580             Returns nothing if no such section is found.
581              
582             Throws a L<Perl::Critic::Exception::IO|Perl::Critic::Exception::IO> if
583             there's a problem with the file.
584              
585              
586             =item C<get_pod_section_from_filehandle( $file_handle, $section_name )>
587              
588             Does the same as C<get_pod_section_from_file()>, but with a file
589             handle.
590              
591              
592             =item C<get_pod_section_from_string( $source, $section_name )>
593              
594             Does the same as C<get_pod_section_from_file()>, but with a string
595             that contains the raw POD.
596              
597              
598             =item C<get_pod_section_for_module( $module_name, $section_name )>
599              
600             Does the same as C<get_pod_section_from_file()>, but with a module
601             name.
602              
603             Throws a
604             L<Perl::Critic::Exception::Generic|Perl::Critic::Exception::Generic>
605             if a file containing POD for the module can't be found.
606              
607              
608             =item C<trim_raw_pod_section( $pod_section )>
609              
610             Returns a copy of the parameter, with any starting C<=item1 BLAH>
611             removed and all leading and trailing whitespace (including newlines)
612             removed after that.
613              
614             For example, using one of the C<get_raw_pod_section_from_*> functions
615             to get the "NAME" section of this module and then calling
616             C<trim_raw_pod_section()> on the result would give you
617             "Perl::Critic::Utils::POD - Utility functions for dealing with POD.".
618              
619              
620             =item C<trim_pod_section( $pod_section )>
621              
622             Returns a copy of the parameter, with any starting line removed and
623             leading blank lines and trailing whitespace (including newlines)
624             removed after that. Note that only leading whitespace on the first
625             real line of the section will remain.
626              
627             Since this cannot count upon a C<=item1> marker, this is much less
628             reliable than C<trim_raw_pod_section()>.
629              
630              
631             =item C<get_raw_module_abstract_from_file( $file_name )>
632              
633             Attempts to parse the "NAME" section of the specified file and get the
634             abstract of the module from that. If it succeeds, it returns the
635             abstract. If it fails, either because there is no "NAME" section or
636             there is no abstract after the module name, returns nothing. If it
637             looks like there's a malformed abstract, throws a
638             L<Perl::Critic::Exception::Fatal::Generic|Perl::Critic::Exception::Fatal::Generic>.
639              
640             Example "well formed" "NAME" sections without abstracts:
641              
642             Some::Module
643              
644             Some::Other::Module -
645              
646             Example "NAME" sections that will result in an exception:
647              
648             Some::Bad::Module This has no hyphen.
649              
650             Some::Mean::Module -- This has double hyphens.
651              
652             Some::Nasty::Module - This one attempts to
653             span multiple lines.
654              
655              
656             =item C<get_raw_module_abstract_from_filehandle( $file_handle )>
657              
658             Does the same as C<get_raw_module_abstract_from_file()>, but with a
659             file handle.
660              
661              
662             =item C<get_raw_module_abstract_from_string( $source )>
663              
664             Does the same as C<get_raw_module_abstract_from_file()>, but with a
665             string that contains the raw POD.
666              
667              
668             =item C<get_raw_module_abstract_for_module( $module_name )>
669              
670             Does the same as C<get_raw_module_abstract_from_file()>, but for a
671             module name.
672              
673              
674             =item C<get_module_abstract_from_file( $file_name )>
675              
676             Does the same as C<get_raw_module_abstract_from_file()>, but with
677             escapes interpreted.
678              
679              
680             =item C<get_module_abstract_from_filehandle( $file_handle )>
681              
682             Does the same as C<get_module_abstract_from_file()>, but with a file
683             handle.
684              
685              
686             =item C<get_module_abstract_from_string( $source )>
687              
688             Does the same as C<get_module_abstract_from_file()>, but with a string
689             that contains the raw POD.
690              
691              
692             =item C<get_module_abstract_for_module( $module_name )>
693              
694             Does the same as C<get_module_abstract_from_file()>, but for a module
695             name.
696              
697              
698             =back
699              
700              
701             =head1 AUTHOR
702              
703             Elliot Shank <perl@galumph.com>
704              
705              
706             =head1 COPYRIGHT
707              
708             Copyright (c) 2008-2011 Elliot Shank.
709              
710             This program is free software; you can redistribute it and/or modify
711             it under the same terms as Perl itself. The full text of this license
712             can be found in the LICENSE file included with this module.
713              
714             =cut
715              
716             # Local Variables:
717             # mode: cperl
718             # cperl-indent-level: 4
719             # fill-column: 78
720             # indent-tabs-mode: nil
721             # c-indentation-style: bsd
722             # End:
723             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :