File Coverage

blib/lib/Perl/ToPerl6/Utils/POD.pm
Criterion Covered Total %
statement 32 129 24.8
branch 0 42 0.0
condition n/a
subroutine 11 36 30.5
pod 19 19 100.0
total 62 226 27.4


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