Icon for Dimension.orgIcon for TalentIcon for ToolsIcon for Doorways.org
Icon for ToolsIcon for Perl Tools

DoxyFilt: Perl/Filter/Filter.pm Source File

  • Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List

Perl/Filter/Filter.pm

Go to the documentation of this file.
00001 #=| @note   This tests comments for files
00002 
00003 package Doxygen::Perl::Filter;
00004 
00005 =head1 NAME
00006 
00007 Doxygen::Perl::Filter - Perl extension for generating Doxygen documentation
00008 
00009 =head1 SYNOPSIS
00010 
00011     my  $filter = new Doxygen::Perl::Filter($path);
00012 
00013 =head1 ABSTRACT
00014 
00015 The basic Perl script filter, or parser.
00016 Processes a Perl script or module looking
00017 for subroutines and class inheritance.
00018 Creates appropriate Doxygen::Item and subclass
00019 objects to represent the file,
00020 any package (class) defined within the file,
00021 functions or methods defined in the file,
00022 and other miscellaneous comments.
00023 Stores the data on itself (single use only)
00024 and generates Doxygen-parseable output as required.
00025 
00026 =head1 DESCRIPTION
00027 
00028 Some comments are ignored by POD but can be used to push data straight
00029 through to Doxygen, so use Doxygen markup symbology.
00030 The comments are recognized by the comment pattern registered
00031 with the Doxygen::Source package, defaulting to the constant
00032 C<COMMENT> defined in this module.
00033     
00034 Octothorpe bars:
00035 
00036     ##################################################################
00037 
00038 Must have at least 64 octothorpes (not settable at this time).
00039 Octothorpe bars may begin with any of the comment sequences,
00040 in which case the total must contain no spaces and be at least
00041 64 characters long.
00042 
00043 Octothorpe bars are immune to Doxygen pass-through.  If you want to
00044 pass one through, make it with a comment trigraph (as above) followed
00045 by a space followed by whatever you want to pass through.
00046     
00047 =head1 METHODS
00048 
00049 =over
00050 
00051 =cut
00052 
00053 #=| @note   This tests comments for classes
00054 
00055 use     5.005;  # just to pick something, but not really tested
00056 use     strict;
00057 use     warnings;
00058 use     UNIVERSAL   qw(isa);
00059 
00060 use     Carp;
00061 
00062 use     base qw(Doxygen::Filter);
00063 
00064 use     Doxygen::Item::Class;
00065 use     Doxygen::Item::Function;
00066 use     Doxygen::POD::Filter;
00067 
00068 our $VERSION = '0.01';
00069 
00070 use     constant    COMMENT =>  qr(^\s*#(?:##(?!#)|=\|) ?(.*)$)m;
00071 
00072 ###########################################################################
00073 ###########################################################################
00074 
00075 =item   C<new($class, %flags)>
00076 
00077 Constructor for Doxygen::Perl::Filter objects.
00078 
00079 =cut
00080 
00081 ### @param  %flags  flags to become object's fields
00082 
00083 sub new
00084 {
00085     Doxygen::Filter::new(@_, cmnt => COMMENT)
00086 }
00087 
00088 
00089 =item   C<parse($self, $text, $source)>
00090 
00091 Parse a source file.
00092 
00093 Attach results (Doxygen::Item objects) to Doxygen::Source object.
00094 
00095 =cut
00096 
00097 ### \param  $text   reference to text of entire file
00098 ### @param  $source source object for parse,
00099 ###                 contains persistent data for parse
00100 
00101 sub parse
00102 {
00103     my ($self, $text, $source) = @_;
00104     
00105     # First yank out all the nasty POD,
00106     #   which will be handled by a different filter:
00107     Doxygen::POD::Filter::CleanText(\$text);
00108     
00109     # Remove any __END__ and/or __DATA__ from the end:
00110     $text =~ s/\n\s*__(?:END|DATA)__.*$//s;
00111     
00112     # Now count the lines:
00113     
00114     $self->{lines} = {
00115         blank   => 0,
00116         code    => 0,
00117         comment => 0,
00118         total   => 0
00119     };
00120     
00121     for (split(/\n/, $text)) {
00122         $self->{lines}->{total}++;
00123         
00124         if (/^\s*#/) {          # comment line
00125             $self->{lines}->{comment}++;
00126         } elsif (! /\S/) {    # blank line
00127             $self->{lines}->{blank}++;
00128         } else {                # code line
00129             $self->{lines}->{code}++;
00130         }
00131     }
00132     
00133     # Paranoia runs deep...
00134     
00135     if ($text =~ /\n=/) {
00136         $source->log('E', "POD still in 'cleaned' text in ",
00137                      __PACKAGE__, "::parse():\n", $text);
00138         exit;
00139     }
00140     
00141     # Break up the source text by package (class):
00142     my  @chunks = split /(?:^|(?<=[\n|;|\}]))\s*package\s+([\w:]+)\s*;/s,
00143                   $text;
00144     
00145     # Adjust chunks according to arcane rituals:
00146     
00147     my  $last1 = @chunks - 2;
00148     
00149     for (my $i = 0; $i < $last1; $i++) {
00150         # Is there comment data at the end of the previous block?
00151         if (my $block = EndBlock(\$chunks[$i])) {
00152             substr($chunks[$i+2], 0, 0, $block);
00153         }
00154     }
00155     
00156     # Parse the parts according to their predilections:
00157     
00158     $self->parseHeader(shift(@chunks), $source);
00159     
00160     $self->parseClass(splice(@chunks, 0, 2), $source)
00161         while @chunks > 1;
00162 }
00163 
00164 ###########################################################################
00165 ###########################################################################
00166 
00167 =item   C<parseClass($self, $class, $text, $source)>
00168 
00169 Parse a section of source text beginning with a package declaration
00170 and ending before the next package declaration (or end of file).
00171 
00172 =cut
00173 
00174 ### @internal
00175 
00176 sub parseClass  # $self, $class, $text, $source
00177 {
00178     my ($self, $class, $text, $source) = @_;
00179     my  $item = new Doxygen::Item::Class(name => $class);
00180     
00181     $source->focus->itemSet('class', $item, $class);
00182     $source->entityPush($item);
00183     
00184     eval {
00185         $source->log('T', 'Parsing class ', $class)->pushLog;
00186         
00187         eval {
00188             $self->parseFuncs($text, $source);
00189         };
00190         
00191         $source->popLog;
00192 
00193         die $@ if $@;
00194     };
00195     
00196     $source->entityPop($item);
00197         
00198     die $@ if $@;
00199 }
00200 
00201 ###########################################################################
00202 ###########################################################################
00203 
00204 =item   C<parseFunc($self, $function, $text, $source)>
00205 
00206 Parse a section of source text beginning with a subroutine
00207 declaration and ending before the next subroutine declaration
00208 (or end of file).
00209 
00210 =cut
00211 
00212 ### @internal
00213 
00214 sub parseFunc
00215 {
00216     my ($self, $function, $text, $source) = @_;
00217     my  %flags  = ( name => $function);
00218     my  $entity = $source->entity;
00219     
00220     $flags{class} = $entity
00221         if isa $entity, 'Doxygen::Item::Class';
00222     
00223     my  $item = new Doxygen::Item::Function(%flags);
00224     
00225     $entity->itemSet('function', $item, $function);
00226     $source->entityPush($item);
00227     
00228     eval {  # Parse text associated with function:
00229         $source->log('T', 'Parsing sub ', $function, "()\n")->pushLog;
00230         
00231         eval {
00232 #           Took this out for the moment,
00233 #             it seems to pick up ### comments passing @param
00234 #             through to Doxygen...
00235 #           $item->arguments($1) if $text =~ /^[#\s]*(\\?[\$\@\%]\w.*?)\n/s;
00236             $self->parseCmnts(\$text, $source);
00237         };
00238         
00239         $source->popLog;
00240         
00241         die $@ if $@;
00242     };
00243     
00244     $source->entityPop($item);
00245     
00246     die $@ if $@;
00247 }
00248 
00249 ###########################################################################
00250 ###########################################################################
00251 
00252 =item   C<parseFuncs($self, $text, $source)>
00253 
00254 Parse text associated with file or class.
00255 
00256 Break out functions and act appropriately.
00257 
00258 =cut
00259 
00260 sub parseFuncs
00261 {
00262     my ($self, $text, $source) = @_;
00263     
00264     # Break up the source text by function declaration:
00265     my  @chunks = split /(?:^|(?<=[\n|;|\}]))\s*sub\s+(\w+)\s*/s, $text;
00266 
00267     # Adjust chunks according to arcane rituals:
00268 
00269     my  $last1 = @chunks - 2;
00270 
00271     for (my $i = 0; $i < $last1; $i++) {
00272         # Is there comment data at the end of the previous block?
00273         if (my $block = EndBlock(\$chunks[$i])) {
00274             substr($chunks[$i+2], 0, 0, $block);
00275         }
00276     }
00277 
00278     # Parse the parts according to their predilections:
00279 
00280     $self->parsePlain(shift(@chunks), $source);
00281 
00282     $self->parseFunc(splice(@chunks, 0, 2), $source)
00283         while @chunks > 1;
00284 }
00285 
00286 ###########################################################################
00287 ###########################################################################
00288 
00289 =item   C<parseHeader($self, $text, $source)>
00290 
00291 Parse a section of source text containing no package declarations.
00292 
00293 =cut
00294 
00295 ### @internal
00296 
00297 sub parseHeader  # $self, $text, $source
00298 {
00299     my  $self = shift;
00300     
00301     $self->parseFuncs(@_)
00302 }
00303 
00304 ###########################################################################
00305 ###########################################################################
00306 
00307 =item   C<parsePlain($self, $text, $source)>
00308 
00309 Parse a section of source text containing no package or
00310 function declarations.
00311 
00312 ### @internal
00313 
00314 =cut
00315 
00316 sub parsePlain  # $self, $text, $source
00317 {
00318     my ($self, $text, $source) = @_;
00319     my  $entity = $source->entity;
00320     
00321 #   $source->log('T', 'parsePlain(', $source, ' [', $entity, '] )');
00322 #   $source->log('T', $text);
00323     
00324     $entity->textAppend('notes', "\@version $1\n")
00325         if $text
00326         && $text =~ /\n\s*(?:(?:our|my)\s*)?\$VERSION\s*=\s*(.+?)\s*;/s;
00327     
00328     if (isa($entity, 'Doxygen::Item::Class')) {
00329         # Look for class inheritance:
00330 
00331         $self->parseAnc_s($source, $1)
00332             while $text =~ /\@ISA\s*=\s*(?:qw)?\(([^\)]+)\)\s*;/g;
00333 
00334         $self->parseAnc_s($source, $1)
00335             while $text =~ /\buse\s+base\s+(?:qw)?\(([^\)]+)\)\s*;/g;
00336     }
00337 
00338     $self->parseCmnts(\$text, $source);
00339 }
00340 
00341 ###########################################################################
00342 ###########################################################################
00343 
00344 =item   C<parseAnc_s($self, $source, $ancestors)>
00345 
00346 Parse a list of ancestors from C<@ISA> or C<use base>.
00347 
00348 =cut
00349 
00350 ### @internal
00351 
00352 sub parseAnc_s  # $self, $source, $ancestors
00353 {
00354     my ($self, $source, $ancestors) = @_;
00355     my  $entity = $source->entity;
00356     
00357 #   $source->log('T', 'parseAnc_s(', $entity, ', ', $ancestors, ')');
00358     
00359     $entity->ancestor($ancestors)
00360         if isa $entity, 'Doxygen::Item::Class';
00361 
00362     for my $include (split /\s+/, $ancestors) {
00363         if (0) {
00364             #include documentation in Perl format:
00365             $source->getFile->Include($include);
00366         } else {
00367             #include documentation uses existing pathnames,
00368             #   allows more data to be collected/deduced
00369             #   by doxygen, probably preferable, eh?
00370             $include =~ s|::|/|g;
00371             $source->getFile->Include("$include.pm");
00372         }
00373     }
00374 }
00375 
00376 ###########################################################################
00377 ###########################################################################
00378 
00379 =item   C<EndBlock(\$text)>
00380 
00381 Peels a last block of comments from a referenced chunk of text.
00382 
00383 Defined essentially as one or more octothorpe separator bars followed
00384 by nothing but 'special' DoxyFilt comment lines (or blank lines)
00385 to the end of the text block:
00386 
00387     #########################################################
00388     #########################################################
00389     #
00390     #   Some comment text...
00391     #
00392     =EOT=
00393 
00394 Remove the text block if it is found, otherwise undef.
00395 
00396 =cut
00397 
00398 ### @internal
00399 
00400 sub EndBlock    # \$text
00401 {
00402     my  $text = shift;
00403     my  $good = undef;
00404     my  @text = split /\n+/, $$text;
00405     my  @rslt = ( );
00406     
00407     while (my $line = pop(@text)) {
00408         unless ($line || $line =~ /\S/) {
00409             # Track the blank lines in case we find something good,
00410             #   but they're not sufficient in themselves:
00411             unshift @rslt, $line, 
00412             next;
00413         }
00414         
00415         if ($line =~ /^\s*#/) {
00416             # Comments should re-attach down in case
00417             #   they're special Doxygen comments:
00418             $good++ if $line =~ /\S/;
00419             unshift @rslt, $line;
00420             next;
00421         }
00422         
00423         # At this point we're dealing with a code line
00424         #   (it's not blank and it's not a comment, eh?)
00425         #   so the search is done:
00426         
00427         push @text, $line;  # don't lose last line!
00428         last;
00429     }
00430     
00431     if ($good) {
00432         # Found something we think should go down to the next block:
00433         $$text = join "\n", @text;
00434         return   join "\n", @rslt, '';
00435     }
00436     
00437     undef
00438 }
00439 
00440 ###########################################################################
00441 ###########################################################################
00442 
00443 1
00444 
00445 __END__
00446 
00447 =back
00448 
00449 =head1 SEE ALSO
00450 
00451 DoxyFilt.pl Doxygen::Filter
00452 
00453 =head1 AUTHOR
00454 
00455 Marc M. Adkins, L<mailTo:Perl@Doorways.org>
00456 
00457 =head1 COPYRIGHT AND LICENSE
00458 
00459 Copyright 2004-2010 by Marc M. Adkins
00460 
00461 This library is free software; you can redistribute it and/or modify
00462 it under the same terms as Perl itself.
00463 
00464 =cut

Generated on Mon Dec 27 2010 15:15:39 for DoxyFilt by  doxygen 1.7.1

www.dimension.org logo

(C)opyright 1998 - 2012 Dimension.org

WebMaster