File Coverage

lib/Pod/Autopod.pm
Criterion Covered Total %
statement 14 663 2.1
branch 0 218 0.0
condition 0 90 0.0
subroutine 5 56 8.9
pod 11 11 100.0
total 30 1038 2.8


line stmt bran cond sub pod time code
1             package Pod::Autopod; ## Generates pod documentation by analysing perl modules.
2             $Pod::Autopod::VERSION = '1.213';
3 1     1   721 use 5.006; #Pod::Abstract uses features of 5.6
  1         2  
4 1     1   615 use FileHandle;
  1         10291  
  1         7  
5 1     1   493 use strict;
  1         2  
  1         26  
6 1     1   838 use Pod::Abstract;
  1         29061  
  1         46  
7 1     1   14 use Pod::Abstract::BuildNode qw(node nodes);
  1         3  
  1         9221  
8              
9              
10             # This Module is designed to generate pod documentation of a perl class by analysing its code.
11             # The idea is to have something similar like javadoc. So it uses also comments written directly
12             # obove the method definitions. It is designed to asumes a pm file which represents a class.
13             #
14             # Of course it can not understand every kind of syntax, parameters, etc. But the plan is to improve
15             # this library in the future to understand more and more automatically.
16             #
17             # Please note, there is also an "autopod" command line util in this package.
18             #
19             #
20             # SYNOPSIS
21             # ========
22             #
23             # use Pod::Autopod;
24             #
25             # new Pod::Autopod(readfile=>'Foo.pm', writefile=>'Foo2.pm');
26             #
27             # # reading Foo.pm and writing Foo2.pm but with pod
28             #
29             #
30             # my $ap = new Pod::Autopod(readfile=>'Foo.pm');
31             # print $ap->getPod();
32             #
33             # # reading and Foo.pm and prints the generated pod.
34             #
35             # my $ap = new Pod::Autopod();
36             # $ap->setPerlCode($mycode);
37             # print $ap->getPod();
38             # $ap->writeFile('out.pod');
39             #
40             # # asumes perl code in $mycoce and prints out the pod.
41             # # also writes to the file out.pod
42             #
43             #
44             # HOWTO
45             # =====
46             #
47             # To add a documentation about a method, write it with a classical remark char "#"
48             # before the sub{} definition:
49             #
50             # # This method is doing foo.
51             # #
52             # # print $self->foo();
53             # #
54             # #
55             # # It is not doing bar, only foo.
56             # sub foo{
57             # ...
58             # }
59             #
60             # A gap before sub{} is allowed.
61             #
62             # In further versions of autopod, here new features will appear.
63             #
64             # To define parameters and return values you can use a boundle of keywords.
65             # So far parameters and return values can not realy be autodetected, so manual
66             # way is necessary, but it is designed to type it rapidly.
67             #
68             # sub foo{ # void ($text)
69             # ...
70             # }
71             #
72             # The example above produces the following method description:
73             #
74             # $self->foo($text);
75             #
76             # The object "$self" is the default and automatially used when a constructor was found ("new")
77             # or the class inherits with ISA or "use base".
78             # You can change this by the parameter "selfstring" in the autopod constructor.
79             #
80             # The example looks simple, but the engine does more than you think. Please have a look here:
81             #
82             # sub foo{ # void (scalar text)
83             # ...
84             # }
85             #
86             # That procudes the same output! It means the dollar sign of the first example is a symbol which means "scalar".
87             #
88             # sub foo{ # ($)
89             # ...
90             # }
91             #
92             # Produces:
93             #
94             # $self->foo($scalar);
95             #
96             # As you see, that was the quickest way to write the definition. The keywork "void" is default.
97             #
98             # The following keywords or characters are allowed:
99             #
100             # array @
101             # arrayref \@
102             # hash %
103             # hashref \%
104             # method &
105             # scalar $
106             # scalarref \$
107             # void only as return value
108             #
109             # Now a more complex example:
110             #
111             # sub foo{# $state ($firstname,$lastname,\%persondata)
112             # ...
113             # }
114             #
115             # produces:
116             #
117             # my $state = $self->foo($firstname, $lastname, \%persondata);
118             #
119             # or write it in java style:
120             #
121             # sub foo{# scalar state (scalar firstname,scalar lastname,hashref persondata)
122             # ...
123             # }
124             #
125             # Multiple return values may be displayed as following:
126             #
127             # sub foo{# $a,$b ($text)
128             # ...
129             # }
130             #
131             # produces:
132             #
133             # my ($a, $b) = $self->foo($text);
134             #
135             #
136             # If you want to use key values pairs as in a hash, you may describe it like:
137             #
138             # sub foo{# void (firstname=>$scalar,lastname=>scalar)
139             # ...
140             # }
141             #
142             # The second "scalar" above is without a "$", that is no mistake, both works.
143             #
144             # There is also a way to expain that a value A OR B is expected. See here:
145             #
146             # sub foo{# $lista|\$refb (\@list|$text,$flag)
147             # ...
148             # }
149             #
150             # procudes:
151             #
152             # my $lista | \$refb = $self->foo(\@list | $text, $flag);
153             #
154             # Of course, that is not an official perl syntax with the or "|", but it shows
155             # you that is expected.
156             #
157             #
158             # In the First Part obove all method descriptions, you can add general informations, which are
159             # per default displayed under the head item "DESCRIPTION". But also own items can be used by
160             # underlining a text with "=" chars like:
161             #
162             # # HOWTO
163             # # =====
164             # # Read here howto do it.
165             #
166             # Some of these title keywords are allways places in a special order, which you can not change. For
167             # example LICENSE is allways near the end.
168             #
169             # Added some hacks to teach this tool also some doxygen parametes. For example:
170             #
171             # # @brief kept as simple text
172             # # @param text to be added
173             # # @return string with some text
174             # sub foo{
175             # return "abc".shift;
176             # }
177             #
178             #
179             # procudes:
180             #
181             # my $string = $self->foo($text);
182             #
183             #
184             # LICENSE
185             # =======
186             # You can redistribute it and/or modify it under the conditions of LGPL.
187             #
188             # By the way, the source code is quite bad. So feel free to replace this idea with something better Perl OO code.
189             #
190             # AUTHOR
191             # ======
192             # Andreas Hernitscheck ahernit(AT)cpan.org
193              
194              
195             # Constructor
196             #
197             # The keyvalues are not mandatory.
198             #
199             # selfstring may hold something like '$self' as alternative to '$self', which is default.
200             #
201             # alsohiddenmethods gets a boolean flag to show also methods which starts with "_".
202             #
203             sub new{ # $object ($filename=>scalar,alsohiddenmethods=>scalar,selfstring=>scalar)
204 0     0 1   my $pkg=shift;
205 0           my %v=@_;
206              
207              
208 0           my $self={};
209 0           bless $self,$pkg;
210              
211 0           $self->{package}=$pkg;
212              
213 0           foreach my $k (keys %v){ ## sets values to object
214 0           $self->{$k}=$v{$k};
215             }
216            
217 0   0       $self->{'selfstring'} = $self->{'selfstring'} || '$self';
218            
219              
220 0 0         if ($self->{'readfile'}){
221 0           $self->readFile($self->{'readfile'});
222             }
223              
224              
225 0 0         if ($self->{'writefile'}){
226 0           $self->writeFile($self->{'writefile'});
227             }
228              
229              
230 0 0         if ($self->{'readdir'}){
231 0           $self->readDirectory($self->{'readdir'});
232             }
233              
234 0           return $self;
235             }
236              
237              
238             ## Returns the border string which delimit the perl code and pod inside a pm file.
239             sub getBorderString{ ## $scalar
240 0     0 1   my $self=shift;
241 0           my $pkg=$self->{'package'};
242              
243 0 0         if ($self->{'BORDER'} eq ''){
244            
245 0           my $border = '#' x 20;
246 0           $border .= " pod generated by $pkg - keep this line to make pod updates possible ";
247 0           $border .= '#' x 20;
248 0           $self->{'BORDER'}=$border;
249            
250             }
251              
252 0           return $self->{'BORDER'};
253             }
254              
255              
256             ## Set an alternative border string.
257             ## If you change this, you have to do it again when updating the pod.
258             sub setBorderString{ ## void ($borderstring)
259 0     0 1   my $self=shift;
260 0           my $s=shift;
261              
262 0           $self->{'BORDER'} =$s;
263              
264             }
265              
266              
267              
268             # Expects Perl code as arrayref
269             # or text (scalar).
270             #
271             # When used, it automatically runs scanArray().
272             # This now passes the filename to be used in case
273             # we are podding a .pl or .cgi file. NW
274             sub setPerlCode{ ## void ($text|\@array, $file)
275 0     0 1   my $self=shift;
276 0           my $code=shift;
277 0           my $file=shift;
278              
279 0           my $arr;
280              
281 0 0         if (!ref $code){
282 0           my @a = split(/\n/,$code);
283 0           $arr = \@a;
284             }else{
285 0           $arr=$code;
286             }
287              
288 0           $self->{'PERL_CODE'}=$arr;
289              
290 0           $self->scanArray($arr, $file);
291 0           $self->buildPod();
292             }
293              
294              
295             # Returns perl code which was set before.
296             sub getPerlCode{# $text
297 0     0 1   my $self=shift;
298            
299 0           my $border = $self->getBorderString();
300            
301 0           my $arr = $self->{'PERL_CODE'};
302            
303 0           my @code;
304 0           foreach my $row (@$arr){
305            
306 0 0         if ($row=~ m/$border/){last}; ## border found, end loop
  0            
307            
308 0           push @code,$row;
309             }
310            
311 0           my $text=join("",@code);
312            
313 0           return $text;
314             }
315              
316              
317              
318             # Returns the pod formated text.s
319             sub getPod{ ## $text
320 0     0 1   my $self=shift;
321              
322 0           return $self->{"POD_TEXT"};
323             }
324              
325              
326              
327             sub _getFileArray{
328 0     0     my $self=shift;
329 0           my $filename=shift;
330 0           my @f;
331              
332 0           my $fh=new FileHandle;
333 0           open($fh,'<',$filename);
334             #lockhsh($fh);
335 0           @f=<$fh>;
336             #unlockh($fh);
337 0           close($fh);
338              
339              
340 0 0         return wantarray ? @f : \@f;
341             }
342              
343              
344             sub _getFileScalar{
345 0     0     my $self=shift;
346 0           my $filename=shift;
347            
348 0           my $a = $self->_getFileArray($filename);
349              
350 0           return join("",@$a);
351             }
352              
353              
354              
355             # writes a pod file
356             #
357             # If the file has a pm or pl or cgi extension, it writes the perl code and the pod
358             # If the file has a pod extension or any, it only writes the pod.
359             sub writeFile{ # void ($filename)
360 0     0 1   my $self=shift;
361 0           my $file=shift;
362 0           my $pod=$self->getPod();
363              
364 0 0         if ($file=~ m/\.(pm|pl|cgi)$/i){ ## target is pm or pl or cgi file, so add perl-code
365 0           my $text=$self->getPerlCode();
366 0           $text.="\n".$self->{'BORDER'}."\n\n$pod";
367 0           $self->_putFile($file,$text);
368             }else{## target is any or pod file, write only pod
369 0           $self->_putFile($file,$pod);
370             }
371            
372             }
373              
374              
375             ## Reading a Perl class file and loads it to memory.
376             sub readFile{ # void ($filename)
377 0     0 1   my $self=shift;
378 0 0         my $file=shift or die "need filename";
379              
380              
381 0           my $arr = $self->_getFileArray($file);
382 0           $self->setPerlCode($arr, $file);
383            
384            
385             }
386              
387              
388             ## scans a directoy recoursively for pm files and may
389             ## generate pod of them.
390             ##
391             ## You can also set the flag updateonly to build new pod
392             ## only for files you already build a pod (inside the file)
393             ## in the past. Alternatively you can write the magic word
394             ## AUTOPODME somewhere in the pm file what signals that this
395             ## pm file wants to be pod'ed by autopod.
396             ##
397             ## The flag pod let will build a separate file. If poddir set,
398             ## the generated pod file will be saved to a deparate directory.
399             ## With verbose it prints the list of written files.
400             ##
401             sub readDirectory{ # void ($directory,updateonly=>scalar,pod=>scalar,verbose=>scalar)
402 0     0 1   my $self=shift;
403 0 0         my $directory=shift or die "need directory";
404 0           my $v={@_};
405 0           my $updateonly=$v->{'updateonly'};
406 0           my $verbose=$v->{'verbose'};
407 0           my $pod=$v->{'pod'};
408 0           my $poddir=$v->{'poddir'};
409 0           my $border=$self->getBorderString();
410              
411              
412 0           my @dir = $self->_getPodFilesRecoursive($directory);
413              
414              
415 0           foreach my $filein (@dir){
416            
417 0           my $fileout = $filein;
418              
419 0 0         if ($poddir){
420 0           $pod=1;
421 0           $fileout=~ s|^$directory|$poddir|;
422              
423 0           my $p=_extractPath($fileout);
424              
425              
426 0 0         if (!-e $p){
427 0           _makeDirRecursive($p);
428             }
429             }
430              
431            
432 0           my $filecontent = $self->_getFileScalar($filein);
433 0 0         if ($updateonly){
434 0 0 0       if (($filecontent!~ m/$border/) && ($filecontent!~ m/AUTOPODME/) ){$fileout=undef}; ## no border, no update
  0            
435             }
436            
437 0 0         if ($pod){
438 0           $fileout=~ s/\.pm$/.pod/;
439             }
440            
441 0           my $ap = new Pod::Autopod();
442 0           $ap->readFile($filein);
443 0           $ap->writeFile($fileout);
444            
445 0 0 0       print $fileout."\n" if $verbose && $fileout;
446            
447             }
448              
449             }
450              
451              
452              
453              
454              
455             sub _getPodFilesRecoursive{
456 0     0     my $self=shift;
457 0           my $path=shift;
458 0           my %para=@_;
459 0           my @files;
460              
461 0           @files=$self->_getFilesRecoursiveAll($path);
462 0           $self->_filterFileArray(\@files,ext=>'pm',path=>$path);
463 0           @files=sort @files;
464              
465 0 0         return wantarray ? @files : \@files;
466             }
467              
468              
469             sub _getFilesRecoursiveAll{
470 0     0     my $self=shift;
471 0           my $path=shift;
472 0           my %para;
473             my @f;
474 0           my @fm;
475              
476              
477 0           @f=$self->_getDirArray($path);
478              
479             #$self->_filterFileArray(\@f);
480 0           $self->_addPathToArray($path,\@f);
481              
482 0           foreach my $d (@f){
483 0 0         if (-d $d){
484 0           push @fm,$self->_getFilesRecoursiveAll($d);
485             }
486             }
487 0           push @f,@fm;
488              
489            
490            
491 0           return @f;
492             }
493              
494              
495              
496             sub _getDirArray{
497 0     0     my $self=shift;
498 0           my $path=shift;
499 0           my @f;
500             my @nf;
501              
502 0           opendir(FDIR,$path);
503 0           @f=readdir FDIR;
504 0           closedir(FDIR);
505              
506 0           foreach my $d (@f){
507 0 0         if ($d!~ m/^\.\.?/){push @nf,$d};
  0            
508             }
509              
510 0 0         return wantarray ? @nf : \@nf;
511             }
512              
513              
514              
515             sub _addPathToArray{
516 0     0     my $self=shift;
517 0           my $path=shift;
518 0           my $dir_ref=shift;
519              
520 0           foreach my $z (@$dir_ref){
521 0           $z=$path.'/'.$z;
522             }
523             }
524            
525              
526              
527              
528             sub _filterFileArray{
529 0     0     my $self=shift;
530 0           my $dir_ref=shift;
531 0           my %para=@_;
532 0           my @nf;
533 0           my $path=$para{path};
534              
535              
536 0 0         if ($para{onlyFiles} ne ''){$para{noDir}=1};
  0            
537            
538            
539 0           foreach my $i (@$dir_ref){
540 0           my $ok=1;
541 0 0         if ($i=~ m/^\.\.?$/){$ok=0};
  0            
542            
543 0 0         if (-d $i){$ok=0};
  0            
544              
545 0           my $ext=lc($para{ext});
546 0 0         if (exists $para{ext}){
547 0 0         if ($i=~ m/\.$ext$/i){$ok=1}else{$ok=0};
  0            
  0            
548             };
549              
550 0 0         if ($ok == 1){push @nf,$i};
  0            
551             }
552 0           @$dir_ref=@nf;
553 0           undef @nf;
554              
555             }
556            
557            
558            
559              
560              
561              
562            
563              
564             sub _putFile{
565 0     0     my $self=shift;
566 0           my $file=shift;
567 0           my $text=shift;
568              
569 0           my $fh=new FileHandle;
570 0           open($fh,'>',"$file");
571             # lockh($fh);
572 0           print $fh $text;
573             # unlockh($fh);
574 0           close($fh);
575             }
576              
577              
578             # This class may scan the perl code.
579             # But it is called automatically when importing a perl code.
580             sub scanArray{
581 0     0 1   my $self=shift;
582 0 0         my $arr=shift or die "Arrayref expected";
583 0           my $file=shift;
584 0           $self->{'STATE'} = 'head';
585            
586            
587             ## reverse read
588 0           for (my $i=0;$i < scalar(@$arr); $i++){
589 0           my $p=scalar(@$arr)-1-$i;
590              
591 0           my $writeOut = 1;
592            
593 0           my $line = $arr->[$p];
594              
595 0 0 0       if ((($line=~ m/^\s*\#/) || ($p == 0)) && ($self->{'STATE'} eq 'headwait')){ ## last line of body
    0 0        
      0        
      0        
596 0           $self->{'STATE'} = 'head';
597             }elsif((($line=~ m/^\s*$/) || ($p == 0)) && ($self->{'STATE'} eq 'head')){ ## last line of body
598 0           $self->{'STATE'} = 'bodywait';
599              
600             ## collected doxy params? then rewrite methodline
601 0 0 0       if ((exists $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'doxyparamline'}) && (scalar(@{ $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'doxyparamline'} }) > 0)){
  0            
602              
603 0           my $methodlinerest = $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'methodlinerest'};
604              
605 0 0         if ($methodlinerest !~ /\{\s+.+/){ ## dont overwrite existing line
606 0           my @param;
607 0           foreach my $l (@{ $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'doxyparamline'} }){
  0            
608 0           $l =~ m/^([^\s]+)/;
609 0           my $firstword = $1;
610 0 0         if ($firstword !~ m/^[\$\@\%]/){$firstword='$'.$firstword}; # scalar is fallback if nothing given
  0            
611 0           push @param, $firstword;
612             }
613            
614 0   0       my $retparam = $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'doxyreturn'} || 'void';
615              
616 0           my $newmethodlinerest = sprintf("{ # %s (%s)", $retparam, join(", ",@param));
617 0           $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'methodlinerest'} = $newmethodlinerest;
618             }
619              
620             }
621              
622             }
623            
624              
625              
626 0 0 0       if (($self->{'STATE'} eq 'headwait') && ($line!~ m/^\s*$/) && ($line!~ m/^\s*\#/)){
      0        
627 0           $self->{'STATE'}='free';
628             }
629              
630              
631 0 0 0       if ((($line=~ m/^\s*\}/) || ($p == 0) || ($line=~ m/^\s*sub [^ ]+/)) && ($self->{'STATE'}=~ m/^(head|headwait|bodywait|free)$/)){ ## last line of body
      0        
632 0           $self->_clearBodyBuffer();
633 0           $self->{'STATE'} = 'body';
634 0           $self->_addHeadBufferToAttr();
635             }
636              
637             # a hack for doxy gen, which rewrites the methodline
638             # doxy @return
639 0 0         if ($self->{'STATE'} eq 'head'){
640 0 0         if ($line=~ m/^\s*#\s*\@return\s+(.*)/){
641 0           my $retline = $1; # also containts description, which is not used at the moment
642 0           $retline =~ m/([^\s]+)(.*)/;
643 0           my $retval = $1;
644 0           my $desc = $2;
645              
646 0 0         if ($retval !~ m/^[\$\@\%]/){$retval='$'.$retval}; # scalar is fallback if nothing given
  0            
647              
648 0 0         if (exists $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'returnline'}){
649 0           $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'methodlinerest'} =~ s/(\s*\#\s*)([^\s]+) /$1$retval/; # remove/replace value behind "sub {" declaration
650             }else{
651 0           $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'methodlinerest'} = $retval;
652             }
653            
654 0           $self->_addLineToHeadBuffer("");
655 0           $self->_addLineToHeadBuffer("returns $desc");
656 0           $self->_addLineToHeadBuffer("");
657 0           $writeOut = 0;
658              
659 0           $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'doxyreturn'} = $retval;
660             }
661              
662 0 0         if ($line=~ m/^\s*#\s*\@brief\s+(.*)/){ ## removes the @brief word
663 0           my $text = $1;
664 0           $self->_addLineToHeadBuffer($text);
665 0           $writeOut = 0;
666             }
667              
668 0 0         if ($line=~ m/^\s*#\s*\@param\s+(.*)/){ ## creates a param text.
669 0           my $text = $1;
670 0           $self->_addLineToHeadBuffer("");
671 0           $self->_addLineToHeadBuffer("parameter: $text");
672 0           $self->_addLineToHeadBuffer("");
673 0           $writeOut = 0;
674              
675 0   0       $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'doxyparamline'} ||= [];
676 0           push @{ $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'doxyparamline'} }, $text;
  0            
