1 ##############################################################################
2 # $URL: http://perlcritic.tigris.org/svn/perlcritic/trunk/Perl-Critic/lib/Perl/Critic/Utils/POD.pm $
3 # $Date: 2008-07-03 10:19:10 -0500 (Thu, 03 Jul 2008) $
6 ##############################################################################
8 package Perl::Critic::Utils::POD;
14 use English qw< -no_match_vars >;
17 use Pod::PlainText ();
20 # TODO: non-fatal generic?
21 use Perl::Critic::Exception::Fatal::Generic qw< throw_generic >;
22 use Perl::Critic::Exception::IO qw< throw_io >;
23 use Perl::Critic::Utils qw< :characters >;
27 our $VERSION = '1.088';
29 #-----------------------------------------------------------------------------
32 get_pod_file_for_module
33 get_raw_pod_section_from_file
34 get_raw_pod_section_from_filehandle
35 get_raw_pod_section_from_string
36 get_raw_pod_section_for_module
37 get_pod_section_from_file
38 get_pod_section_from_filehandle
39 get_pod_section_from_string
40 get_pod_section_for_module
43 get_raw_module_abstract_from_file
44 get_raw_module_abstract_from_filehandle
45 get_raw_module_abstract_from_string
46 get_raw_module_abstract_for_module
47 get_module_abstract_from_file
48 get_module_abstract_from_filehandle
49 get_module_abstract_from_string
50 get_module_abstract_for_module
57 #-----------------------------------------------------------------------------
59 sub get_pod_file_for_module {
60 my ($module_name) = @_;
62 # No File::Spec: %INC always uses forward slashes.
63 (my $relative_path = $module_name) =~ s< :: ></>xmsg;
64 $relative_path .= '.pm';
66 my $absolute_path = $INC{$relative_path} or return;
68 (my $pod_path = $absolute_path) =~ s< [.] [^.]+ \z><.pod>xms;
69 return $pod_path if -f $pod_path;
71 return $absolute_path;
74 #-----------------------------------------------------------------------------
76 sub get_raw_pod_section_from_file {
77 my ($file_name, $section_name) = @_;
79 return _get_pod_section_from_file(
86 #-----------------------------------------------------------------------------
88 sub get_raw_pod_section_from_filehandle {
89 my ($file_handle, $section_name) = @_;
91 return _get_pod_section_from_filehandle(
98 #-----------------------------------------------------------------------------
100 sub get_raw_pod_section_from_string {
101 my ($source, $section_name) = @_;
103 return _get_pod_section_from_string(
110 #-----------------------------------------------------------------------------
112 sub get_raw_pod_section_for_module {
113 my ($module_name, $section_name) = @_;
115 my $file_name = get_pod_file_for_module($module_name)
116 or throw_generic qq<Could not find POD for "$module_name".>;
118 return get_raw_pod_section_from_file($file_name, $section_name);
121 #-----------------------------------------------------------------------------
123 sub get_pod_section_from_file {
124 my ($file_name, $section_name) = @_;
126 return _get_pod_section_from_file(
129 Pod::PlainText->new(),
133 #-----------------------------------------------------------------------------
135 sub get_pod_section_from_filehandle {
136 my ($file_handle, $section_name) = @_;
138 return _get_pod_section_from_filehandle(
141 Pod::PlainText->new(),
145 #-----------------------------------------------------------------------------
147 sub get_pod_section_from_string {
148 my ($source, $section_name) = @_;
150 return _get_pod_section_from_string(
153 Pod::PlainText->new(),
157 #-----------------------------------------------------------------------------
159 sub get_pod_section_for_module {
160 my ($module_name, $section_name) = @_;
162 my $file_name = get_pod_file_for_module($module_name)
163 or throw_generic qq<Could not find POD for "$module_name".>;
165 return get_pod_section_from_file($file_name, $section_name);
168 #-----------------------------------------------------------------------------
170 sub _get_pod_section_from_file {
171 my ($file_name, $section_name, $parser) = @_;
173 # Grr... the handle is open for a whopping 1 statement. Too painful to
174 # fix the policy right now.
175 ## no critic (RequireBriefOpen)
176 open my $file_handle, '<', $file_name
178 message => qq<Could not open "$file_name": $ERRNO>,
179 file_name => $file_name,
183 _get_pod_section_from_filehandle(
184 $file_handle, $section_name, $parser,
189 message => qq<Could not close "$file_name": $ERRNO>,
190 file_name => $file_name,
197 #-----------------------------------------------------------------------------
199 sub _get_pod_section_from_filehandle {
200 my ($file_handle, $section_name, $parser) = @_;
202 $parser->select($section_name);
204 my $content = $EMPTY;
205 my $content_handle = IO::String->new( \$content );
207 $parser->parse_from_filehandle( $file_handle, $content_handle );
209 return if $content eq $EMPTY;
213 #-----------------------------------------------------------------------------
215 sub _get_pod_section_from_string {
216 my ($source, $section_name, $parser) = @_;
218 my $source_handle = IO::String->new( \$source );
221 _get_pod_section_from_filehandle(
222 $source_handle, $section_name, $parser,
226 #-----------------------------------------------------------------------------
228 sub trim_raw_pod_section {
231 return if not defined $pod;
233 $pod =~ s< \A =head1 \b [^\n]* \n $ ><>xms;
234 $pod =~ s< \A \s+ ><>xms;
235 $pod =~ s< \s+ \z ><>xms;
240 #-----------------------------------------------------------------------------
242 sub trim_pod_section {
245 return if not defined $pod;
247 $pod =~ s< \A [^\n]* \n ><>xms;
248 $pod =~ s< \A \s* \n ><>xms;
249 $pod =~ s< \s+ \z ><>xms;
254 #-----------------------------------------------------------------------------
256 sub get_raw_module_abstract_from_file {
257 my ($file_name) = @_;
260 _get_module_abstract_from_file(
263 \&trim_raw_pod_section,
267 #-----------------------------------------------------------------------------
269 sub get_raw_module_abstract_from_filehandle {
270 my ($file_handle) = @_;
273 _get_module_abstract_from_filehandle(
276 \&trim_raw_pod_section,
280 #-----------------------------------------------------------------------------
282 sub get_raw_module_abstract_from_string {
286 _get_module_abstract_from_string(
289 \&trim_raw_pod_section,
293 #-----------------------------------------------------------------------------
295 sub get_raw_module_abstract_for_module {
296 my ($module_name) = @_;
298 my $file_name = get_pod_file_for_module($module_name)
299 or throw_generic qq<Could not find POD for "$module_name".>;
301 return get_raw_module_abstract_from_file($file_name);
304 #-----------------------------------------------------------------------------
306 sub get_module_abstract_from_file {
307 my ($file_name) = @_;
310 _get_module_abstract_from_file(
312 Pod::PlainText->new(),
317 #-----------------------------------------------------------------------------
319 sub get_module_abstract_from_filehandle {
320 my ($file_handle) = @_;
323 _get_module_abstract_from_filehandle(
325 Pod::PlainText->new(),
330 #-----------------------------------------------------------------------------
332 sub get_module_abstract_from_string {
336 _get_module_abstract_from_string(
338 Pod::PlainText->new(),
343 #-----------------------------------------------------------------------------
345 sub get_module_abstract_for_module {
346 my ($module_name) = @_;
348 my $file_name = get_pod_file_for_module($module_name)
349 or throw_generic qq<Could not find POD for "$module_name".>;
351 return get_module_abstract_from_file($file_name);
354 #-----------------------------------------------------------------------------
356 sub _get_module_abstract_from_file {
357 my ($file_name, $parser, $trimmer) = @_;
359 # Grr... the handle is open for a whopping 1 statement. Too painful to
360 # fix the policy right now.
361 ## no critic (RequireBriefOpen)
362 open my $file_handle, '<', $file_name
364 message => qq<Could not open "$file_name": $ERRNO>,
365 file_name => $file_name,
368 my $module_abstract =
369 _get_module_abstract_from_filehandle(
370 $file_handle, $parser, $trimmer,
375 message => qq<Could not close "$file_name": $ERRNO>,
376 file_name => $file_name,
380 return $module_abstract;
383 #-----------------------------------------------------------------------------
385 sub _get_module_abstract_from_filehandle { ## no critic (RequireFinalReturn)
386 my ($file_handle, $parser, $trimmer) = @_;
389 _get_pod_section_from_filehandle( $file_handle, 'NAME', $parser );
390 return if not $name_section;
392 $name_section = $trimmer->($name_section);
393 return if not $name_section;
395 # Testing for parser class, blech. But it's a lot simpler and it's all
396 # hidden in the implementation.
397 if ('Pod::Select' eq ref $parser) {
398 if ( $name_section =~ m< \n >xms ) {
400 qq<Malformed NAME section in "$name_section". >
401 . q<It must be on a single line>;
405 $name_section =~ s< \s+ >< >xmsg;
407 # Ugh. Pod::PlainText splits up module names.
423 my ($module_name, $rest) = ($1, $2);
425 $module_name =~ s/ [ ] //xms;
427 $name_section = $module_name . ( $rest ? $rest : $EMPTY );
435 [\w:]+ # Module name.
437 - # The required single hyphen.
440 \S # At least one non-whitespace.
441 (?: .* \S)? # Everything up to the last non-whitespace.
447 my $module_abstract = $1;
448 return $module_abstract;
455 [\w:]+ # Module name.
456 (?: \s* - )? # The single hyphen is now optional.
464 throw_generic qq<Malformed NAME section in "$name_section".>;
467 #-----------------------------------------------------------------------------
469 sub _get_module_abstract_from_string {
470 my ($source, $parser, $trimmer) = @_;
472 my $source_handle = IO::String->new( \$source );
475 _get_module_abstract_from_filehandle(
476 $source_handle, $parser, $trimmer,
480 #-----------------------------------------------------------------------------
486 #-----------------------------------------------------------------------------
494 Perl::Critic::Utils::POD - Utility functions for dealing with POD.
499 use Perl::Critic::Utils::POD qw< get_pod_section_from_file >;
502 get_pod_section_from_file('Perl/Critic/Utils/POD.pm', 'SYNOPSIS');
505 get_pod_section_from_filehandle($file_handle, 'SEE ALSO');
508 my $see_also_content = trim_pod_section($see_also);
511 # "Utility functions for dealing with POD."
512 my $module_abstract =
513 get_module_abstract_from_file('Perl/Critic/Utils/POD.pm');
515 my $module_abstract =
516 get_module_abstract_from_filehandle($file_handle);
521 Provides means of accessing chunks of POD.
524 =head1 IMPORTABLE SUBROUTINES
528 =item C<get_pod_file_for_module( $module_name )>
530 Figure out where to find the POD for the parameter.
532 This depends upon the module already being loaded; it will not find
533 the path for arbitrary modules.
535 If there is a file with a ".pod" extension next to the real module
536 location, it will be returned in preference to the actual module.
539 =item C<get_raw_pod_section_from_file( $file_name, $section_name )>
541 Retrieves the specified section of POD (i.e. something marked by
542 C<=head1>) from the file. This is uninterpreted; escapes are not
543 processed and any sub-sections will be present. E.g. if the content
544 contains "CZ<><$x>", the return value will contain "CZ<><$x>".
546 Returns nothing if no such section is found.
548 Throws a L<Perl::Critic::Exception::IO> if there's a problem with the
552 =item C<get_raw_pod_section_from_filehandle( $file_handle, $section_name )>
554 Does the same as C<get_raw_pod_section_from_file()>, but with a file
558 =item C<get_raw_pod_section_from_string( $source, $section_name )>
560 Does the same as C<get_raw_pod_section_from_file()>, but with a string
561 that contains the raw POD.
564 =item C<get_raw_pod_section_for_module( $module_name, $section_name )>
566 Does the same as C<get_raw_pod_section_from_file()>, but with a module
569 Throws a L<Perl::Critic::Exception::Generic> if a file containing POD
570 for the module can't be found.
573 =item C<get_pod_section_from_file( $file_name, $section_name )>
575 Retrieves the specified section of POD (i.e. something marked by
576 C<=head1>) from the file. This is interpreted into plain text.
578 Returns nothing if no such section is found.
580 Throws a L<Perl::Critic::Exception::IO> if there's a problem with the
584 =item C<get_pod_section_from_filehandle( $file_handle, $section_name )>
586 Does the same as C<get_pod_section_from_file()>, but with a file
590 =item C<get_pod_section_from_string( $source, $section_name )>
592 Does the same as C<get_pod_section_from_file()>, but with a string
593 that contains the raw POD.
596 =item C<get_pod_section_for_module( $module_name, $section_name )>
598 Does the same as C<get_pod_section_from_file()>, but with a module
601 Throws a L<Perl::Critic::Exception::Generic> if a file containing POD
602 for the module can't be found.
605 =item C<trim_raw_pod_section( $pod_section )>
607 Returns a copy of the parameter, with any starting C<=item1 BLAH>
608 removed and all leading and trailing whitespace (including newlines)
611 For example, using one of the C<get_raw_pod_section_from_*> functions
612 to get the "NAME" section of this module and then calling
613 C<trim_raw_pod_section()> on the result would give you
614 "Perl::Critic::Utils::POD - Utility functions for dealing with POD.".
617 =item C<trim_pod_section( $pod_section )>
619 Returns a copy of the parameter, with any starting line removed and
620 leading blank lines and trailing whitespace (including newlines)
621 removed after that. Note that only leading whitespace on the first
622 real line of the section will remain.
624 Since this cannot count upon a C<=item1> marker, this is much less
625 reliable than C<trim_raw_pod_section()>.
628 =item C<get_raw_module_abstract_from_file( $file_name )>
630 Attempts to parse the "NAME" section of the specified file and get the
631 abstract of the module from that. If it succeeds, it returns the
632 abstract. If it fails, either because there is no "NAME" section or
633 there is no abstract after the module name, returns nothing. If it
634 looks like there's a malformed abstract, throws a
635 L<Perl::Critic::Exception::Fatal::Generic>.
637 Example "well formed" "NAME" sections without abstracts:
641 Some::Other::Module -
643 Example "NAME" sections that will result in an exception:
645 Some::Bad::Module This has no hyphen.
647 Some::Mean::Module -- This has double hyphens.
649 Some::Nasty::Module - This one attempts to
653 =item C<get_raw_module_abstract_from_filehandle( $file_handle )>
655 Does the same as C<get_raw_module_abstract_from_file()>, but with a
659 =item C<get_raw_module_abstract_from_string( $source )>
661 Does the same as C<get_raw_module_abstract_from_file()>, but with a
662 string that contains the raw POD.
665 =item C<get_raw_module_abstract_for_module( $module_name )>
667 Does the same as C<get_raw_module_abstract_from_file()>, but for a
671 =item C<get_module_abstract_from_file( $file_name )>
673 Does the same as C<get_raw_module_abstract_from_file()>, but with
677 =item C<get_module_abstract_from_filehandle( $file_handle )>
679 Does the same as C<get_module_abstract_from_file()>, but with a file
683 =item C<get_module_abstract_from_string( $source )>
685 Does the same as C<get_module_abstract_from_file()>, but with a string
686 that contains the raw POD.
689 =item C<get_module_abstract_for_module( $module_name )>
691 Does the same as C<get_module_abstract_from_file()>, but for a module
700 Elliot Shank <perl@galumph.com>
704 Copyright (c) 2008 Elliot Shank. All rights reserved.
706 This program is free software; you can redistribute it and/or modify
707 it under the same terms as Perl itself. The full text of this license
708 can be found in the LICENSE file included with this module.
714 # cperl-indent-level: 4
716 # indent-tabs-mode: nil
717 # c-indentation-style: bsd
719 # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :