File Coverage

lib/Pod/Autopod.pm
Criterion Covered Total %
statement 14 668 2.1
branch 0 218 0.0
condition 0 87 0.0
subroutine 5 56 8.9
pod 11 11 100.0
total 30 1040 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.214';
3 1     1   657 use 5.006; #Pod::Abstract uses features of 5.6
  1         3  
4 1     1   531 use FileHandle;
  1         8954  
  1         6  
5 1     1   416 use strict;
  1         2  
  1         20  
6 1     1   538 use Pod::Abstract;
  1         24554  
  1         31  
7 1     1   8 use Pod::Abstract::BuildNode qw(node nodes);
  1         2  
  1         6594  
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              
579              
580              
581              
582             # This class may scan the perl code.
583             # But it is called automatically when importing a perl code.
584             sub scanArray{
585 0     0 1   my $self=shift;
586 0 0         my $arr=shift or die "Arrayref expected";
587 0           my $file=shift;
588 0           $self->{'STATE'} = 'head';
589            
590            
591             ## reverse read
592 0           for (my $i=0;$i < scalar(@$arr); $i++){
593 0           my $p=scalar(@$arr)-1-$i;
594              
595 0           my $writeOut = 1;
596            
597            
598            
599            
600 0           my $line = $arr->[$p];
601              
602 0 0 0       if ((($line=~ m/^\s*\#/) || ($p == 0)) && ($self->{'STATE'} eq 'headwait')){ ## last line of body
    0 0        
      0        
      0        
603 0           $self->{'STATE'} = 'head';
604             }elsif((($line=~ m/^\s*$/) || ($p == 0)) && ($self->{'STATE'} eq 'head')){ ## last line of body
605 0           $self->{'STATE'} = 'bodywait';
606              
607             ## collected doxy params? then rewrite methodline
608 0 0 0       if ((exists $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'doxyparamline'}) && (scalar(@{ $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'doxyparamline'} }) > 0)){
  0            
609              
610 0           my $methodlinerest = $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'methodlinerest'};
611              
612 0 0         if ($methodlinerest !~ /\{\s+.+/){ ## dont overwrite existing line
613 0           my @param;
614 0           foreach my $l (@{ $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'doxyparamline'} }){
  0            
615 0           $l =~ m/^([^\s]+)/;
616 0           my $firstword = $1;
617 0 0         if ($firstword !~ m/^[\$\@\%]/){$firstword='$'.$firstword}; # scalar is fallback if nothing given
  0            
618 0           push @param, $firstword;
619             }
620            
621 0   0       my $retparam = $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'doxyreturn'} || 'void';
622              
623 0           my $newmethodlinerest = sprintf("{ # %s (%s)", $retparam, join(", ",@param));
624 0           $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'methodlinerest'} = $newmethodlinerest;
625             }
626              
627             }
628              
629             }
630            
631              
632              
633 0 0 0       if (($self->{'STATE'} eq 'headwait') && ($line!~ m/^\s*$/) && ($line!~ m/^\s*\#/)){
      0        
634 0           $self->{'STATE'}='free';
635             }
636              
637              
638 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        
639 0           $self->_clearBodyBuffer();
640 0           $self->{'STATE'} = 'body';
641 0           $self->_addHeadBufferToAttr();
642             }
643              
644             # a hack for doxy gen, which rewrites the methodline
645             # doxy @return
646 0 0         if ($self->{'STATE'} eq 'head'){
647 0 0         if ($line=~ m/^\s*#\s*\@return\s+(.*)/){
648 0           my $retline = $1; # also containts description, which is not used at the moment
649 0           $retline =~ m/([^\s]+)(.*)/;
650 0           my $retval = $1;
651 0           my $desc = $2;
652              
653 0 0         if ($retval !~ m/^[\$\@\%]/){$retval='$'.$retval}; # scalar is fallback if nothing given
  0            
654              
655 0 0         if (exists $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'returnline'}){
656 0           $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'methodlinerest'} =~ s/(\s*\#\s*)([^\s]+) /$1$retval/; # remove/replace value behind "sub {" declaration
657             }else{
658 0           $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'methodlinerest'} = $retval;
659             }
660            
661 0           $self->_addLineToHeadBuffer("");
662 0           $self->_addLineToHeadBuffer("returns $desc");
663 0           $self->_addLineToHeadBuffer("");
664 0           $writeOut = 0;
665              
666 0           $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'doxyreturn'} = $retval;
667             }
668              
669 0 0         if ($line=~ m/^\s*#\s*\@brief\s+(.*)/){ ## removes the @brief word
670 0           my $text = $1;
671 0           $self->_addLineToHeadBuffer($text);
672 0           $writeOut = 0;
673             }
674              
675 0 0         if ($line=~ m/^\s*#\s*\@param\s+(.*)/){ ## creates a param text.
676 0           my $text = $1;
677 0           $self->_addLineToHeadBuffer("");
678 0           $self->_addLineToHeadBuffer("parameter: $text");
679 0           $self->_addLineToHeadBuffer("");
680 0           $writeOut = 0;
681              
682 0   0       $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'doxyparamline'} ||= [];
683 0           push @{ $self->{'METHOD_ATTR'}->{ $self->_getMethodName() }->{'doxyparamline'} }, $text;
  0            
