00001 package Doxygen::Source;
00002
00003 =head1 NAME
00004
00005 Doxygen::Source - Perl extension for generating Doxygen documentation
00006
00007 =head1 SYNOPSIS
00008
00009 my $source = new Doxygen::Source($path);
00010
00011 $source->generate;
00012
00013 =head1 ABSTRACT
00014
00015 Represents a single source file to be filtered for Doxygen.
00016
00017 A newly created instance requires a pathname, from which text is read.
00018 Zero or more parsers will be passed against the source text,
00019 storing interim state (Doxygen::Item objects) on the Source object.
00020
00021 When the parsing is complete, use the object to generate Doxygen-enabled
00022 output.
00023
00024 =head1 DESCRIPTION
00025
00026 =head1 METHODS
00027
00028 =over
00029
00030 =cut
00031
00032 use 5.005; # just to pick something, but not really tested
00033 use strict;
00034 use warnings;
00035 use UNIVERSAL qw(isa);
00036
00037 use Doxygen::Item::File;
00038
00039 use base qw(Doxygen::Item);
00040
00041 our $VERSION = '0.01';
00042
00043 use constant TYPE_ALIAS => (
00044 Batch => 'Script',
00045 Shell => 'Script',
00046 );
00047
00048 use constant TYPE_CHCK => (
00049 Perl => qr(^(?:#!/.*\bperl|package)\b)m,
00050 POD => qr(^=(?:cut|head\d|item|pod))m,
00051 Shell => qr(^#!/bin/(?:ba|c|k|z)?sh\b)
00052 );
00053
00054 use constant TYPE_CMNT => (
00055 Batch => qr(^\s*rem ?(.*)$)im,
00056 Shell => qr(^\s*#{2,3}(?!#) ?(.*)$)m
00057 );
00058
00059 use constant TYPE_DOCS => (
00060 Batch => qr(\.(?:bat|cmd)$)i,
00061 Perl => qr(\.(?:p[lm])$)i,
00062 POD => qr(\.(?:p(?:l|m|od))$)i,
00063 Shell => qr(\.(?:ba|c|k|z)?sh$)i,
00064 SQL => qr(\.sql$)i
00065 );
00066
00067 use constant TYPE_FLAG => (
00068 );
00069
00070 use constant TYPE_PASS => (
00071 qr(\.doxy?$)i
00072 );
00073
00074 use constant TYPE_SPAWN => (
00075 # Python => /usr/local/bin/DoxyPyth.py
00076 );
00077
00078 ###########################################################################
00079 ###########################################################################
00080
00081 =item C<new($class, %flags)>
00082
00083 Constructor for Doxygen::Source objects.
00084
00085 Takes a series of flags which initialize object fields.
00086 If the C<path> flag is set the object is immediately
00087 parsed, otherwise it must be done later.
00088
00089 Useful flags:
00090
00091 =over
00092
00093 =item C<info>
00094
00095 If set to false will turn I<off> the
00096 generation of 'informational' ([I])
00097 log messages.
00098
00099 =item C<type>
00100
00101 A hash reference that
00102 contains a series of objects that control how pathnames
00103 are processed or not processed.
00104 In general, the sub-objects specify regular expressions
00105 that are matched against pathnames.
00106
00107 In all cases regular expressions may be replaced by
00108 simple strings that are converted into regular expressions
00109 using the following expression:
00110
00111 qr(\.$strings$)i
00112
00113 The following sub-flags may be specified
00114 within the C<type> hash:
00115
00116 =over
00117
00118 =item C<alias>
00119
00120 Causes specific filter names to be handled
00121 by different filters.
00122 For example, C<Batch> and C<Shell> are both
00123 handled by the instantiated C<Script> filter.
00124 There are no C<Batch> and C<Shell> filters
00125 (unless you instantiate them yourself).
00126 Each key can have a single value,
00127 new ones replace old ones, setting a key
00128 to point to itself is equivalent to
00129 removing it.
00130
00131 =item C<check>
00132
00133 Specifies patterns for filters to see if files
00134 without suffixes are destined for these filters.
00135 For example, specify a pattern for the first
00136 line of a shell file (C<qr(^#!/bin/(?:ba|c|k|z)sh\b)>)
00137 which may show up without a suffix.
00138 The keys are filter names, (e.g. C<Shell>).
00139 Each key can have a single comment pattern,
00140 and a new one with the same key replaces the
00141 older one with that key.
00142
00143 =item C<cmnt>
00144
00145 A hash reference to a list of keys and comment
00146 recognition patterns.
00147 The patterns must each have a single returned
00148 value (C<$1>), that is to say, they must each
00149 return the comment text found.
00150 The keys are filter names, (e.g. C<Batch>).
00151 Each key can have a single comment pattern,
00152 and a new one with the same key replaces the
00153 older one with that key.
00154
00155 =item C<docs>
00156
00157 A hash reference to a list of keys and suffixes.
00158 The keys are filter names, for example C<POD>
00159 invokes C<Doxygen::POD::Filter>.
00160 Each key can have a single suffix pattern,
00161 and a new one with the same key replaces the
00162 older one with that key.
00163
00164 =item C<pass>
00165
00166 An array reference to a list of suffixes that should be
00167 passed through unprocessed.
00168 Values are cumulative with the default value (C<qr(\.doxy?)i>)
00169 but can be overidden by setting C<docs>.
00170
00171 =item C<spawn>
00172
00173 Hash reference from document types to command-line invocations.
00174 Define the suffix and document type in C<docs> then define
00175 the spawning command line using the document type name as the key.
00176 The command line can have C<{}> as a placeholder for the pathname
00177 of the file to be processed or it will be appended to the end.
00178
00179 =back
00180
00181 =item C<path>
00182
00183 Pathname of file to be parsed into the object.
00184 Calls C<Parse()> method with the value after
00185 other initialization.
00186 The same can be done separately.
00187
00188 =item C<stats>
00189
00190 Turns statistics generation on or off.
00191 Defaults to on, set to non-true value to override.
00192
00193 =item C<trace>
00194
00195 Turns on generation of tracing ([T]) and hacking
00196 ([H]) messages.
00197
00198 =back
00199
00200 Takes a pathname (C<$path>) as an argument.
00201 During the construction of the object parses the
00202 file thus specified using as many applicable
00203 filters are possible.
00204
00205 If no filters apply, returns C<undef> to indicate
00206 that other action is required
00207 (the file needs to be copied through).
00208
00209 In the latter case, if the pathname doesn't match
00210 one of the 'pass through' patterns a warning is logged.
00211
00212 =cut
00213
00214 sub new
00215 {
00216 my ($class, %flags) = @_;
00217 my $self = bless \%flags, $class;
00218
00219 # Fixup comment type suffix patterns:
00220
00221 my %alias = TYPE_ALIAS;
00222
00223 if (isa($self->{type}->{alias}, 'HASH')) {
00224 $alias{$_} = $self->{type}->{alias}->{$_}
00225 for keys %{$self->{type}->{alias}};
00226 }
00227
00228 $self->{type}->{alias} = \%alias;
00229
00230 # Fixup filter check patterns:
00231
00232 my %chck = TYPE_CHCK;
00233
00234 if (isa($self->{type}->{chck}, 'HASH')) {
00235 $chck{$_} = _filterPattern_($self->{type}->{chck}->{$_})
00236 for keys %{$self->{type}->{chck}};
00237 }
00238
00239 $self->{type}->{chck} = \%chck;
00240
00241 # Fixup comment type suffix patterns:
00242
00243 my %cmnt = TYPE_CMNT;
00244
00245 if (isa($self->{type}->{cmnt}, 'HASH')) {
00246 $cmnt{$_} = _suffixPattern_($self->{type}->{cmnt}->{$_})
00247 for keys %{$self->{type}->{cmnt}};
00248 }
00249
00250 $self->{type}->{cmnt} = \%cmnt;
00251
00252 # Fixup document type suffix patterns:
00253
00254 my %docs = TYPE_DOCS;
00255
00256 if (isa($self->{type}->{docs}, 'HASH')) {
00257 $docs{$_} = _suffixPattern_($self->{type}->{docs}->{$_})
00258 for keys %{$self->{type}->{docs}};
00259 }
00260
00261 $self->{type}->{docs} = \%docs;
00262
00263 my %flag = TYPE_FLAG;
00264
00265 if (isa($self->{type}->{flag}, 'HASH')) {
00266 $flag{$_} = _flagValue_($self->{type}->{flag}->{$_})
00267 for keys %{$self->{type}->{flag}};
00268 }
00269
00270 $self->{type}->{flag} = \%flag;
00271
00272 # Fixup pass-through suffix patterns:
00273
00274 my @pass = TYPE_PASS;
00275
00276 push @pass, map { _suffixPattern_($_) } @{$self->{type}->{pass}}
00277 if isa $self->{type}->{pass}, 'ARRAY';
00278
00279 $self->{type}->{pass} = \@pass;
00280
00281 # Fixup process spawn patterns:
00282
00283 my %spawn = TYPE_SPAWN;
00284
00285 if (isa($self->{type}->{spawn}, 'HASH')) {
00286 $spawn{$_} = $self->{type}->{spawn}->{$_}
00287 for keys %{$self->{type}->{spawn}};
00288 }
00289
00290 $self->{type}->{spawn} = \%spawn;
00291
00292 $self->{stats} = 1
00293 unless exists $self->{stats};
00294
00295 # Parse (if necessary) and return self unless parse fails:
00296
00297 $self->{path} ? $self->parse : $self
00298 }
00299
00300 ###########################################################################
00301
00302 sub DESTROY # $self
00303 {
00304 $_[0]->popLog;
00305 }
00306
00307 ###########################################################################
00308 ###########################################################################
00309
00310 =item C<parse($self [ , $path ])>
00311
00312 Parse the specified source file.
00313
00314 Applies all appropriate parsers the the source file.
00315 Each parser is able to store information on itself
00316 or this C<Doxygen::Source> object.
00317
00318 =cut
00319
00320 sub parse
00321 {
00322 my $self = shift;
00323 my $path = shift || $self->{path};
00324
00325 unless ($path && -f $path) {
00326 $self->log('E', 'No viable source path to be parsed!',
00327 ($path ? "\n $path" : ''));
00328 return undef;
00329 }
00330
00331 for my $docType (keys %{$self->{type}->{spawn}}) {
00332 return $self->spawn($docType, $path)
00333 if isa($self->{type}->{docs}->{$docType}, 'Regexp')
00334 && $path =~ $self->{type}->{docs}->{$docType};
00335 }
00336
00337 # Create the file object immediately:
00338 local $/ = undef; # slurp file
00339
00340 unless (open(SOURCE, '<', $self->{path})) {
00341 $self->log('E', "Unable to open source file:\n ",
00342 $self->{path}, "\n $!\n");
00343 return undef;
00344 }
00345
00346 my $text = <SOURCE>;
00347
00348 close SOURCE;
00349
00350 unless ($text && $text =~ /\S/) {
00351 $self->log('E', "Empty source file:\n ", $self->{path}, "\n");
00352 return undef;
00353 }
00354
00355 # OK, the file exists,
00356 # create the first entity to represent the file:
00357
00358 local $SIG{__WARN__} = sub { $self->_warning_(shift) };
00359
00360 $self->log('I', 'File: ', $self->{path}, "\n")->pushLog;
00361
00362 my $found = 0;
00363
00364 $self = eval {
00365 $self->{entity} = [ $self->getFile($self->{path}) ];
00366
00367 # Check for all kinds of parsers that might match the document:
00368
00369 for ( # all registered doc types...
00370 keys(%{$self->{type}->{docs}}),
00371 # ...and all types that have check patterns...
00372 grep { # ...and aren't a registered doc type...
00373 ! $self->{type}->{docs}->{$_}
00374 } keys(%{$self->{type}->{chck}}) ) {
00375 # Check to see if we have a matching document type:
00376 next
00377 unless ($self->{type}->{docs}->{$_} &&
00378 $self->{path} =~ $self->{type}->{docs}->{$_})
00379 || ($self->{path} !~ /\.[^\/\\\.]*$/ &&
00380 $self->{type}->{chck}->{$_} &&
00381 $text =~ $self->{type}->{chck}->{$_});
00382
00383 eval {
00384 # Safely create a filter for that document type:
00385 my $fAlias = $self->{type}->{alias}->{$_} || $_;
00386 my $fClass = "Doxygen::${fAlias}::Filter";
00387 my $filter = eval "use $fClass; new $fClass";
00388
00389 $@ && die "Error loading filter:\n $@\n";
00390 $filter || die "Unable to load filter:\n $@\n";
00391
00392 # Set comment pattern for filter
00393 # (by document type, not alias name):
00394
00395 $filter->{cmnt} = $self->{type}->{cmnt}->{$_}
00396 if $self->{type}->{cmnt}->{$_};
00397
00398 # Parse file with the filter for this document type:
00399 $filter->parse($text, $self);
00400
00401 $found = 1
00402 if $self->{stats}
00403 && $filter->statistics($self);
00404
00405 $self->{filters}->{$_} = $filter;
00406 };
00407
00408 $@ && $self->log('E', "Error parsing ", $_, " document:\n ",
00409 $self->{path}, "\n $@");
00410 }
00411
00412 unless (keys %{$self->{filters}}) {
00413 ($self->{path} =~ $_ && return undef)
00414 for @{$self->{type}->{pass}};
00415
00416 $self->log('W', "Don\'t know how to filter document:\n ",
00417 $self->{path}, "\n");
00418
00419 return undef
00420 }
00421
00422 $self
00423 };
00424
00425 die $@ if $@;
00426
00427 if ($found) {
00428 my @lines = split /\n/, $text;
00429
00430 $self->log('.', 'Source total(', scalar(@lines), ')');
00431 }
00432
00433 $self
00434 }
00435
00436 ###########################################################################
00437
00438 =item C<spawn($self, $doctype, $path)>
00439
00440 Spawn a sub-process via C<system()> to execute a program to handle
00441 the current path.
00442
00443 =cut
00444
00445 sub spawn
00446 {
00447 my ($self, $doctype, $path) = @_;
00448
00449 $self->{spawned} = 1;
00450
00451 my $command = $self->{type}->{spawn}->{$doctype};
00452
00453 unless ($command && $command =~ /\S/) {
00454 $self->log('W', 'Empty command for ', $doctype);
00455
00456 return undef;
00457 }
00458
00459 $command =~ s|\{\}|$path| or $command .= " $path";
00460
00461 $self->log('I', 'Spawn: ', $command);
00462
00463 my $result = system $command;
00464
00465 if ($result < 0) {
00466 $self->log('E', 'Unable to start ', $doctype, ' command:');
00467 $self->log('+', ' ', $command);
00468 $self->log('+', ' ', $!);
00469
00470 return undef;
00471 }
00472
00473 my $exitValue = $? >> 8;
00474 my $signalNum = $? & 127;
00475 my $coreDumped = $? & 128;
00476
00477 $self->log('W', 'Exit value: ', $exitValue) if $exitValue;
00478 $self->log('W', 'Signal num: ', $signalNum) if $signalNum;
00479 $self->log('W', 'Core dumped!') if $coreDumped;
00480 $self
00481 }
00482
00483 ###########################################################################
00484 ###########################################################################
00485
00486 =item C<massage($self)>
00487
00488 Massage items in file after parsing and before generating.
00489
00490 Each filter may have a C<massage> method and/or a C<parse> method.
00491 The order of parsing and massaging is undefined except that
00492 I<all> parsing will complete prior to I<any> massaging being done.
00493
00494 For the C<Source> object, C<massage> must iterate through the
00495 set of filters created during the C<parse> phase and call the
00496 C<massage> method on each one.
00497
00498 =cut
00499
00500 sub massage
00501 {
00502 my $self = shift;
00503
00504 return if $self->{spawned};
00505
00506 local $SIG{__WARN__} = sub { $self->_warning_(shift) };
00507
00508 # Massage all of the filters:
00509 $_->massage($self)
00510 for values %{$self->{filters}};
00511
00512 # Massage the file:
00513 $self->getFile->massage($self);
00514 }
00515
00516 ###########################################################################
00517 ###########################################################################
00518
00519 =item C<generate($self, %flags)>
00520
00521 Generates output understandable by doxygen to standard output.
00522
00523 Should be run after running C<massage()>.
00524
00525 Must be overloaded by derived subclasses.
00526
00527 =cut
00528
00529 sub generate
00530 {
00531 my $self = shift;
00532
00533 return if $self->{spawned};
00534
00535 local $SIG{__WARN__} = sub { $self->_warning_(shift) };
00536
00537 $self->getFile->generate(@_, source => $self);
00538 $self->SUPER::generate (@_, source => $self);
00539 }
00540
00541 ###########################################################################
00542 ###########################################################################
00543
00544 =item C<entity($self)>
00545
00546 Return the top node from the entity stack.
00547
00548 The entity stack is for source entities.
00549 The stack always starts with a Doxygen::Item::File object to
00550 represent the file being parsed.
00551 Other objects that may be placed on the stack :
00552
00553 <ul>
00554 <li>Doxygen::Item::Class
00555 <li>Doxygen::Item::Function
00556 </ul>
00557
00558 In general a file object will be on the bottom,
00559 then a class object (if applicable) and finally
00560 a function object.
00561
00562 =cut
00563
00564 sub entity
00565 {
00566 $_[0]->{entity}->[0]
00567 }
00568
00569 ###########################################################################
00570
00571 =item C<entityPop($self [ , $entity ] )>
00572
00573 Pop the top entity from the entity stack.
00574
00575 If the C<$entity> argument is defined,
00576 pop all entities down to and including that specified.
00577
00578 =cut
00579
00580 sub entityPop # $self [ , $entity ]
00581 {
00582 my ($self, $entity) = @_;
00583
00584 if ($entity) {
00585 while (my $popped = shift @{$self->{entity}}) {
00586 last if $popped == $entity;
00587 }
00588 } else {
00589 shift @{$self->{entity}};
00590 }
00591 }
00592
00593 ###########################################################################
00594
00595 =item C<entityPush($self, $entity)>
00596
00597 Push a new current entity on the stack.
00598
00599 The stack starts with just the file object.
00600
00601 =cut
00602
00603 #=| \param $entity The entity to be pushed onto the stack.
00604
00605 sub entityPush # $self, $entity
00606 {
00607 my $self = shift;
00608
00609 unshift @{$self->{entity}}, shift
00610 }
00611
00612 ###########################################################################
00613 ###########################################################################
00614
00615 =item C<flag($self, $name [ , $docType ])>
00616
00617 Return value of named flag in source context.
00618
00619 Flags are specified at source creation.
00620 Flags are named either C<docType::flagName> or C<flagName>.
00621 The former describe flags specific to document types
00622 (filter types) and only visible to filters of the specified
00623 document type.
00624 In addition, the former, where applicable, override the latter.
00625 The latter are global to all filters and act as global flags
00626 and/or default values for specific flags.
00627
00628 When a flag is requested by name, if a C<$docType>
00629 is specified it will be used to check for a filter-specific
00630 value first, then for the global value.
00631 The argument should be either the name of a filter class
00632 or an object of a filter class.
00633
00634 The C<$name> argument should never specify names
00635 of the form C<docType::flagName>, as that is specified
00636 via the optional C<$docType> parameter.
00637
00638 =cut
00639
00640 sub flag
00641 {
00642 my ($self, $name, $doctype) = @_;
00643
00644 # $self->log('T', __PACKAGE__, '::flag(', $name, ', ', $doctype, ')');
00645
00646 if ($doctype && isa($doctype, 'Doxygen::Filter')) {
00647 my $filtype = ref($doctype) || $doctype;
00648
00649 # $self->log('T', 'fTyp: ', $filtype);
00650
00651 if ($filtype =~ /Doxygen::(.*)::Filter/) {
00652 my $name = "$1::$name";
00653
00654 # $self->log('T', 'name: ', $name);
00655
00656 return $self->{type}->{flag}->{$name}
00657 if exists $self->{type}->{flag}->{$name};
00658 }
00659
00660 if (ref($doctype)) {
00661 my $flag = $doctype->flags;
00662
00663 # $self->log('T', 'flag: ', $flag);
00664 # $self->log('T', ' ', $_, ' => ', $flag->{$_}) for keys %$flag;
00665 # $self->log('T', 'valu: ', $flag->{$name});
00666
00667 return $flag->{$name}
00668 if exists $flag->{$name};
00669 }
00670 }
00671
00672 # $self->log('T', 'valu= ', $self->{type}->{flag}->{$name});
00673
00674 $self->{type}->{flag}->{$name}
00675 }
00676
00677 ###########################################################################
00678 ###########################################################################
00679
00680 =item C<focus($self)>
00681
00682 Return the current focus for adding comment lines.
00683
00684 Defaults to the value for the current source entity,
00685 but may be overridden by descendant classes modelling
00686 language-specific documentation entities.
00687
00688 =cut
00689
00690 #=| \return A doxy::Item object.
00691
00692 sub focus
00693 {
00694 $_[0]->entity
00695 }
00696
00697 ###########################################################################
00698 ###########################################################################
00699
00700 =item C<getFile($self [ , $path ] )>
00701
00702 Get file object for this filter object,
00703 creating object if necessary.
00704
00705 my $file = $target->getFile($path);
00706
00707 The file object should be created early using the path so that it can
00708 be referred to freely without the pathname later:
00709
00710 $doc->getFile->append($text);
00711
00712 =cut
00713
00714 sub getFile
00715 {
00716 my $self = shift;
00717
00718 unless (isa($self->{file}, 'Doxygen::Item::File')) {
00719 my $path = shift;
00720
00721 return
00722 unless $path
00723 && $path =~ /\S/;
00724
00725 # This makes Doxygen::Test work,
00726 # but it could be considered non-optimal
00727 # (then again, why would we ever need it otherwise?):
00728 $path =~ s|\.\./||g;
00729
00730 $self->{file} = new Doxygen::Item::File(path => $path)
00731 }
00732
00733 $self->{file}
00734 }
00735
00736 ###########################################################################
00737 ###########################################################################
00738
00739 =item C<log($self, $code, @stuff)>
00740
00741 Formatted logging function.
00742
00743 The C<$code> is a single-character from the following set:
00744
00745 =over
00746
00747 =item I
00748
00749 Info
00750
00751 =item T
00752
00753 Trace
00754
00755 =item W
00756
00757 Warning
00758
00759 =item E
00760
00761 Error
00762
00763 =back
00764
00765 =cut
00766
00767 sub log
00768 {
00769 my $self = shift;
00770 my $code = shift || 'T';
00771
00772 return $self # hacking and tracing messages default off
00773 if ($code eq 'H' || $code eq 'T')
00774 && ! $self->{trace};
00775
00776 return $self # information messages default on
00777 if $code eq 'I'
00778 && exists $self->{info}
00779 && ! $self->{info};
00780
00781 my $indent = isa($self->{logIndent}, 'ARRAY') && @{$self->{logIndent}}
00782 ? $self->{logIndent}->[0]
00783 : '';
00784
00785 for (split(/\n/, join('', map {
00786 defined($_) ? $_ : '<undef>'
00787 } @_, "\n"))) {
00788 print STDERR "[$code]$indent $_\n";
00789 $code = '+' unless $code eq '+';
00790 }
00791
00792 $self
00793 }
00794
00795 ###########################################################################
00796
00797 =item C<popLog($self)>
00798
00799 Pop the last indentation level from the logging stream.
00800
00801 =cut
00802
00803 sub popLog # $self
00804 {
00805 my $self = shift;
00806
00807 shift @{$self->{logIndent}}
00808 if isa($self->{logIndent}, 'ARRAY')
00809 && @{$self->{logIndent}};
00810
00811 $self
00812 }
00813
00814 ###########################################################################
00815
00816 =item C<pushLog($self [ , $spaces ] )>
00817
00818 Indent the logging functionality accessible via log().
00819
00820 Specify the C<$spaces> (as the actual indentation string) or it defaults to 2.
00821
00822 =cut
00823
00824 sub pushLog # $self [ , $spaces ]
00825 {
00826 my $self = shift;
00827
00828 $self->{logIndent} = [ ]
00829 unless isa $self->{logIndent}, 'ARRAY';
00830
00831 unshift @{$self->{logIndent}},
00832 ((@{$self->{logIndent}} ? $self->{logIndent}->[0] : '')
00833 . (shift || ' '));
00834
00835 $self
00836 }
00837
00838 ###########################################################################
00839
00840 =item C<_warning_($self, $stuff)>
00841
00842 Special logging call used for trapping warnings.
00843
00844 Breaks up standard warning text so it doesn't overwrite lines in log.
00845
00846 =cut
00847
00848 #=| @internal
00849
00850 sub _warning_
00851 {
00852 my ($self, $stuff) = @_;
00853
00854 $stuff =~ s/\b(at\s+[\w\.\\\/]+\s*line\s+\d+)/\n $1/;
00855
00856 $self->log('W', $stuff)
00857 }
00858
00859 ###########################################################################
00860 ###########################################################################
00861
00862 =item C<_commentPattern_($string)>
00863
00864 Convert a string into a pattern for recognizing a comment.
00865
00866 =cut
00867
00868 #=| @todo handle qr()im flags
00869
00870 sub _commentPattern_
00871 {
00872 isa($_[0], 'Regexp') ? $_[0] :
00873 $_[0] =~ /^qr\((.*)\)$/ ? qr($1) : qr(^\s*$_[0] ?(.*)$)m
00874 }
00875
00876 ###########################################################################
00877
00878 =item C<_filterPattern_($string)>
00879
00880 Convert a string into a pattern for recognizing a comment.
00881
00882 =cut
00883
00884 #=| @todo handle qr()im flags
00885
00886 sub _filterPattern_
00887 {
00888 isa($_[0], 'Regexp') ? $_[0] :
00889 $_[0] =~ /^qr\((.*)\)$/ ? qr($1) : qr(^$1)
00890 }
00891
00892 ###########################################################################
00893
00894 =item C<_flagValue_($string)>
00895
00896 Evaluate a string (or pattern) representing a flag value.
00897
00898 =cut
00899
00900 #=| @todo handle qr()im flags
00901
00902 sub _flagValue_
00903 {
00904 isa($_[0], 'Regexp') ? $_[0] :
00905 $_[0] =~ /^qr\((.*)\)$/ ? qr(^$1$) : $_[0]
00906 }
00907
00908 ###########################################################################
00909
00910 =item C<_suffixPattern_($string)>
00911
00912 Convert a string into a pattern for recognizing a suffix.
00913
00914 =cut
00915
00916 #=| @todo handle qr()i flag
00917
00918 sub _suffixPattern_
00919 {
00920 isa($_[0], 'Regexp') ? $_[0] :
00921 $_[0] =~ /^qr\((.*)\)$/ ? qr($1) : qr(\.$_[0])i
00922 }
00923
00924 ###########################################################################
00925 ###########################################################################
00926
00927 1
00928
00929 __END__
00930
00931 =back
00932
00933 =head1 SEE ALSO
00934
00935 DoxyFilt.pl Doxygen::Filter
00936
00937 =head1 AUTHOR
00938
00939 Marc M. Adkins, L<mailTo:Perl@Doorways.org>
00940
00941 =head1 COPYRIGHT AND LICENSE
00942
00943 Copyright 2004-2010 by Marc M. Adkins
00944
00945 This library is free software; you can redistribute it and/or modify
00946 it under the same terms as Perl itself.
00947
00948 =cut