677             }
678              
679             }
680              
681              
682              
683             ## list items
684 0 0 0       if ( ($self->{'STATE'} eq 'head') || ($self->{'STATE'} eq 'free') ){
685              
686 0 0         if ($line=~ m/^\s*#\s*-\s+(.*)/){ # minus
    0          
687 0           my $text = $1;
688              
689 0 0         if ( $self->{'SUB_STATE'} ne 'listitem' ){
690 0           $self->{'SUB_STATE'} = 'listitem';
691              
692 0           $self->_addLineToHeadBuffer("=back"); # from down to top
693 0           $self->_addLineToHeadBuffer("");
694             }
695              
696              
697 0           $self->_addLineToHeadBuffer($text);
698 0           $self->_addLineToHeadBuffer("=item *");
699              
700 0           $line = undef;
701            
702             }elsif( $self->{'SUB_STATE'} eq 'listitem' ){
703 0           $self->_addLineToHeadBuffer("=over");
704 0           $self->_addLineToHeadBuffer("");
705 0           delete $self->{'SUB_STATE'};
706             }
707              
708             }
709              
710              
711              
712              
713 0 0         if ($line=~ m/^\s*sub [^ ]+/){ ## head line
714 0           $self->_clearHeadBuffer();
715 0           $self->_setMethodLine($line);
716 0           $self->{'STATE'} = 'headwait';
717 0           $self->_addBodyBufferToAttr();
718 0           $self->_setMethodAttr($self->_getMethodName(),'returnline',$self->_getMethodReturn());
719 0           $self->_setMethodReturn(undef);
720             }
721              
722 0 0         if ($writeOut){
723 0 0         if ($self->{'STATE'} eq 'head'){
    0          
724 0           $self->_addLineToHeadBuffer($line);
725             }elsif($self->{'STATE'} eq 'body'){
726 0           $self->_addLineToBodyBuffer($line);
727             }
728             }
729            
730 0 0         if ($line=~ m/^\s*package ([^\;]+)\;(.*)/){
731 0           $self->{'PKGNAME'}=$1;
732 0           $self->{'PKGNAME_DESC'}=$2;
733 0           $self->{'PKGNAME_DESC'}=~ s/^\s*\#*//g;
734             }
735              
736 0 0         if ($line=~ m/^\s*use +([^\; ]+)[\; ](.*)/){
737 0   0       $self->{'REQUIRES'} = $self->{'REQUIRES'} || [];
738 0           my $name=$1;
739 0           my $rem=$2;
740 0           $rem=~ s/^[^\#]*\#*//;
741 0           push @{$self->{'REQUIRES'}},{'name'=>$name,'desc'=>$rem};
  0            
742             }
743              
744              
745 0 0 0       if (($line=~ m/^\s*use base +([^\; ]+)[\;](.*)/) ||
746             ($line=~ m/^\s*our +\@ISA +([^\; ]+)[\;](.*)/)){
747 0   0       $self->{'INHERITS_FROM'} = $self->{'INHERITS_FROM'} || [];
748 0           my $name=$1;
749 0           my $rem=$2;
750 0           $name=~ s/qw\(//g;
751 0           $name=~ s/[\)\']//g;
752 0           my @n=split(/ +/,$name);
753 0           foreach my $n (@n){
754 0 0         push @{$self->{'INHERITS_FROM'}},{'name'=>$n} if $n;
  0            
755             }
756             }
757            
758             #print $line.' - '.$self->{'STATE'};
759             }
760            
761            
762 0 0 0       if ((exists $self->{'METHOD_ATTR'}->{'new'}) || (scalar($self->{'INHERITS_FROM'}) >= 1 )){ ## its a class!
763 0           $self->{'ISCLASS'}=1;
764             }
765            
766            
767 0 0         if (!exists $self->{'PKGNAME'}){
768 0           my $filet=$file;
769 0           $filet =~ s/\.pm//g;
770 0           $filet =~ s|/|::|g;
771 0           $self->{'PKGNAME'}=$filet;
772 0           $self->{'PKGNAME_DESC'}=$filet;
773             }
774              
775             # print Dumper($self->{'METHOD_ATTR'});
776 0           $self->_analyseAttributes();
777              
778              
779 0           $self->_scanDescription($arr);
780              
781              
782             #print Dumper($self->{'METHOD_ATTR'});
783              
784            
785             }
786              
787              
788              
789              
790             sub _scanDescription{
791 0     0     my $self=shift;
792 0 0         my $arr=shift or die "Arrayref expected";
793            
794 0           $self->{'STATE'} = 'head';
795            
796 0           my @text;
797            
798 0           my $state='wait';
799 0           for (my $i=0;$i < scalar(@$arr); $i++){
800            
801 0           my $line = $arr->[$i];
802            
803 0 0 0       if (($line=~ m/^\s*\#+(.*)/) && ($state=~ m/^(wait|rem)$/)){
    0 0        
804 0           $state='rem';
805 0           $line=~ m/^\s*\#+(.*)/;
806 0           my $text=$1;
807              
808             # doxy @brief in head
809 0 0         if ($text=~ m/^\s*\@brief\s+(.*)/i){
810 0           $text = $1;
811             }
812              
813              
814 0           push @text,$text;
815            
816             }elsif(($line!~ m/^\s*\#+(.*)/) && ($state=~ m/^(rem)$/)){
817 0           $state='done';
818             }
819            
820             }
821            
822            
823 0           my $more = $self->_findOwnTitlesInArray(array=>\@text, default=>'DESCRIPTION');
824            
825 0           $self->{'MORE'} = $more;
826              
827             }
828              
829              
830              
831              
832              
833             sub _findOwnTitlesInArray{
834 0     0     my $self=shift;
835 0           my $v={@_};
836 0 0         my $arr=$v->{'array'} or die "Array expected";
837 0           my $default=$v->{'default'};
838 0           my $morearr={};
839              
840 0           $self->_prepareArrayText(array=>$arr);
841              
842 0           my $area = $default;
843              
844 0           my $nextok=0;
845 0           for (my $i=0;$i < scalar(@$arr); $i++){
846              
847 0           my $line = $arr->[$i];
848 0           my $next = $arr->[$i+1];
849            
850             ## is introduction?
851 0 0         if ($next=~ m/^\s*(\={3,50})/){ ## find a ==== bar
852 0           my $l=length($1);
853 0           $area=$self->_trim($line);
854 0           $nextok=$i+2; ## skip next 2 rows
855             }
856            
857 0 0         if ($i >= $nextok){
858 0   0       $morearr->{$area} = $morearr->{$area} || [];
859 0           push @{$morearr->{$area}},$line;
  0            
860             }
861              
862             }
863            
864            
865 0           return $morearr;
866             }
867              
868              
869              
870              
871              
872              
873             sub _addLineToHeadBuffer{
874 0     0     my $self=shift;
875 0           my $line=shift;
876              
877 0           $line = $self->_trim($line);
878              
879 0   0       $self->{'HEAD'} = $self->{'HEAD'} || [];
880            
881 0           unshift @{$self->{'HEAD'}},$line;
  0            
882            
883              
884             }
885              
886              
887              
888              
889             sub _addLineToBodyBuffer{
890 0     0     my $self=shift;
891 0           my $line=shift;
892              
893 0           $line = $self->_trim($line);
894              
895 0 0         if ($line=~ m/^\s*return (.*)/){
896 0 0         if (!$self->_getMethodReturn){
897 0           $self->_setMethodReturn($line);
898             }
899             }
900              
901              
902 0   0       $self->{'BODY'} = $self->{'BODY'} || [];
903            
904 0           unshift @{$self->{'BODY'}},$line;
  0            
905            
906              
907             }
908              
909              
910              
911             sub _clearBodyBuffer{
912 0     0     my $self=shift;
913 0           my $line=shift;
914              
915 0           $line = $self->_trim($line);
916              
917 0           $self->{'BODY'} = [];
918              
919             }
920              
921              
922              
923              
924             sub _clearHeadBuffer{
925 0     0     my $self=shift;
926 0           my $line=shift;
927              
928 0           $line = $self->_trim($line);
929              
930 0           $self->{'HEAD'} = [];
931              
932             }
933              
934              
935             sub _addHeadBufferToAttr{
936 0     0     my $self=shift;
937              
938 0           my $m = $self->_getMethodName();
939 0 0         if ($m){
940 0           $self->_setMethodAttr($m,'head',$self->{'HEAD'})
941             }
942             }
943              
944              
945              
946             sub _addBodyBufferToAttr{
947 0     0     my $self=shift;
948              
949 0           my $m = $self->_getMethodName();
950 0           $self->_setMethodAttr($m,'body',$self->{'BODY'})
951             }
952              
953              
954              
955              
956             sub _setMethodLine{
957 0     0     my $self=shift;
958 0           my $s=shift;
959              
960 0           $s = $self->_trim($s);
961            
962 0 0         if ($s=~ m/sub ([^ \{]+)(.*)/){
963 0           $self->_setMethodName($1);
964 0           $self->_setMethodAttr($1,'methodlinerest',$2);
965             }
966              
967              
968 0           $self->{'METHOD_LINE'}=$s;
969             }
970              
971              
972              
973             sub _getMethodLine{
974 0     0     my $self=shift;
975              
976 0           return $self->{'METHOD_LINE'};
977             }
978              
979              
980              
981             sub _setMethodName{
982 0     0     my $self=shift;
983 0           my $s=shift;
984              
985              
986 0           $self->{'METHOD_NAME'}=$s;
987             }
988              
989              
990              
991              
992              
993             sub _getMethodReturn{
994 0     0     my $self=shift;
995              
996 0           return $self->{'METHOD_RETURN'};
997             }
998              
999              
1000              
1001             sub _setMethodReturn{
1002 0     0     my $self=shift;
1003 0           my $s=shift;
1004              
1005              
1006 0           $self->{'METHOD_RETURN'}=$s;
1007             }
1008              
1009              
1010              
1011              
1012              
1013             sub _getMethodName{
1014 0     0     my $self=shift;
1015              
1016              
1017 0           return $self->{'METHOD_NAME'};
1018             }
1019              
1020              
1021              
1022              
1023             sub _setMethodAttr{
1024 0     0     my $self=shift;
1025 0           my $name=shift;
1026 0           my $k=shift;
1027 0           my $s=shift;
1028              
1029 0           $self->{'METHOD_ATTR'}->{$name}->{$k}=$s;
1030             }
1031              
1032              
1033              
1034              
1035              
1036             sub _trim{
1037 0     0     my $self=shift;
1038 0           my $s=shift;
1039              
1040 0 0         if (ref $s){
1041              
1042 0           $$s=~ s/^\s*//;
1043 0           $$s=~ s/\s*$//;
1044            
1045             }else{
1046              
1047 0           $s=~ s/^\s*//;
1048 0           $s=~ s/\s*$//;
1049              
1050 0           return $s;
1051             }
1052            
1053             }
1054              
1055              
1056              
1057              
1058              
1059             sub _analyseAttributes{
1060 0     0     my $self=shift;
1061 0           my $attr = $self->{'METHOD_ATTR'};
1062              
1063              
1064 0           foreach my $method (keys %$attr){
1065 0           my $mat=$attr->{$method};
1066            
1067 0           $self->_analyseAttributes_Method(attributes=>$mat,method=>$method);
1068 0           $self->_analyseAttributes_Head(attributes=>$mat,method=>$method);
1069             }
1070            
1071            
1072             }
1073              
1074              
1075              
1076              
1077              
1078             sub _analyseAttributes_Method{
1079 0     0     my $self=shift;
1080 0           my $v={@_};
1081 0           my $method=$v->{'method'};
1082 0           my $mat=$v->{'attributes'};
1083              
1084              
1085 0           my $mrest = $mat->{'methodlinerest'};
1086 0           $mrest=~ s/^[^\#]+\#*//;
1087 0           $mat->{'methodlinecomment'}=$mrest;
1088              
1089 0           my ($re,$at) = split(/\(/,$mrest,2);
1090 0           $at=~ s/\)//;
1091              
1092              
1093 0           $mat->{'returntypes'} = $self->_getTypeTreeByLine($re);
1094 0           $mat->{'attributetypes'} = $self->_getTypeTreeByLine($at);
1095              
1096            
1097             }
1098              
1099              
1100              
1101              
1102              
1103              
1104              
1105              
1106             sub _analyseAttributes_Head{
1107 0     0     my $self=shift;
1108 0           my $v={@_};
1109 0           my $method=$v->{'method'};
1110 0           my $mat=$v->{'attributes'};
1111              
1112              
1113 0           $self->_prepareArrayText(array=>$mat->{'head'});
1114              
1115             }
1116              
1117              
1118              
1119              
1120             sub _prepareArrayText{
1121 0     0     my $self=shift;
1122 0           my $v={@_};
1123 0           my $array=$v->{'array'};
1124              
1125             #print Dumper($array);
1126             ## removes rem and gap before rows
1127              
1128 0           my $space=99;
1129 0           foreach my $h (@{$array}){
  0            
1130            
1131 0           $h=~ s/^\#+//; ## remove remarks
1132            
1133 0 0         if ($h!~ m/^(\s*)$/){
1134 0           $h=~ m/^( +)[^\s]/;
1135 0           my $l=length($1);
1136 0 0 0       if (($l >0) && ($l < $space)){
1137 0           $space=$l
1138             }
1139             }
1140             }
1141              
1142              
1143 0 0         if ($space != 99){
1144 0           foreach my $h (@{$array}){
  0            
1145 0           $h=~ s/^\s{0,$space}//;
1146             }
1147             }
1148              
1149              
1150             }
1151              
1152              
1153              
1154              
1155              
1156              
1157             sub _getTypeTreeByLine{
1158 0     0     my $self=shift;
1159 0           my $line=shift;
1160              
1161            
1162 0           my @re = split(/\,/,$line);
1163            
1164 0           my @rettype;
1165 0           foreach my $s (@re){
1166 0           $s=$self->_trim($s);
1167              
1168              
1169 0           my @or = split(/\|/,$s);
1170 0           my @orelems;
1171 0           my $elem={};
1172            
1173 0           foreach my $o (@or){
1174 0           my $name;
1175             my $type;
1176 0           my $typevalue;
1177            
1178 0 0         if ($o=~ m/^([^ ]+)\s*\=\>\s*([^ ]+)$/){
    0          
    0          
    0          
1179 0           $type='keyvalue';
1180 0           $name=$1;
1181 0           $typevalue=$2;
1182            
1183             }elsif ($o=~ m/^([^ ]+) ([^ ]+)$/){
1184 0           $type=lc($1);
1185 0           $name=$2;
1186             }elsif ($o=~ m/^([^ \$\%\@]+)$/){
1187 0           $type=lc($1);
1188             }elsif ($o=~ m/^([\$\%\@\\]+)(.*)$/){
1189 0           my $typec=$1;
1190 0           my $namec=$2;
1191            
1192 0 0         if ($typec eq '$'){$type='scalar'}
  0            
1193 0 0         if ($typec eq '\$'){$type='scalarref'}
  0            
1194 0 0         if ($typec eq '%'){$type='hash'}
  0            
1195 0 0         if ($typec eq '\%'){$type='hashref'}
  0            
1196 0 0         if ($typec eq '@'){$type='array'}
  0            
1197 0 0         if ($typec eq '\@'){$type='arrayref'}
  0            
1198 0 0         if ($typec eq '&'){$type='method'}
  0            
1199 0 0         if ($typec eq '\&'){$type='method'}
  0            
1200              
1201 0   0       $name=$namec || $type;
1202             }
1203            
1204 0           $elem = {name=>$name,type=>$type,typevalue=>$typevalue};
1205 0           push @orelems, $elem;
1206             }
1207              
1208            
1209              
1210 0           push @rettype,\@orelems;
1211             }
1212            
1213            
1214 0           return \@rettype;
1215             }
1216              
1217              
1218              
1219              
1220              
1221             # Builds the pod. Called automatically when imporing a perl code.
1222             sub buildPod{
1223 0     0 1   my $self=shift;
1224 0           my $attr = $self->{'METHOD_ATTR'};
1225              
1226 0           $self->{'POD_PARTS'}={};
1227              
1228 0           $self->_buildPod_Name();
1229 0           $self->_buildPod_Methods();
1230 0           $self->_buildPod_Requires();
1231 0           $self->_buildPod_Inherits();
1232 0           $self->_buildPod_More();
1233              
1234              
1235 0           $self->_buildPodText();
1236              
1237             }
1238              
1239              
1240              
1241              
1242              
1243             sub _buildPod_Requires{
1244 0     0     my $self=shift;
1245              
1246 0   0       my $re=$self->{'REQUIRES'} || [];
1247              
1248              
1249 0           my %dontshow;
1250 0           my @dontshow = qw(vars strict warnings libs base);
1251 0           map {$dontshow{$_}=1} @dontshow;
  0            
1252              
1253 0           my $node = node->root;
1254              
1255 0           $node->push( node->head1("REQUIRES") );
1256            
1257 0 0         if (scalar(@$re) > 0){
1258              
1259              
1260 0           foreach my $e (@$re){
1261              
1262 0           my $name=$e->{'name'};
1263 0           my $desc=$e->{'desc'};
1264              
1265 0 0         if (!$dontshow{$name}){
1266              
1267 0           $desc=$self->_trim($desc);
1268 0           my $text = "L<$name> $desc\n\n";
1269 0 0         if ($name ne $self->{'PKGNAME'}){
1270 0           $node->push( node->text($text));
1271             }
1272             }
1273             }
1274            
1275 0           $self->{'POD_PARTS'}->{'REQUIRES'} = $node;
1276             }
1277              
1278             }
1279              
1280              
1281              
1282              
1283              
1284             sub _buildPod_Inherits{
1285 0     0     my $self=shift;
1286              
1287 0   0       my $re=$self->{'INHERITS_FROM'} || [];
1288              
1289 0           my %dontshow;
1290 0           my @dontshow = qw(vars strict warnings libs base);
1291 0           map {$dontshow{$_}=1} @dontshow;
  0            
1292              
1293 0           my $node = node->root;
1294              
1295 0           $node->push( node->head1("IMPLEMENTS") );
1296            
1297 0 0         if (scalar(@$re) > 0){
1298              
1299              
1300 0           foreach my $e (@$re){
1301              
1302 0           my $name=$e->{'name'};
1303 0           my $desc=$e->{'desc'};
1304              
1305 0 0         if (!$dontshow{$name}){
1306              
1307 0           $desc=$self->_trim($desc);
1308 0           my $text = "L<$name> $desc\n\n";
1309              
1310 0           $node->push( node->text($text));
1311             }
1312             }
1313            
1314 0           $self->{'POD_PARTS'}->{'IMPLEMENTS'} = $node;
1315             }
1316              
1317             }
1318              
1319              
1320              
1321              
1322             sub _buildPodText{
1323 0     0     my $self=shift;
1324              
1325 0           my $parts=$self->{'POD_PARTS'};
1326              
1327 0           my @text;
1328              
1329 0           my @first = qw(NAME SYNOPSIS DESCRIPTION REQUIRES IMPLEMENTS EXPORTS HOWTO NOTES METHODS);
1330 0           my @last = ('CAVEATS','TODO','TODOS','SEE ALSO','AUTHOR','COPYRIGHT','LICENSE','COPYRIGHT AND LICENSE');
1331              
1332 0           my @own = keys %{$parts};
  0            
1333 0           my @free;
1334 0           push @own,@first;
1335 0           push @own,@last;
1336            
1337 0           my %def;
1338 0           map {$def{$_}=1} @first;
  0            
1339 0           map {$def{$_}=1} @last;
  0            
1340            
1341 0           foreach my $n (@own){
1342 0 0         if (!exists $def{$n}){push @free,$n};
  0            
1343             }
1344              
1345 0           my @all;
1346 0           push @all,@first,@free,@last;
1347              
1348 0           foreach my $area (@all){
1349 0 0         if (exists $parts->{$area}){
1350 0           push @text,$parts->{$area}->pod;
1351             }
1352             }
1353            
1354            
1355              
1356            
1357 0           my $node = node->root;
1358 0           $node->push( node->cut );
1359 0           push @text,$node->pod;
1360            
1361 0           my $text=join("\n",@text);
1362              
1363 0           $self->{"POD_TEXT"} = $text;
1364             }
1365              
1366              
1367              
1368              
1369              
1370             sub _buildPod_Name{
1371 0     0     my $self=shift;
1372 0           my $attr = $self->{'METHOD_ATTR'};
1373 0           my $name = $self->{'PKGNAME'};
1374              
1375 0           my $node = node->root;
1376              
1377 0           $node->push( node->head1("NAME") );
1378            
1379 0           my @name;
1380            
1381 0           push @name,$self->{'PKGNAME'};
1382 0 0         push @name,$self->_trim($self->{'PKGNAME_DESC'}) if $self->{'PKGNAME_DESC'};
1383            
1384 0           my $namestr = join(" - ",@name)."\n\n";
1385              
1386              
1387 0           $node->push( node->text($namestr));
1388              
1389              
1390 0           $self->{'POD_PARTS'}->{'NAME'} = $node;
1391              
1392             }
1393              
1394              
1395              
1396              
1397              
1398              
1399              
1400             sub _buildPod_More{
1401 0     0     my $self=shift;
1402 0           my $attr = $self->{'METHOD_ATTR'};
1403              
1404              
1405              
1406 0           my $more = $self->{'MORE'};
1407              
1408 0           foreach my $area (keys %$more){
1409              
1410 0           my $node = node->root;
1411            
1412 0           my $desc=$more->{$area};
1413             # length(@$desc) throws an error on newer perl, so use scalar(@$desc) instead. NW
1414 0 0         if (scalar(@$desc) > 0){
1415            
1416 0           $node->push( node->head1("$area") );
1417 0           $node->push( node->text( join("\n",@$desc)."\n\n" ));
1418            
1419             }
1420              
1421 0           $self->{'POD_PARTS'}->{$area} = $node;
1422             }
1423              
1424              
1425             }
1426              
1427              
1428              
1429              
1430              
1431              
1432             sub _buildPod_Methods{
1433 0     0     my $self=shift;
1434 0           my $attr = $self->{'METHOD_ATTR'};
1435              
1436 0           my $node = node->root;
1437              
1438 0           $node->push( node->head1("METHODS") );
1439              
1440             ## sort alphabeticaly
1441 0           my @methods = keys %$attr;
1442 0           @methods = sort @methods;
1443              
1444 0 0         if (exists $attr->{'new'}){ ## constructor first
1445 0           $self->_buildPod_Methods_addMethod(node=>$node,method=>'new');
1446             }
1447              
1448 0           foreach my $method (@methods){
1449              
1450 0           my $ok = 1;
1451              
1452 0 0         if ($method eq ''){$ok=0};
  0            
1453              
1454 0 0         if ($method=~ m/^\_/){
1455 0           $ok=0;
1456 0 0         if ($self->{'alsohiddenmethods'}){$ok=1};
  0            
1457             }
1458              
1459 0 0         if ($ok){
1460 0 0         if ($method ne 'new'){
1461 0           $self->_buildPod_Methods_addMethod(node=>$node,method=>$method);
1462             }
1463             }
1464            
1465             }
1466              
1467            
1468 0           $self->{'POD_PARTS'}->{'METHODS'} = $node;
1469             }
1470              
1471              
1472              
1473              
1474             sub _buildPod_Methods_addMethod{
1475 0     0     my $self=shift;
1476 0           my $v={@_};
1477 0           my $node=$v->{'node'};
1478 0           my $method=$v->{'method'};
1479 0           my $attr = $self->{'METHOD_ATTR'};
1480 0           my $mat=$attr->{$method};
1481              
1482 0           my $selfstring='';
1483 0 0         if ($self->{'ISCLASS'}){
1484 0           $selfstring=$self->{'selfstring'}.'->';
1485             }
1486            
1487              
1488             ## method name
1489 0           $node->push( node->head2("$method") );
1490              
1491              
1492             ## how to call
1493              
1494 0           my $retstring = $self->_buildParamString(params=>$mat->{'returntypes'}, braces=>1,separatorand=>', ',separatoror=>' | ');
1495 0           my $paramstring = $self->_buildParamString(params=>$mat->{'attributetypes'}, braces=>0,separatorand=>', ',separatoror=>' | ');
1496              
1497 0           my $addit=0;
1498 0 0         if ($retstring){
    0          
1499 0           $retstring = " my $retstring = $selfstring$method($paramstring);";
1500 0           $addit=1;
1501             }elsif($paramstring){
1502 0           $retstring = " $selfstring$method($paramstring);";
1503 0           $addit=1;
1504             }else{
1505 0           $retstring = " $selfstring$method();";
1506 0           $addit=1;
1507             }
1508              
1509              
1510 0 0         if ($addit){
1511 0           $retstring.="\n\n";
1512 0           $node->push( node->text($retstring) );
1513             }
1514              
1515              
1516             ### head text
1517              
1518 0           my $text;
1519 0 0         if ($mat->{'head'}){
1520 0           $text = join("\n",@{ $mat->{'head'} }); ## I added the return here, which is necessary using example codes before methods
  0            
1521 0 0         if ($text){$text.="\n\n\n"};
  0            
1522            
1523 0           $node->push( node->text($text) );
1524             }
1525            
1526              
1527              
1528             }
1529              
1530              
1531              
1532             sub _buildParamString{
1533 0     0     my $self=shift;
1534 0           my $v={@_};
1535 0           my $params=$v->{'params'};
1536 0           my $braces=$v->{'braces'};
1537 0   0       my $separatorand=$v->{'separatorand'} || ',';
1538 0   0       my $separatoror=$v->{'separatoror'} || '|';
1539 0           my $text='';
1540              
1541              
1542 0 0 0       if ((exists $params->[0]->[0]->{'type'}) && ($params->[0]->[0]->{'type'} eq 'void')){return};
  0            
1543              
1544 0           my @and;
1545 0           foreach my $arra (@$params){
1546              
1547 0           my @or;
1548 0           foreach my $e (@$arra){
1549            
1550 0           my $name = $e->{'name'};
1551 0           my $type = $e->{'type'};
1552            
1553 0   0       my $wname = $name || $type;
1554            
1555 0 0         if ($type ne 'keyvalue'){
1556 0           my $ctype=$self->_typeToChar($type);
1557 0           push @or,"$ctype$wname";
1558             }else{
1559 0           my $typev = $e->{'typevalue'};
1560 0           my $ctype=$self->_typeToChar($typev);
1561 0           push @or,"$name => $ctype$typev";
1562             }
1563            
1564             }
1565            
1566 0           push @and,join($separatoror,@or);
1567             }
1568            
1569 0           $text=join($separatorand,@and);
1570              
1571 0 0 0       if ((scalar(@$params) > 1) && ($braces)){
1572 0           $text="($text)";
1573             }
1574              
1575 0           return $text;
1576             }
1577              
1578              
1579              
1580             sub _typeToChar{
1581 0     0     my $self=shift;
1582 0           my $type=shift;
1583 0           my $c='';
1584              
1585 0           my $m = { 'array' => '@',
1586             'arrayref' => '\@',
1587             'hash' => '%',
1588             'hashref' => '\%',
1589             'method' => '&',
1590             'scalar' => '$',
1591             'scalarref' => '\$',
1592             };
1593              
1594 0   0       $c=$m->{$type} || $c;
1595              
1596 0           return $c;
1597             }
1598              
1599              
1600              
1601              
1602              
1603             sub _makeDirRecursive{
1604 0     0     my $dir=shift;
1605 0           my $path;
1606              
1607 0 0         if (!-e $dir){
1608              
1609 0           my @path=split(/\//,$dir);
1610 0           foreach my $p (@path){
1611 0 0         if (!-e $path.$p){
1612 0           mkdir $path.$p;
1613             # print "CREATE: ".$path.$p."\n";
1614             }
1615 0           $path.=$p.'/';
1616             }
1617              
1618             }
1619             }
1620              
1621              
1622              
1623              
1624             sub _extractPath{
1625 0     0     my $p=shift;
1626              
1627 0 0         if ($p=~ m/\//){
1628 0           $p=~ s/(.*)\/(.*)$/$1/;
1629             }else{
1630 0 0         if ($p=~ m/^\.*$/){ # only ".."
1631 0           $p=$p; ## nothing to do
1632             }else{
1633 0           $p='';
1634             }
1635             }
1636              
1637 0           return $p;
1638             }
1639              
1640              
1641              
1642              
1643              
1644             1;
1645              
1646              
1647              
1648              
1649              
1650              
1651              
1652              
1653              
1654              
1655              
1656             #################### pod generated by Pod::Autopod - keep this line to make pod updates possible ####################
1657              
1658             =head1 NAME
1659              
1660             Pod::Autopod - Generates pod documentation by analysing perl modules.
1661              
1662              
1663             =head1 SYNOPSIS
1664              
1665              
1666             use Pod::Autopod;
1667              
1668             new Pod::Autopod(readfile=>'Foo.pm', writefile=>'Foo2.pm');
1669              
1670             # reading Foo.pm and writing Foo2.pm but with pod
1671              
1672              
1673             my $ap = new Pod::Autopod(readfile=>'Foo.pm');
1674             print $ap->getPod();
1675              
1676             # reading and Foo.pm and prints the generated pod.
1677              
1678             my $ap = new Pod::Autopod();
1679             $ap->setPerlCode($mycode);
1680             print $ap->getPod();
1681             $ap->writeFile('out.pod');
1682              
1683             # asumes perl code in $mycoce and prints out the pod.
1684             # also writes to the file out.pod
1685              
1686              
1687              
1688              
1689             =head1 DESCRIPTION
1690              
1691             This Module is designed to generate pod documentation of a perl class by analysing its code.
1692             The idea is to have something similar like javadoc. So it uses also comments written directly
1693             obove the method definitions. It is designed to asumes a pm file which represents a class.
1694              
1695             Of course it can not understand every kind of syntax, parameters, etc. But the plan is to improve
1696             this library in the future to understand more and more automatically.
1697              
1698             Please note, there is also an "autopod" command line util in this package.
1699              
1700              
1701              
1702              
1703             =head1 REQUIRES
1704              
1705             L
1706              
1707             L
1708              
1709             L
1710              
1711             L
1712              
1713             L
1714              
1715             L<5.006> Pod::Abstract uses features of 5.6
1716              
1717              
1718             =head1 HOWTO
1719              
1720              
1721             To add a documentation about a method, write it with a classical remark char "#"
1722             before the sub{} definition:
1723              
1724             # This method is doing foo.
1725             #
1726             # print $self->foo();
1727             #
1728             #
1729             # It is not doing bar, only foo.
1730             sub foo{
1731             ...
1732             }
1733              
1734             A gap before sub{} is allowed.
1735              
1736             In further versions of autopod, here new features will appear.
1737              
1738             To define parameters and return values you can use a boundle of keywords.
1739             So far parameters and return values can not realy be autodetected, so manual
1740             way is necessary, but it is designed to type it rapidly.
1741              
1742             sub foo{ # void ($text)
1743             ...
1744             }
1745              
1746             The example above produces the following method description:
1747              
1748             $self->foo($text);
1749              
1750             The object "$self" is the default and automatially used when a constructor was found ("new")
1751             or the class inherits with ISA or "use base".
1752             You can change this by the parameter "selfstring" in the autopod constructor.
1753              
1754             The example looks simple, but the engine does more than you think. Please have a look here:
1755              
1756             sub foo{ # void (scalar text)
1757             ...
1758             }
1759            
1760             That procudes the same output! It means the dollar sign of the first example is a symbol which means "scalar".
1761              
1762             sub foo{ # ($)
1763             ...
1764             }
1765              
1766             Produces:
1767              
1768             $self->foo($scalar);
1769              
1770             As you see, that was the quickest way to write the definition. The keywork "void" is default.
1771              
1772             The following keywords or characters are allowed:
1773              
1774             array @
1775             arrayref \@
1776             hash %
1777             hashref \%
1778             method &
1779             scalar $
1780             scalarref \$
1781             void only as return value
1782              
1783             Now a more complex example:
1784              
1785             sub foo{# $state ($firstname,$lastname,\%persondata)
1786             ...
1787             }
1788              
1789             produces:
1790              
1791             my $state = $self->foo($firstname, $lastname, \%persondata);
1792              
1793             or write it in java style:
1794              
1795             sub foo{# scalar state (scalar firstname,scalar lastname,hashref persondata)
1796             ...
1797             }
1798              
1799             Multiple return values may be displayed as following:
1800              
1801             sub foo{# $a,$b ($text)
1802             ...
1803             }
1804              
1805             produces:
1806              
1807             my ($a, $b) = $self->foo($text);
1808              
1809              
1810             If you want to use key values pairs as in a hash, you may describe it like:
1811              
1812             sub foo{# void (firstname=>$scalar,lastname=>scalar)
1813             ...
1814             }
1815              
1816             The second "scalar" above is without a "$", that is no mistake, both works.
1817              
1818             There is also a way to expain that a value A OR B is expected. See here:
1819              
1820             sub foo{# $lista|\$refb (\@list|$text,$flag)
1821             ...
1822             }
1823              
1824             procudes:
1825              
1826             my $lista | \$refb = $self->foo(\@list | $text, $flag);
1827              
1828             Of course, that is not an official perl syntax with the or "|", but it shows
1829             you that is expected.
1830              
1831              
1832             In the First Part obove all method descriptions, you can add general informations, which are
1833             per default displayed under the head item "DESCRIPTION". But also own items can be used by
1834             underlining a text with "=" chars like:
1835              
1836             # HOWTO
1837             # =====
1838             # Read here howto do it.
1839              
1840             Some of these title keywords are allways places in a special order, which you can not change. For
1841             example LICENSE is allways near the end.
1842              
1843             Added some hacks to teach this tool also some doxygen parametes. For example:
1844              
1845             # @brief kept as simple text
1846             # @param text to be added
1847             # @return string with some text
1848             sub foo{
1849             return "abc".shift;
1850             }
1851              
1852              
1853             procudes:
1854              
1855             my $string = $self->foo($text);
1856              
1857              
1858              
1859              
1860             =head1 METHODS
1861              
1862             =head2 new
1863              
1864             my $object = $self->new($filename => $scalar, alsohiddenmethods => $scalar, selfstring => $scalar);
1865              
1866             Constructor
1867              
1868             The keyvalues are not mandatory.
1869              
1870             selfstring may hold something like '$self' as alternative to '$self', which is default.
1871              
1872             alsohiddenmethods gets a boolean flag to show also methods which starts with "_".
1873              
1874              
1875              
1876             =head2 buildPod
1877              
1878             $self->buildPod();
1879              
1880             Builds the pod. Called automatically when imporing a perl code.
1881              
1882              
1883             =head2 foo
1884              
1885             $self->foo();
1886              
1887             This method is doing foo.
1888              
1889             print $self->foo();
1890              
1891              
1892             It is not doing bar, only foo.
1893              
1894              
1895             =head2 getBorderString
1896              
1897             my $scalar = $self->getBorderString();
1898              
1899             Returns the border string which delimit the perl code and pod inside a pm file.
1900              
1901              
1902             =head2 getPerlCode
1903              
1904             my $text = $self->getPerlCode();
1905              
1906             Returns perl code which was set before.
1907              
1908              
1909             =head2 getPod
1910              
1911             my $text = $self->getPod();
1912              
1913             Returns the pod formated text.s
1914              
1915              
1916             =head2 readDirectory
1917              
1918             $self->readDirectory($directory, updateonly => $scalar, pod => $scalar, verbose => $scalar);
1919              
1920             scans a directoy recoursively for pm files and may
1921             generate pod of them.
1922              
1923             You can also set the flag updateonly to build new pod
1924             only for files you already build a pod (inside the file)
1925             in the past. Alternatively you can write the magic word
1926             AUTOPODME somewhere in the pm file what signals that this
1927             pm file wants to be pod'ed by autopod.
1928              
1929             The flag pod let will build a separate file. If poddir set,
1930             the generated pod file will be saved to a deparate directory.
1931             With verbose it prints the list of written files.
1932              
1933              
1934              
1935             =head2 readFile
1936              
1937             $self->readFile($filename);
1938              
1939             Reading a Perl class file and loads it to memory.
1940              
1941              
1942             =head2 scanArray
1943              
1944             $self->scanArray();
1945              
1946             This class may scan the perl code.
1947             But it is called automatically when importing a perl code.
1948              
1949              
1950             =head2 setBorderString
1951              
1952             $self->setBorderString($borderstring);
1953              
1954             Set an alternative border string.
1955             If you change this, you have to do it again when updating the pod.
1956              
1957              
1958             =head2 setPerlCode
1959              
1960             $self->setPerlCode($text | \@array, $file);
1961              
1962             Expects Perl code as arrayref
1963             or text (scalar).
1964              
1965             When used, it automatically runs scanArray().
1966             This now passes the filename to be used in case
1967             we are podding a .pl or .cgi file. NW
1968              
1969              
1970             =head2 writeFile
1971              
1972             $self->writeFile($filename);
1973              
1974             writes a pod file
1975              
1976             If the file has a pm or pl or cgi extension, it writes the perl code and the pod
1977             If the file has a pod extension or any, it only writes the pod.
1978              
1979              
1980              
1981             =head1 AUTHOR
1982              
1983             Andreas Hernitscheck ahernit(AT)cpan.org
1984              
1985              
1986             =head1 LICENSE
1987              
1988             You can redistribute it and/or modify it under the conditions of LGPL.
1989              
1990             By the way, the source code is quite bad. So feel free to replace this idea with something better Perl OO code.
1991              
1992              
1993              
1994             =cut
1995