684             }
685              
686             }
687              
688              
689              
690              
691              
692              
693              
694              
695              
696 0 0         if ($line=~ m/^\s*sub [^ ]+/){ ## head line
697 0           $self->_clearHeadBuffer();
698 0           $self->_setMethodLine($line);
699 0           $self->{'STATE'} = 'headwait';
700 0           $self->_addBodyBufferToAttr();
701 0           $self->_setMethodAttr($self->_getMethodName(),'returnline',$self->_getMethodReturn());
702 0           $self->_setMethodReturn(undef);
703             }
704              
705              
706            
707            
708            
709 0 0         if ($writeOut){
710 0 0         if ($self->{'STATE'} eq 'head'){
    0          
711 0           $self->_addLineToHeadBuffer($line);
712             }elsif($self->{'STATE'} eq 'body'){
713 0           $self->_addLineToBodyBuffer($line);
714             }
715             }
716            
717 0 0         if ($line=~ m/^\s*package ([^\;]+)\;(.*)/){
718 0           $self->{'PKGNAME'}=$1;
719 0           $self->{'PKGNAME_DESC'}=$2;
720 0           $self->{'PKGNAME_DESC'}=~ s/^\s*\#*//g;
721             }
722              
723 0 0         if ($line=~ m/^\s*use +([^\; ]+)[\; ](.*)/){
724 0   0       $self->{'REQUIRES'} = $self->{'REQUIRES'} || [];
725 0           my $name=$1;
726 0           my $rem=$2;
727 0           $rem=~ s/^[^\#]*\#*//;
728 0           push @{$self->{'REQUIRES'}},{'name'=>$name,'desc'=>$rem};
  0            
729             }
730              
731              
732 0 0 0       if (($line=~ m/^\s*use base +([^\; ]+)[\;](.*)/) ||
733             ($line=~ m/^\s*our +\@ISA +([^\; ]+)[\;](.*)/)){
734 0   0       $self->{'INHERITS_FROM'} = $self->{'INHERITS_FROM'} || [];
735 0           my $name=$1;
736 0           my $rem=$2;
737 0           $name=~ s/qw\(//g;
738 0           $name=~ s/[\)\']//g;
739 0           my @n=split(/ +/,$name);
740 0           foreach my $n (@n){
741 0 0         push @{$self->{'INHERITS_FROM'}},{'name'=>$n} if $n;
  0            
742             }
743             }
744            
745             #print $line.' - '.$self->{'STATE'};
746             }
747            
748            
749 0 0 0       if ((exists $self->{'METHOD_ATTR'}->{'new'}) || (scalar($self->{'INHERITS_FROM'}) >= 1 )){ ## its a class!
750 0           $self->{'ISCLASS'}=1;
751             }
752            
753            
754 0 0         if (!exists $self->{'PKGNAME'}){
755 0           my $filet=$file;
756 0           $filet =~ s/\.pm//g;
757 0           $filet =~ s|/|::|g;
758 0           $self->{'PKGNAME'}=$filet;
759 0           $self->{'PKGNAME_DESC'}=$filet;
760             }
761              
762             # print Dumper($self->{'METHOD_ATTR'});
763 0           $self->_analyseAttributes();
764              
765              
766 0           $self->_scanDescription($arr);
767              
768              
769             #print Dumper($self->{'METHOD_ATTR'});
770              
771            
772             }
773              
774              
775              
776              
777             sub _scanDescription{
778 0     0     my $self=shift;
779 0 0         my $arr=shift or die "Arrayref expected";
780            
781 0           $self->{'STATE'} = 'head';
782            
783 0           my @text;
784            
785 0           my $state='wait';
786 0           for (my $i=0;$i < scalar(@$arr); $i++){
787            
788 0           my $line = $arr->[$i];
789            
790 0 0 0       if (($line=~ m/^\s*\#+(.*)/) && ($state=~ m/^(wait|rem)$/)){
    0 0        
791 0           $state='rem';
792 0           $line=~ m/^\s*\#+(.*)/;
793 0           my $text=$1;
794              
795             # doxy @brief in head
796 0 0         if ($text=~ m/^\s*\@brief\s+(.*)/i){
797 0           $text = $1;
798             }
799              
800              
801 0           push @text,$text;
802            
803             }elsif(($line!~ m/^\s*\#+(.*)/) && ($state=~ m/^(rem)$/)){
804 0           $state='done';
805             }
806            
807             }
808            
809            
810 0           my $more = $self->_findOwnTitlesInArray(array=>\@text, default=>'DESCRIPTION');
811            
812 0           $self->{'MORE'} = $more;
813              
814             }
815              
816              
817              
818              
819              
820             sub _findOwnTitlesInArray{
821 0     0     my $self=shift;
822 0           my $v={@_};
823 0 0         my $arr=$v->{'array'} or die "Array expected";
824 0           my $default=$v->{'default'};
825 0           my $morearr={};
826              
827 0           $self->_prepareArrayText(array=>$arr);
828              
829 0           my $area = $default;
830              
831 0           my $nextok=0;
832 0           for (my $i=0;$i < scalar(@$arr); $i++){
833              
834 0           my $line = $arr->[$i];
835 0           my $next = $arr->[$i+1];
836            
837             ## is introduction?
838 0 0         if ($next=~ m/^\s*(\={3,50})/){ ## find a ==== bar
839 0           my $l=length($1);
840 0           $area=$self->_trim($line);
841 0           $nextok=$i+2; ## skip next 2 rows
842             }
843            
844 0 0         if ($i >= $nextok){
845 0   0       $morearr->{$area} = $morearr->{$area} || [];
846 0           push @{$morearr->{$area}},$line;
  0            
847             }
848              
849             }
850            
851            
852 0           return $morearr;
853             }
854              
855              
856              
857              
858              
859              
860             sub _addLineToHeadBuffer{
861 0     0     my $self=shift;
862 0           my $line=shift;
863              
864 0           $line = $self->_trim($line);
865              
866 0   0       $self->{'HEAD'} = $self->{'HEAD'} || [];
867            
868 0           unshift @{$self->{'HEAD'}},$line;
  0            
869            
870              
871             }
872              
873              
874              
875              
876             sub _addLineToBodyBuffer{
877 0     0     my $self=shift;
878 0           my $line=shift;
879              
880 0           $line = $self->_trim($line);
881              
882 0 0         if ($line=~ m/^\s*return (.*)/){
883 0 0         if (!$self->_getMethodReturn){
884 0           $self->_setMethodReturn($line);
885             }
886             }
887              
888              
889 0   0       $self->{'BODY'} = $self->{'BODY'} || [];
890            
891 0           unshift @{$self->{'BODY'}},$line;
  0            
892            
893              
894             }
895              
896              
897              
898             sub _clearBodyBuffer{
899 0     0     my $self=shift;
900 0           my $line=shift;
901              
902 0           $line = $self->_trim($line);
903              
904 0           $self->{'BODY'} = [];
905              
906             }
907              
908              
909              
910              
911             sub _clearHeadBuffer{
912 0     0     my $self=shift;
913 0           my $line=shift;
914              
915 0           $line = $self->_trim($line);
916              
917 0           $self->{'HEAD'} = [];
918              
919             }
920              
921              
922             sub _addHeadBufferToAttr{
923 0     0     my $self=shift;
924              
925 0           my $m = $self->_getMethodName();
926 0 0         if ($m){
927 0           $self->_setMethodAttr($m,'head',$self->{'HEAD'})
928             }
929             }
930              
931              
932              
933             sub _addBodyBufferToAttr{
934 0     0     my $self=shift;
935              
936 0           my $m = $self->_getMethodName();
937 0           $self->_setMethodAttr($m,'body',$self->{'BODY'})
938             }
939              
940              
941              
942              
943             sub _setMethodLine{
944 0     0     my $self=shift;
945 0           my $s=shift;
946              
947 0           $s = $self->_trim($s);
948            
949 0 0         if ($s=~ m/sub ([^ \{]+)(.*)/){
950 0           $self->_setMethodName($1);
951 0           $self->_setMethodAttr($1,'methodlinerest',$2);
952             }
953              
954              
955 0           $self->{'METHOD_LINE'}=$s;
956             }
957              
958              
959              
960             sub _getMethodLine{
961 0     0     my $self=shift;
962              
963 0           return $self->{'METHOD_LINE'};
964             }
965              
966              
967              
968             sub _setMethodName{
969 0     0     my $self=shift;
970 0           my $s=shift;
971              
972              
973 0           $self->{'METHOD_NAME'}=$s;
974             }
975              
976              
977              
978              
979              
980             sub _getMethodReturn{
981 0     0     my $self=shift;
982              
983 0           return $self->{'METHOD_RETURN'};
984             }
985              
986              
987              
988             sub _setMethodReturn{
989 0     0     my $self=shift;
990 0           my $s=shift;
991              
992              
993 0           $self->{'METHOD_RETURN'}=$s;
994             }
995              
996              
997              
998              
999              
1000             sub _getMethodName{
1001 0     0     my $self=shift;
1002              
1003              
1004 0           return $self->{'METHOD_NAME'};
1005             }
1006              
1007              
1008              
1009              
1010             sub _setMethodAttr{
1011 0     0     my $self=shift;
1012 0           my $name=shift;
1013 0           my $k=shift;
1014 0           my $s=shift;
1015              
1016 0           $self->{'METHOD_ATTR'}->{$name}->{$k}=$s;
1017             }
1018              
1019              
1020              
1021              
1022              
1023             sub _trim{
1024 0     0     my $self=shift;
1025 0           my $s=shift;
1026              
1027 0 0         if (ref $s){
1028              
1029 0           $$s=~ s/^\s*//;
1030 0           $$s=~ s/\s*$//;
1031            
1032             }else{
1033              
1034 0           $s=~ s/^\s*//;
1035 0           $s=~ s/\s*$//;
1036              
1037 0           return $s;
1038             }
1039            
1040             }
1041              
1042              
1043              
1044              
1045              
1046             sub _analyseAttributes{
1047 0     0     my $self=shift;
1048 0           my $attr = $self->{'METHOD_ATTR'};
1049              
1050              
1051 0           foreach my $method (keys %$attr){
1052 0           my $mat=$attr->{$method};
1053            
1054 0           $self->_analyseAttributes_Method(attributes=>$mat,method=>$method);
1055 0           $self->_analyseAttributes_Head(attributes=>$mat,method=>$method);
1056             }
1057            
1058            
1059             }
1060              
1061              
1062              
1063              
1064              
1065             sub _analyseAttributes_Method{
1066 0     0     my $self=shift;
1067 0           my $v={@_};
1068 0           my $method=$v->{'method'};
1069 0           my $mat=$v->{'attributes'};
1070              
1071              
1072 0           my $mrest = $mat->{'methodlinerest'};
1073 0           $mrest=~ s/^[^\#]+\#*//;
1074 0           $mat->{'methodlinecomment'}=$mrest;
1075              
1076 0           my ($re,$at) = split(/\(/,$mrest,2);
1077 0           $at=~ s/\)//;
1078              
1079              
1080 0           $mat->{'returntypes'} = $self->_getTypeTreeByLine($re);
1081 0           $mat->{'attributetypes'} = $self->_getTypeTreeByLine($at);
1082              
1083            
1084             }
1085              
1086              
1087              
1088              
1089              
1090              
1091              
1092              
1093             sub _analyseAttributes_Head{
1094 0     0     my $self=shift;
1095 0           my $v={@_};
1096 0           my $method=$v->{'method'};
1097 0           my $mat=$v->{'attributes'};
1098              
1099              
1100 0           $self->_prepareArrayText(array=>$mat->{'head'});
1101              
1102             }
1103              
1104              
1105              
1106              
1107             sub _prepareArrayText{
1108 0     0     my $self=shift;
1109 0           my $v={@_};
1110 0           my $array=$v->{'array'};
1111              
1112             #print Dumper($array);
1113             ## removes rem and gap before rows
1114              
1115 0           my $space=99;
1116 0           foreach my $h (@{$array}){
  0            
1117            
1118 0           $h=~ s/^\#+//; ## remove remarks
1119            
1120 0 0         if ($h!~ m/^(\s*)$/){
1121 0           $h=~ m/^( +)[^\s]/;
1122 0           my $l=length($1);
1123 0 0 0       if (($l >0) && ($l < $space)){
1124 0           $space=$l
1125             }
1126             }
1127             }
1128              
1129              
1130 0 0         if ($space != 99){
1131 0           foreach my $h (@{$array}){
  0            
1132 0           $h=~ s/^\s{0,$space}//;
1133             }
1134             }
1135              
1136            
1137            
1138 0           foreach my $line (@{$array}){
  0            
1139 0           my @replace;
1140            
1141             ## list items
1142 0 0         if ($line=~ m/^\s*-\s+(.*)/){ # minus
    0          
1143 0           my $text = $1;
1144              
1145 0 0         if ( $self->{'SUB_STATE'} ne 'listitem' ){
1146 0           $self->{'SUB_STATE'} = 'listitem';
1147              
1148 0           push @replace, "=over";
1149             }
1150              
1151 0           push @replace,"";
1152 0           push @replace, "=item *";
1153 0           push @replace, $text;
1154 0           push @replace,"";
1155            
1156 0           $line = undef;
1157            
1158             }elsif( $self->{'SUB_STATE'} eq 'listitem' ){
1159 0           push @replace, "=back";
1160 0           push @replace, "";
1161              
1162 0           delete $self->{'SUB_STATE'};
1163             }
1164              
1165 0 0         if (scalar(@replace) > 0){
1166 0           $line = join("\n",@replace);
1167             }
1168             }
1169              
1170            
1171            
1172             }
1173              
1174              
1175              
1176              
1177              
1178              
1179             sub _getTypeTreeByLine{
1180 0     0     my $self=shift;
1181 0           my $line=shift;
1182              
1183            
1184 0           my @re = split(/\,/,$line);
1185            
1186 0           my @rettype;
1187 0           foreach my $s (@re){
1188 0           $s=$self->_trim($s);
1189              
1190              
1191 0           my @or = split(/\|/,$s);
1192 0           my @orelems;
1193 0           my $elem={};
1194            
1195 0           foreach my $o (@or){
1196 0           my $name;
1197             my $type;
1198 0           my $typevalue;
1199            
1200 0 0         if ($o=~ m/^([^ ]+)\s*\=\>\s*([^ ]+)$/){
    0          
    0          
    0          
1201 0           $type='keyvalue';
1202 0           $name=$1;
1203 0           $typevalue=$2;
1204            
1205             }elsif ($o=~ m/^([^ ]+) ([^ ]+)$/){
1206 0           $type=lc($1);
1207 0           $name=$2;
1208             }elsif ($o=~ m/^([^ \$\%\@]+)$/){
1209 0           $type=lc($1);
1210             }elsif ($o=~ m/^([\$\%\@\\]+)(.*)$/){
1211 0           my $typec=$1;
1212 0           my $namec=$2;
1213            
1214 0 0         if ($typec eq '$'){$type='scalar'}
  0            
1215 0 0         if ($typec eq '\$'){$type='scalarref'}
  0            
1216 0 0         if ($typec eq '%'){$type='hash'}
  0            
1217 0 0         if ($typec eq '\%'){$type='hashref'}
  0            
1218 0 0         if ($typec eq '@'){$type='array'}
  0            
1219 0 0         if ($typec eq '\@'){$type='arrayref'}
  0            
1220 0 0         if ($typec eq '&'){$type='method'}
  0            
1221 0 0         if ($typec eq '\&'){$type='method'}
  0            
1222              
1223 0   0       $name=$namec || $type;
1224             }
1225            
1226 0           $elem = {name=>$name,type=>$type,typevalue=>$typevalue};
1227 0           push @orelems, $elem;
1228             }
1229              
1230            
1231              
1232 0           push @rettype,\@orelems;
1233             }
1234            
1235            
1236 0           return \@rettype;
1237             }
1238              
1239              
1240              
1241              
1242              
1243             # Builds the pod. Called automatically when imporing a perl code.
1244             sub buildPod{
1245 0     0 1   my $self=shift;
1246 0           my $attr = $self->{'METHOD_ATTR'};
1247              
1248 0           $self->{'POD_PARTS'}={};
1249              
1250 0           $self->_buildPod_Name();
1251 0           $self->_buildPod_Methods();
1252 0           $self->_buildPod_Requires();
1253 0           $self->_buildPod_Inherits();
1254 0           $self->_buildPod_More();
1255              
1256              
1257 0           $self->_buildPodText();
1258              
1259             }
1260              
1261              
1262              
1263              
1264              
1265             sub _buildPod_Requires{
1266 0     0     my $self=shift;
1267              
1268 0   0       my $re=$self->{'REQUIRES'} || [];
1269              
1270              
1271 0           my %dontshow;
1272 0           my @dontshow = qw(vars strict warnings libs base);
1273 0           map {$dontshow{$_}=1} @dontshow;
  0            
1274              
1275 0           my $node = node->root;
1276              
1277 0           $node->push( node->head1("REQUIRES") );
1278            
1279 0 0         if (scalar(@$re) > 0){
1280              
1281              
1282 0           foreach my $e (@$re){
1283              
1284 0           my $name=$e->{'name'};
1285 0           my $desc=$e->{'desc'};
1286              
1287 0 0         if (!$dontshow{$name}){
1288              
1289 0           $desc=$self->_trim($desc);
1290 0           my $text = "L<$name> $desc\n\n";
1291 0 0         if ($name ne $self->{'PKGNAME'}){
1292 0           $node->push( node->text($text));
1293             }
1294             }
1295             }
1296            
1297 0           $self->{'POD_PARTS'}->{'REQUIRES'} = $node;
1298             }
1299              
1300             }
1301              
1302              
1303              
1304              
1305              
1306             sub _buildPod_Inherits{
1307 0     0     my $self=shift;
1308              
1309 0   0       my $re=$self->{'INHERITS_FROM'} || [];
1310              
1311 0           my %dontshow;
1312 0           my @dontshow = qw(vars strict warnings libs base);
1313 0           map {$dontshow{$_}=1} @dontshow;
  0            
1314              
1315 0           my $node = node->root;
1316              
1317 0           $node->push( node->head1("IMPLEMENTS") );
1318            
1319 0 0         if (scalar(@$re) > 0){
1320              
1321              
1322 0           foreach my $e (@$re){
1323              
1324 0           my $name=$e->{'name'};
1325 0           my $desc=$e->{'desc'};
1326              
1327 0 0         if (!$dontshow{$name}){
1328              
1329 0           $desc=$self->_trim($desc);
1330 0           my $text = "L<$name> $desc\n\n";
1331              
1332 0           $node->push( node->text($text));
1333             }
1334             }
1335            
1336 0           $self->{'POD_PARTS'}->{'IMPLEMENTS'} = $node;
1337             }
1338              
1339             }
1340              
1341              
1342              
1343              
1344             sub _buildPodText{
1345 0     0     my $self=shift;
1346              
1347 0           my $parts=$self->{'POD_PARTS'};
1348              
1349 0           my @text;
1350              
1351 0           my @first = qw(NAME SYNOPSIS DESCRIPTION REQUIRES IMPLEMENTS EXPORTS HOWTO NOTES METHODS);
1352 0           my @last = ('CAVEATS','TODO','TODOS','SEE ALSO','AUTHOR','COPYRIGHT','LICENSE','COPYRIGHT AND LICENSE');
1353              
1354 0           my @own = keys %{$parts};
  0            
1355 0           my @free;
1356 0           push @own,@first;
1357 0           push @own,@last;
1358            
1359 0           my %def;
1360 0           map {$def{$_}=1} @first;
  0            
1361 0           map {$def{$_}=1} @last;
  0            
1362            
1363 0           foreach my $n (@own){
1364 0 0         if (!exists $def{$n}){push @free,$n};
  0            
1365             }
1366              
1367 0           my @all;
1368 0           push @all,@first,@free,@last;
1369              
1370 0           foreach my $area (@all){
1371 0 0         if (exists $parts->{$area}){
1372 0           push @text,$parts->{$area}->pod;
1373             }
1374             }
1375            
1376            
1377              
1378            
1379 0           my $node = node->root;
1380 0           $node->push( node->cut );
1381 0           push @text,$node->pod;
1382            
1383 0           my $text=join("\n",@text);
1384              
1385 0           $self->{"POD_TEXT"} = $text;
1386             }
1387              
1388              
1389              
1390              
1391              
1392             sub _buildPod_Name{
1393 0     0     my $self=shift;
1394 0           my $attr = $self->{'METHOD_ATTR'};
1395 0           my $name = $self->{'PKGNAME'};
1396              
1397 0           my $node = node->root;
1398              
1399 0           $node->push( node->head1("NAME") );
1400            
1401 0           my @name;
1402            
1403 0           push @name,$self->{'PKGNAME'};
1404 0 0         push @name,$self->_trim($self->{'PKGNAME_DESC'}) if $self->{'PKGNAME_DESC'};
1405            
1406 0           my $namestr = join(" - ",@name)."\n\n";
1407              
1408              
1409 0           $node->push( node->text($namestr));
1410              
1411              
1412 0           $self->{'POD_PARTS'}->{'NAME'} = $node;
1413              
1414             }
1415              
1416              
1417              
1418              
1419              
1420              
1421              
1422             sub _buildPod_More{
1423 0     0     my $self=shift;
1424 0           my $attr = $self->{'METHOD_ATTR'};
1425              
1426              
1427              
1428 0           my $more = $self->{'MORE'};
1429              
1430 0           foreach my $area (keys %$more){
1431              
1432 0           my $node = node->root;
1433            
1434 0           my $desc=$more->{$area};
1435             # length(@$desc) throws an error on newer perl, so use scalar(@$desc) instead. NW
1436 0 0         if (scalar(@$desc) > 0){
1437            
1438 0           $node->push( node->head1("$area") );
1439 0           $node->push( node->text( join("\n",@$desc)."\n\n" ));
1440            
1441             }
1442              
1443 0           $self->{'POD_PARTS'}->{$area} = $node;
1444             }
1445              
1446              
1447             }
1448              
1449              
1450              
1451              
1452              
1453              
1454             sub _buildPod_Methods{
1455 0     0     my $self=shift;
1456 0           my $attr = $self->{'METHOD_ATTR'};
1457              
1458 0           my $node = node->root;
1459              
1460 0           $node->push( node->head1("METHODS") );
1461              
1462             ## sort alphabeticaly
1463 0           my @methods = keys %$attr;
1464 0           @methods = sort @methods;
1465              
1466 0 0         if (exists $attr->{'new'}){ ## constructor first
1467 0           $self->_buildPod_Methods_addMethod(node=>$node,method=>'new');
1468             }
1469              
1470 0           foreach my $method (@methods){
1471              
1472 0           my $ok = 1;
1473              
1474 0 0         if ($method eq ''){$ok=0};
  0            
1475              
1476 0 0         if ($method=~ m/^\_/){
1477 0           $ok=0;
1478 0 0         if ($self->{'alsohiddenmethods'}){$ok=1};
  0            
1479             }
1480              
1481 0 0         if ($ok){
1482 0 0         if ($method ne 'new'){
1483 0           $self->_buildPod_Methods_addMethod(node=>$node,method=>$method);
1484             }
1485             }
1486            
1487             }
1488              
1489            
1490 0           $self->{'POD_PARTS'}->{'METHODS'} = $node;
1491             }
1492              
1493              
1494              
1495              
1496             sub _buildPod_Methods_addMethod{
1497 0     0     my $self=shift;
1498 0           my $v={@_};
1499 0           my $node=$v->{'node'};
1500 0           my $method=$v->{'method'};
1501 0           my $attr = $self->{'METHOD_ATTR'};
1502 0           my $mat=$attr->{$method};
1503              
1504 0           my $selfstring='';
1505 0 0         if ($self->{'ISCLASS'}){
1506 0           $selfstring=$self->{'selfstring'}.'->';
1507             }
1508            
1509              
1510             ## method name
1511 0           $node->push( node->head2("$method") );
1512              
1513              
1514             ## how to call
1515              
1516 0           my $retstring = $self->_buildParamString(params=>$mat->{'returntypes'}, braces=>1,separatorand=>', ',separatoror=>' | ');
1517 0           my $paramstring = $self->_buildParamString(params=>$mat->{'attributetypes'}, braces=>0,separatorand=>', ',separatoror=>' | ');
1518              
1519 0           my $addit=0;
1520 0 0         if ($retstring){
    0          
1521 0           $retstring = " my $retstring = $selfstring$method($paramstring);";
1522 0           $addit=1;
1523             }elsif($paramstring){
1524 0           $retstring = " $selfstring$method($paramstring);";
1525 0           $addit=1;
1526             }else{
1527 0           $retstring = " $selfstring$method();";
1528 0           $addit=1;
1529             }
1530              
1531              
1532 0 0         if ($addit){
1533 0           $retstring.="\n\n";
1534 0           $node->push( node->text($retstring) );
1535             }
1536              
1537              
1538             ### head text
1539              
1540 0           my $text;
1541 0 0         if ($mat->{'head'}){
1542 0           $text = join("\n",@{ $mat->{'head'} }); ## I added the return here, which is necessary using example codes before methods
  0            
1543 0 0         if ($text){$text.="\n\n\n"};
  0            
1544            
1545 0           $node->push( node->text($text) );
1546             }
1547            
1548              
1549              
1550             }
1551              
1552              
1553              
1554             sub _buildParamString{
1555 0     0     my $self=shift;
1556 0           my $v={@_};
1557 0           my $params=$v->{'params'};
1558 0           my $braces=$v->{'braces'};
1559 0   0       my $separatorand=$v->{'separatorand'} || ',';
1560 0   0       my $separatoror=$v->{'separatoror'} || '|';
1561 0           my $text='';
1562              
1563              
1564 0 0 0       if ((exists $params->[0]->[0]->{'type'}) && ($params->[0]->[0]->{'type'} eq 'void')){return};
  0            
1565              
1566 0           my @and;
1567 0           foreach my $arra (@$params){
1568              
1569 0           my @or;
1570 0           foreach my $e (@$arra){
1571            
1572 0           my $name = $e->{'name'};
1573 0           my $type = $e->{'type'};
1574            
1575 0   0       my $wname = $name || $type;
1576            
1577 0 0         if ($type ne 'keyvalue'){
1578 0           my $ctype=$self->_typeToChar($type);
1579 0           push @or,"$ctype$wname";
1580             }else{
1581 0           my $typev = $e->{'typevalue'};
1582 0           my $ctype=$self->_typeToChar($typev);
1583 0           push @or,"$name => $ctype$typev";
1584             }
1585            
1586             }
1587            
1588 0           push @and,join($separatoror,@or);
1589             }
1590            
1591 0           $text=join($separatorand,@and);
1592              
1593 0 0 0       if ((scalar(@$params) > 1) && ($braces)){
1594 0           $text="($text)";
1595             }
1596              
1597 0           return $text;
1598             }
1599              
1600              
1601              
1602             sub _typeToChar{
1603 0     0     my $self=shift;
1604 0           my $type=shift;
1605 0           my $c='';
1606              
1607 0           my $m = { 'array' => '@',
1608             'arrayref' => '\@',
1609             'hash' => '%',
1610             'hashref' => '\%',
1611             'method' => '&',
1612             'scalar' => '$',
1613             'scalarref' => '\$',
1614             };
1615              
1616 0   0       $c=$m->{$type} || $c;
1617              
1618 0           return $c;
1619             }
1620              
1621              
1622              
1623              
1624              
1625             sub _makeDirRecursive{
1626 0     0     my $dir=shift;
1627 0           my $path;
1628              
1629 0 0         if (!-e $dir){
1630              
1631 0           my @path=split(/\//,$dir);
1632 0           foreach my $p (@path){
1633 0 0         if (!-e $path.$p){
1634 0           mkdir $path.$p;
1635             # print "CREATE: ".$path.$p."\n";
1636             }
1637 0           $path.=$p.'/';
1638             }
1639              
1640             }
1641             }
1642              
1643              
1644              
1645              
1646             sub _extractPath{
1647 0     0     my $p=shift;
1648              
1649 0 0         if ($p=~ m/\//){
1650 0           $p=~ s/(.*)\/(.*)$/$1/;
1651             }else{
1652 0 0         if ($p=~ m/^\.*$/){ # only ".."
1653 0           $p=$p; ## nothing to do
1654             }else{
1655 0           $p='';
1656             }
1657             }
1658              
1659 0           return $p;
1660             }
1661              
1662              
1663              
1664              
1665              
1666             1;
1667              
1668              
1669              
1670              
1671              
1672              
1673              
1674              
1675              
1676              
1677              
1678             #################### pod generated by Pod::Autopod - keep this line to make pod updates possible ####################
1679              
1680             =head1 NAME
1681              
1682             Pod::Autopod - Generates pod documentation by analysing perl modules.
1683              
1684              
1685             =head1 SYNOPSIS
1686              
1687              
1688             use Pod::Autopod;
1689              
1690             new Pod::Autopod(readfile=>'Foo.pm', writefile=>'Foo2.pm');
1691              
1692             # reading Foo.pm and writing Foo2.pm but with pod
1693              
1694              
1695             my $ap = new Pod::Autopod(readfile=>'Foo.pm');
1696             print $ap->getPod();
1697              
1698             # reading and Foo.pm and prints the generated pod.
1699              
1700             my $ap = new Pod::Autopod();
1701             $ap->setPerlCode($mycode);
1702             print $ap->getPod();
1703             $ap->writeFile('out.pod');
1704              
1705             # asumes perl code in $mycoce and prints out the pod.
1706             # also writes to the file out.pod
1707              
1708              
1709              
1710              
1711             =head1 DESCRIPTION
1712              
1713             This Module is designed to generate pod documentation of a perl class by analysing its code.
1714             The idea is to have something similar like javadoc. So it uses also comments written directly
1715             obove the method definitions. It is designed to asumes a pm file which represents a class.
1716              
1717             Of course it can not understand every kind of syntax, parameters, etc. But the plan is to improve
1718             this library in the future to understand more and more automatically.
1719              
1720             Please note, there is also an "autopod" command line util in this package.
1721              
1722              
1723              
1724              
1725             =head1 REQUIRES
1726              
1727             L
1728              
1729             L
1730              
1731             L
1732              
1733             L
1734              
1735             L
1736              
1737             L<5.006> Pod::Abstract uses features of 5.6
1738              
1739              
1740             =head1 HOWTO
1741              
1742              
1743             To add a documentation about a method, write it with a classical remark char "#"
1744             before the sub{} definition:
1745              
1746             # This method is doing foo.
1747             #
1748             # print $self->foo();
1749             #
1750             #
1751             # It is not doing bar, only foo.
1752             sub foo{
1753             ...
1754             }
1755              
1756             A gap before sub{} is allowed.
1757              
1758             In further versions of autopod, here new features will appear.
1759              
1760             To define parameters and return values you can use a boundle of keywords.
1761             So far parameters and return values can not realy be autodetected, so manual
1762             way is necessary, but it is designed to type it rapidly.
1763              
1764             sub foo{ # void ($text)
1765             ...
1766             }
1767              
1768             The example above produces the following method description:
1769              
1770             $self->foo($text);
1771              
1772             The object "$self" is the default and automatially used when a constructor was found ("new")
1773             or the class inherits with ISA or "use base".
1774             You can change this by the parameter "selfstring" in the autopod constructor.
1775              
1776             The example looks simple, but the engine does more than you think. Please have a look here:
1777              
1778             sub foo{ # void (scalar text)
1779             ...
1780             }
1781            
1782             That procudes the same output! It means the dollar sign of the first example is a symbol which means "scalar".
1783              
1784             sub foo{ # ($)
1785             ...
1786             }
1787              
1788             Produces:
1789              
1790             $self->foo($scalar);
1791              
1792             As you see, that was the quickest way to write the definition. The keywork "void" is default.
1793              
1794             The following keywords or characters are allowed:
1795              
1796             array @
1797             arrayref \@
1798             hash %
1799             hashref \%
1800             method &
1801             scalar $
1802             scalarref \$
1803             void only as return value
1804              
1805             Now a more complex example:
1806              
1807             sub foo{# $state ($firstname,$lastname,\%persondata)
1808             ...
1809             }
1810              
1811             produces:
1812              
1813             my $state = $self->foo($firstname, $lastname, \%persondata);
1814              
1815             or write it in java style:
1816              
1817             sub foo{# scalar state (scalar firstname,scalar lastname,hashref persondata)
1818             ...
1819             }
1820              
1821             Multiple return values may be displayed as following:
1822              
1823             sub foo{# $a,$b ($text)
1824             ...
1825             }
1826              
1827             produces:
1828              
1829             my ($a, $b) = $self->foo($text);
1830              
1831              
1832             If you want to use key values pairs as in a hash, you may describe it like:
1833              
1834             sub foo{# void (firstname=>$scalar,lastname=>scalar)
1835             ...
1836             }
1837              
1838             The second "scalar" above is without a "$", that is no mistake, both works.
1839              
1840             There is also a way to expain that a value A OR B is expected. See here:
1841              
1842             sub foo{# $lista|\$refb (\@list|$text,$flag)
1843             ...
1844             }
1845              
1846             procudes:
1847              
1848             my $lista | \$refb = $self->foo(\@list | $text, $flag);
1849              
1850             Of course, that is not an official perl syntax with the or "|", but it shows
1851             you that is expected.
1852              
1853              
1854             In the First Part obove all method descriptions, you can add general informations, which are
1855             per default displayed under the head item "DESCRIPTION". But also own items can be used by
1856             underlining a text with "=" chars like:
1857              
1858             # HOWTO
1859             # =====
1860             # Read here howto do it.
1861              
1862             Some of these title keywords are allways places in a special order, which you can not change. For
1863             example LICENSE is allways near the end.
1864              
1865             Added some hacks to teach this tool also some doxygen parametes. For example:
1866              
1867             # @brief kept as simple text
1868             # @param text to be added
1869             # @return string with some text
1870             sub foo{
1871             return "abc".shift;
1872             }
1873              
1874              
1875             procudes:
1876              
1877             my $string = $self->foo($text);
1878              
1879              
1880              
1881              
1882             =head1 METHODS
1883              
1884             =head2 new
1885              
1886             my $object = $self->new($filename => $scalar, alsohiddenmethods => $scalar, selfstring => $scalar);
1887              
1888             Constructor
1889              
1890             The keyvalues are not mandatory.
1891              
1892             selfstring may hold something like '$self' as alternative to '$self', which is default.
1893              
1894             alsohiddenmethods gets a boolean flag to show also methods which starts with "_".
1895              
1896              
1897              
1898             =head2 buildPod
1899              
1900             $self->buildPod();
1901              
1902             Builds the pod. Called automatically when imporing a perl code.
1903              
1904              
1905             =head2 foo
1906              
1907             $self->foo();
1908              
1909             This method is doing foo.
1910              
1911             print $self->foo();
1912              
1913              
1914             It is not doing bar, only foo.
1915              
1916              
1917             =head2 getBorderString
1918              
1919             my $scalar = $self->getBorderString();
1920              
1921             Returns the border string which delimit the perl code and pod inside a pm file.
1922              
1923              
1924             =head2 getPerlCode
1925              
1926             my $text = $self->getPerlCode();
1927              
1928             Returns perl code which was set before.
1929              
1930              
1931             =head2 getPod
1932              
1933             my $text = $self->getPod();
1934              
1935             Returns the pod formated text.s
1936              
1937              
1938             =head2 readDirectory
1939              
1940             $self->readDirectory($directory, updateonly => $scalar, pod => $scalar, verbose => $scalar);
1941              
1942             scans a directoy recoursively for pm files and may
1943             generate pod of them.
1944              
1945             You can also set the flag updateonly to build new pod
1946             only for files you already build a pod (inside the file)
1947             in the past. Alternatively you can write the magic word
1948             AUTOPODME somewhere in the pm file what signals that this
1949             pm file wants to be pod'ed by autopod.
1950              
1951             The flag pod let will build a separate file. If poddir set,
1952             the generated pod file will be saved to a deparate directory.
1953             With verbose it prints the list of written files.
1954              
1955              
1956              
1957             =head2 readFile
1958              
1959             $self->readFile($filename);
1960              
1961             Reading a Perl class file and loads it to memory.
1962              
1963              
1964             =head2 scanArray
1965              
1966             $self->scanArray();
1967              
1968             This class may scan the perl code.
1969             But it is called automatically when importing a perl code.
1970              
1971              
1972             =head2 setBorderString
1973              
1974             $self->setBorderString($borderstring);
1975              
1976             Set an alternative border string.
1977             If you change this, you have to do it again when updating the pod.
1978              
1979              
1980             =head2 setPerlCode
1981              
1982             $self->setPerlCode($text | \@array, $file);
1983              
1984             Expects Perl code as arrayref
1985             or text (scalar).
1986              
1987             When used, it automatically runs scanArray().
1988             This now passes the filename to be used in case
1989             we are podding a .pl or .cgi file. NW
1990              
1991              
1992             =head2 writeFile
1993              
1994             $self->writeFile($filename);
1995              
1996             writes a pod file
1997              
1998             If the file has a pm or pl or cgi extension, it writes the perl code and the pod
1999             If the file has a pod extension or any, it only writes the pod.
2000              
2001              
2002              
2003             =head1 AUTHOR
2004              
2005             Andreas Hernitscheck ahernit(AT)cpan.org
2006              
2007              
2008             =head1 LICENSE
2009              
2010             You can redistribute it and/or modify it under the conditions of LGPL.
2011              
2012             By the way, the source code is quite bad. So feel free to replace this idea with something better Perl OO code.
2013              
2014              
2015              
2016             =cut
2017