File Coverage

lib/Pod/Autopod.pm
Criterion Covered Total %
statement 14 670 2.0
branch 0 220 0.0
condition 0 90 0.0
subroutine 5 56 8.9
pod 11 11 100.0
total 30 1047 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.215';
3 1     1   751 use 5.006; #Pod::Abstract uses features of 5.6
  1         2  
4 1     1   576 use FileHandle;
  1         10069  
  1         10  
5 1     1   395 use strict;
  1         3  
  1         35  
6 1     1   663 use Pod::Abstract;
  1         23803  
  1         33  
7 1     1   7 use Pod::Abstract::BuildNode qw(node nodes);
  1         2  
  1         6465  
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   0       my $desc = $2 || $retval;
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|method)\s+(.*)/){ ## removes the @brief word
670 0           my $text = $2;
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 ( $line =~ m/^\s*\@method\s+(.*)/i ){
1166 0           push @replace,"";
1167             }
1168              
1169            
1170 0 0         if (scalar(@replace) > 0){
1171 0           $line = join("\n",@replace);
1172             }
1173             }
1174              
1175            
1176            
1177             }
1178              
1179              
1180              
1181              
1182              
1183              
1184             sub _getTypeTreeByLine{
1185 0     0     my $self=shift;
1186 0           my $line=shift;
1187              
1188            
1189 0           my @re = split(/\,/,$line);
1190            
1191 0           my @rettype;
1192 0           foreach my $s (@re){
1193 0           $s=$self->_trim($s);
1194              
1195              
1196 0           my @or = split(/\|/,$s);
1197 0           my @orelems;
1198 0           my $elem={};
1199            
1200 0           foreach my $o (@or){
1201 0           my $name;
1202             my $type;
1203 0           my $typevalue;
1204            
1205 0 0         if ($o=~ m/^([^ ]+)\s*\=\>\s*([^ ]+)$/){
    0          
    0          
    0          
1206 0           $type='keyvalue';
1207 0           $name=$1;
1208 0           $typevalue=$2;
1209            
1210             }elsif ($o=~ m/^([^ ]+) ([^ ]+)$/){
1211 0           $type=lc($1);
1212 0           $name=$2;
1213             }elsif ($o=~ m/^([^ \$\%\@]+)$/){
1214 0           $type=lc($1);
1215             }elsif ($o=~ m/^([\$\%\@\\]+)(.*)$/){
1216 0           my $typec=$1;
1217 0           my $namec=$2;
1218            
1219 0 0         if ($typec eq '$'){$type='scalar'}
  0            
1220 0 0         if ($typec eq '\$'){$type='scalarref'}
  0            
1221 0 0         if ($typec eq '%'){$type='hash'}
  0            
1222 0 0         if ($typec eq '\%'){$type='hashref'}
  0            
1223 0 0         if ($typec eq '@'){$type='array'}
  0            
1224 0 0         if ($typec eq '\@'){$type='arrayref'}
  0            
1225 0 0         if ($typec eq '&'){$type='method'}
  0            
1226 0 0         if ($typec eq '\&'){$type='method'}
  0            
1227              
1228 0   0       $name=$namec || $type;
1229             }
1230            
1231 0           $elem = {name=>$name,type=>$type,typevalue=>$typevalue};
1232 0           push @orelems, $elem;
1233             }
1234              
1235            
1236              
1237 0           push @rettype,\@orelems;
1238             }
1239            
1240            
1241 0           return \@rettype;
1242             }
1243              
1244              
1245              
1246              
1247              
1248             # Builds the pod. Called automatically when imporing a perl code.
1249             sub buildPod{
1250 0     0 1   my $self=shift;
1251 0           my $attr = $self->{'METHOD_ATTR'};
1252              
1253 0           $self->{'POD_PARTS'}={};
1254              
1255 0           $self->_buildPod_Name();
1256 0           $self->_buildPod_Methods();
1257 0           $self->_buildPod_Requires();
1258 0           $self->_buildPod_Inherits();
1259 0           $self->_buildPod_More();
1260              
1261              
1262 0           $self->_buildPodText();
1263              
1264             }
1265              
1266              
1267              
1268              
1269              
1270             sub _buildPod_Requires{
1271 0     0     my $self=shift;
1272              
1273 0   0       my $re=$self->{'REQUIRES'} || [];
1274              
1275              
1276 0           my %dontshow;
1277 0           my @dontshow = qw(vars strict warnings libs base);
1278 0           map {$dontshow{$_}=1} @dontshow;
  0            
1279              
1280 0           my $node = node->root;
1281              
1282 0           $node->push( node->head1("REQUIRES") );
1283            
1284 0 0         if (scalar(@$re) > 0){
1285              
1286              
1287 0           foreach my $e (@$re){
1288              
1289 0           my $name=$e->{'name'};
1290 0           my $desc=$e->{'desc'};
1291              
1292 0 0         if (!$dontshow{$name}){
1293              
1294 0           $desc=$self->_trim($desc);
1295 0           my $text = "L<$name> $desc\n\n";
1296 0 0         if ($name ne $self->{'PKGNAME'}){
1297 0           $node->push( node->text($text));
1298             }
1299             }
1300             }
1301            
1302 0           $self->{'POD_PARTS'}->{'REQUIRES'} = $node;
1303             }
1304              
1305             }
1306              
1307              
1308              
1309              
1310              
1311             sub _buildPod_Inherits{
1312 0     0     my $self=shift;
1313              
1314 0   0       my $re=$self->{'INHERITS_FROM'} || [];
1315              
1316 0           my %dontshow;
1317 0           my @dontshow = qw(vars strict warnings libs base);
1318 0           map {$dontshow{$_}=1} @dontshow;
  0            
1319              
1320 0           my $node = node->root;
1321              
1322 0           $node->push( node->head1("IMPLEMENTS") );
1323            
1324 0 0         if (scalar(@$re) > 0){
1325              
1326              
1327 0           foreach my $e (@$re){
1328              
1329 0           my $name=$e->{'name'};
1330 0           my $desc=$e->{'desc'};
1331              
1332 0 0         if (!$dontshow{$name}){
1333              
1334 0           $desc=$self->_trim($desc);
1335 0           my $text = "L<$name> $desc\n\n";
1336              
1337 0           $node->push( node->text($text));
1338             }
1339             }
1340            
1341 0           $self->{'POD_PARTS'}->{'IMPLEMENTS'} = $node;
1342             }
1343              
1344             }
1345              
1346              
1347              
1348              
1349             sub _buildPodText{
1350 0     0     my $self=shift;
1351              
1352 0           my $parts=$self->{'POD_PARTS'};
1353              
1354 0           my @text;
1355              
1356 0           my @first = qw(NAME SYNOPSIS DESCRIPTION REQUIRES IMPLEMENTS EXPORTS HOWTO NOTES METHODS);
1357 0           my @last = ('CAVEATS','TODO','TODOS','SEE ALSO','AUTHOR','COPYRIGHT','LICENSE','COPYRIGHT AND LICENSE');
1358              
1359 0           my @own = keys %{$parts};
  0            
1360 0           my @free;
1361 0           push @own,@first;
1362 0           push @own,@last;
1363            
1364 0           my %def;
1365 0           map {$def{$_}=1} @first;
  0            
1366 0           map {$def{$_}=1} @last;
  0            
1367            
1368 0           foreach my $n (@own){
1369 0 0         if (!exists $def{$n}){push @free,$n};
  0            
1370             }
1371              
1372 0           my @all;
1373 0           push @all,@first,@free,@last;
1374              
1375 0           foreach my $area (@all){
1376 0 0         if (exists $parts->{$area}){
1377 0           push @text,$parts->{$area}->pod;
1378             }
1379             }
1380            
1381            
1382              
1383            
1384 0           my $node = node->root;
1385 0           $node->push( node->cut );
1386 0           push @text,$node->pod;
1387            
1388 0           my $text=join("\n",@text);
1389              
1390 0           $self->{"POD_TEXT"} = $text;
1391             }
1392              
1393              
1394              
1395              
1396              
1397             sub _buildPod_Name{
1398 0     0     my $self=shift;
1399 0           my $attr = $self->{'METHOD_ATTR'};
1400 0           my $name = $self->{'PKGNAME'};
1401              
1402 0           my $node = node->root;
1403              
1404 0           $node->push( node->head1("NAME") );
1405            
1406 0           my @name;
1407            
1408 0           push @name,$self->{'PKGNAME'};
1409 0 0         push @name,$self->_trim($self->{'PKGNAME_DESC'}) if $self->{'PKGNAME_DESC'};
1410            
1411 0           my $namestr = join(" - ",@name)."\n\n";
1412              
1413              
1414 0           $node->push( node->text($namestr));
1415              
1416              
1417 0           $self->{'POD_PARTS'}->{'NAME'} = $node;
1418              
1419             }
1420              
1421              
1422              
1423              
1424              
1425              
1426              
1427             sub _buildPod_More{
1428 0     0     my $self=shift;
1429 0           my $attr = $self->{'METHOD_ATTR'};
1430              
1431              
1432              
1433 0           my $more = $self->{'MORE'};
1434              
1435 0           foreach my $area (keys %$more){
1436              
1437 0           my $node = node->root;
1438            
1439 0           my $desc=$more->{$area};
1440             # length(@$desc) throws an error on newer perl, so use scalar(@$desc) instead. NW
1441 0 0         if (scalar(@$desc) > 0){
1442            
1443 0           $node->push( node->head1("$area") );
1444 0           $node->push( node->text( join("\n",@$desc)."\n\n" ));
1445            
1446             }
1447              
1448 0           $self->{'POD_PARTS'}->{$area} = $node;
1449             }
1450              
1451              
1452             }
1453              
1454              
1455              
1456              
1457              
1458              
1459             sub _buildPod_Methods{
1460 0     0     my $self=shift;
1461 0           my $attr = $self->{'METHOD_ATTR'};
1462              
1463 0           my $node = node->root;
1464              
1465 0           $node->push( node->head1("METHODS") );
1466              
1467             ## sort alphabeticaly
1468 0           my @methods = keys %$attr;
1469 0           @methods = sort @methods;
1470              
1471 0 0         if (exists $attr->{'new'}){ ## constructor first
1472 0           $self->_buildPod_Methods_addMethod(node=>$node,method=>'new');
1473             }
1474              
1475 0           foreach my $method (@methods){
1476              
1477 0           my $ok = 1;
1478              
1479 0 0         if ($method eq ''){$ok=0};
  0            
1480              
1481 0 0         if ($method=~ m/^\_/){
1482 0           $ok=0;
1483 0 0         if ($self->{'alsohiddenmethods'}){$ok=1};
  0            
1484             }
1485              
1486 0 0         if ($ok){
1487 0 0         if ($method ne 'new'){
1488 0           $self->_buildPod_Methods_addMethod(node=>$node,method=>$method);
1489             }
1490             }
1491            
1492             }
1493              
1494            
1495 0           $self->{'POD_PARTS'}->{'METHODS'} = $node;
1496             }
1497              
1498              
1499              
1500              
1501             sub _buildPod_Methods_addMethod{
1502 0     0     my $self=shift;
1503 0           my $v={@_};
1504 0           my $node=$v->{'node'};
1505 0           my $method=$v->{'method'};
1506 0           my $attr = $self->{'METHOD_ATTR'};
1507 0           my $mat=$attr->{$method};
1508              
1509 0           my $selfstring='';
1510 0 0         if ($self->{'ISCLASS'}){
1511 0           $selfstring=$self->{'selfstring'}.'->';
1512             }
1513            
1514              
1515             ## method name
1516 0           $node->push( node->head2("$method") );
1517              
1518              
1519             ## how to call
1520              
1521 0           my $retstring = $self->_buildParamString(params=>$mat->{'returntypes'}, braces=>1,separatorand=>', ',separatoror=>' | ');
1522 0           my $paramstring = $self->_buildParamString(params=>$mat->{'attributetypes'}, braces=>0,separatorand=>', ',separatoror=>' | ');
1523              
1524 0           my $addit=0;
1525 0 0         if ($retstring){
    0          
1526 0           $retstring = " my $retstring = $selfstring$method($paramstring);";
1527 0           $addit=1;
1528             }elsif($paramstring){
1529 0           $retstring = " $selfstring$method($paramstring);";
1530 0           $addit=1;
1531             }else{
1532 0           $retstring = " $selfstring$method();";
1533 0           $addit=1;
1534             }
1535              
1536              
1537 0 0         if ($addit){
1538 0           $retstring.="\n\n";
1539 0           $node->push( node->text($retstring) );
1540             }
1541              
1542              
1543             ### head text
1544              
1545 0           my $text;
1546 0 0         if ($mat->{'head'}){
1547 0           $text = join("\n",@{ $mat->{'head'} }); ## I added the return here, which is necessary using example codes before methods
  0            
1548 0 0         if ($text){$text.="\n\n\n"};
  0            
1549            
1550 0           $node->push( node->text($text) );
1551             }
1552            
1553              
1554              
1555             }
1556              
1557              
1558              
1559             sub _buildParamString{
1560 0     0     my $self=shift;
1561 0           my $v={@_};
1562 0           my $params=$v->{'params'};
1563 0           my $braces=$v->{'braces'};
1564 0   0       my $separatorand=$v->{'separatorand'} || ',';
1565 0   0       my $separatoror=$v->{'separatoror'} || '|';
1566 0           my $text='';
1567              
1568              
1569 0 0 0       if ((exists $params->[0]->[0]->{'type'}) && ($params->[0]->[0]->{'type'} eq 'void')){return};
  0            
1570              
1571 0           my @and;
1572 0           foreach my $arra (@$params){
1573              
1574 0           my @or;
1575 0           foreach my $e (@$arra){
1576            
1577 0           my $name = $e->{'name'};
1578 0           my $type = $e->{'type'};
1579            
1580 0   0       my $wname = $name || $type;
1581            
1582 0 0         if ($type ne 'keyvalue'){
1583 0           my $ctype=$self->_typeToChar($type);
1584 0           push @or,"$ctype$wname";
1585             }else{
1586 0           my $typev = $e->{'typevalue'};
1587 0           my $ctype=$self->_typeToChar($typev);
1588 0           push @or,"$name => $ctype$typev";
1589             }
1590            
1591             }
1592            
1593 0           push @and,join($separatoror,@or);
1594             }
1595            
1596 0           $text=join($separatorand,@and);
1597              
1598 0 0 0       if ((scalar(@$params) > 1) && ($braces)){
1599 0           $text="($text)";
1600             }
1601              
1602 0           return $text;
1603             }
1604              
1605              
1606              
1607             sub _typeToChar{
1608 0     0     my $self=shift;
1609 0           my $type=shift;
1610 0           my $c='';
1611              
1612 0           my $m = { 'array' => '@',
1613             'arrayref' => '\@',
1614             'hash' => '%',
1615             'hashref' => '\%',
1616             'method' => '&',
1617             'scalar' => '$',
1618             'scalarref' => '\$',
1619             };
1620              
1621 0   0       $c=$m->{$type} || $c;
1622              
1623 0           return $c;
1624             }
1625              
1626              
1627              
1628              
1629              
1630             sub _makeDirRecursive{
1631 0     0     my $dir=shift;
1632 0           my $path;
1633              
1634 0 0         if (!-e $dir){
1635              
1636 0           my @path=split(/\//,$dir);
1637 0           foreach my $p (@path){
1638 0 0         if (!-e $path.$p){
1639 0           mkdir $path.$p;
1640             # print "CREATE: ".$path.$p."\n";
1641             }
1642 0           $path.=$p.'/';
1643             }
1644              
1645             }
1646             }
1647              
1648              
1649              
1650              
1651             sub _extractPath{
1652 0     0     my $p=shift;
1653              
1654 0 0         if ($p=~ m/\//){
1655 0           $p=~ s/(.*)\/(.*)$/$1/;
1656             }else{
1657 0 0         if ($p=~ m/^\.*$/){ # only ".."
1658 0           $p=$p; ## nothing to do
1659             }else{
1660 0           $p='';
1661             }
1662             }
1663              
1664 0           return $p;
1665             }
1666              
1667              
1668              
1669              
1670              
1671             1;
1672              
1673              
1674              
1675              
1676              
1677              
1678              
1679              
1680              
1681              
1682              
1683             #################### pod generated by Pod::Autopod - keep this line to make pod updates possible ####################
1684              
1685             =head1 NAME
1686              
1687             Pod::Autopod - Generates pod documentation by analysing perl modules.
1688              
1689              
1690             =head1 SYNOPSIS
1691              
1692              
1693             use Pod::Autopod;
1694              
1695             new Pod::Autopod(readfile=>'Foo.pm', writefile=>'Foo2.pm');
1696              
1697             # reading Foo.pm and writing Foo2.pm but with pod
1698              
1699              
1700             my $ap = new Pod::Autopod(readfile=>'Foo.pm');
1701             print $ap->getPod();
1702              
1703             # reading and Foo.pm and prints the generated pod.
1704              
1705             my $ap = new Pod::Autopod();
1706             $ap->setPerlCode($mycode);
1707             print $ap->getPod();
1708             $ap->writeFile('out.pod');
1709              
1710             # asumes perl code in $mycoce and prints out the pod.
1711             # also writes to the file out.pod
1712              
1713              
1714              
1715              
1716             =head1 DESCRIPTION
1717              
1718             This Module is designed to generate pod documentation of a perl class by analysing its code.
1719             The idea is to have something similar like javadoc. So it uses also comments written directly
1720             obove the method definitions. It is designed to asumes a pm file which represents a class.
1721              
1722             Of course it can not understand every kind of syntax, parameters, etc. But the plan is to improve
1723             this library in the future to understand more and more automatically.
1724              
1725             Please note, there is also an "autopod" command line util in this package.
1726              
1727              
1728              
1729              
1730             =head1 REQUIRES
1731              
1732             L
1733              
1734             L
1735              
1736             L
1737              
1738             L
1739              
1740             L
1741              
1742             L<5.006> Pod::Abstract uses features of 5.6
1743              
1744              
1745             =head1 HOWTO
1746              
1747              
1748             To add a documentation about a method, write it with a classical remark char "#"
1749             before the sub{} definition:
1750              
1751             # This method is doing foo.
1752             #
1753             # print $self->foo();
1754             #
1755             #
1756             # It is not doing bar, only foo.
1757             sub foo{
1758             ...
1759             }
1760              
1761             A gap before sub{} is allowed.
1762              
1763             In further versions of autopod, here new features will appear.
1764              
1765             To define parameters and return values you can use a boundle of keywords.
1766             So far parameters and return values can not realy be autodetected, so manual
1767             way is necessary, but it is designed to type it rapidly.
1768              
1769             sub foo{ # void ($text)
1770             ...
1771             }
1772              
1773             The example above produces the following method description:
1774              
1775             $self->foo($text);
1776              
1777             The object "$self" is the default and automatially used when a constructor was found ("new")
1778             or the class inherits with ISA or "use base".
1779             You can change this by the parameter "selfstring" in the autopod constructor.
1780              
1781             The example looks simple, but the engine does more than you think. Please have a look here:
1782              
1783             sub foo{ # void (scalar text)
1784             ...
1785             }
1786            
1787             That procudes the same output! It means the dollar sign of the first example is a symbol which means "scalar".
1788              
1789             sub foo{ # ($)
1790             ...
1791             }
1792              
1793             Produces:
1794              
1795             $self->foo($scalar);
1796              
1797             As you see, that was the quickest way to write the definition. The keywork "void" is default.
1798              
1799             The following keywords or characters are allowed:
1800              
1801             array @
1802             arrayref \@
1803             hash %
1804             hashref \%
1805             method &
1806             scalar $
1807             scalarref \$
1808             void only as return value
1809              
1810             Now a more complex example:
1811              
1812             sub foo{# $state ($firstname,$lastname,\%persondata)
1813             ...
1814             }
1815              
1816             produces:
1817              
1818             my $state = $self->foo($firstname, $lastname, \%persondata);
1819              
1820             or write it in java style:
1821              
1822             sub foo{# scalar state (scalar firstname,scalar lastname,hashref persondata)
1823             ...
1824             }
1825              
1826             Multiple return values may be displayed as following:
1827              
1828             sub foo{# $a,$b ($text)
1829             ...
1830             }
1831              
1832             produces:
1833              
1834             my ($a, $b) = $self->foo($text);
1835              
1836              
1837             If you want to use key values pairs as in a hash, you may describe it like:
1838              
1839             sub foo{# void (firstname=>$scalar,lastname=>scalar)
1840             ...
1841             }
1842              
1843             The second "scalar" above is without a "$", that is no mistake, both works.
1844              
1845             There is also a way to expain that a value A OR B is expected. See here:
1846              
1847             sub foo{# $lista|\$refb (\@list|$text,$flag)
1848             ...
1849             }
1850              
1851             procudes:
1852              
1853             my $lista | \$refb = $self->foo(\@list | $text, $flag);
1854              
1855             Of course, that is not an official perl syntax with the or "|", but it shows
1856             you that is expected.
1857              
1858              
1859             In the First Part obove all method descriptions, you can add general informations, which are
1860             per default displayed under the head item "DESCRIPTION". But also own items can be used by
1861             underlining a text with "=" chars like:
1862              
1863             # HOWTO
1864             # =====
1865             # Read here howto do it.
1866              
1867             Some of these title keywords are allways places in a special order, which you can not change. For
1868             example LICENSE is allways near the end.
1869              
1870             Added some hacks to teach this tool also some doxygen parametes. For example:
1871              
1872             # @brief kept as simple text
1873             # @param text to be added
1874             # @return string with some text
1875             sub foo{
1876             return "abc".shift;
1877             }
1878              
1879              
1880             procudes:
1881              
1882             my $string = $self->foo($text);
1883              
1884              
1885              
1886              
1887             =head1 METHODS
1888              
1889             =head2 new
1890              
1891             my $object = $self->new($filename => $scalar, alsohiddenmethods => $scalar, selfstring => $scalar);
1892              
1893             Constructor
1894              
1895             The keyvalues are not mandatory.
1896              
1897             selfstring may hold something like '$self' as alternative to '$self', which is default.
1898              
1899             alsohiddenmethods gets a boolean flag to show also methods which starts with "_".
1900              
1901              
1902              
1903             =head2 buildPod
1904              
1905             $self->buildPod();
1906              
1907             Builds the pod. Called automatically when imporing a perl code.
1908              
1909              
1910             =head2 foo
1911              
1912             $self->foo();
1913              
1914             This method is doing foo.
1915              
1916             print $self->foo();
1917              
1918              
1919             It is not doing bar, only foo.
1920              
1921              
1922             =head2 getBorderString
1923              
1924             my $scalar = $self->getBorderString();
1925              
1926             Returns the border string which delimit the perl code and pod inside a pm file.
1927              
1928              
1929             =head2 getPerlCode
1930              
1931             my $text = $self->getPerlCode();
1932              
1933             Returns perl code which was set before.
1934              
1935              
1936             =head2 getPod
1937              
1938             my $text = $self->getPod();
1939              
1940             Returns the pod formated text.s
1941              
1942              
1943             =head2 readDirectory
1944              
1945             $self->readDirectory($directory, updateonly => $scalar, pod => $scalar, verbose => $scalar);
1946              
1947             scans a directoy recoursively for pm files and may
1948             generate pod of them.
1949              
1950             You can also set the flag updateonly to build new pod
1951             only for files you already build a pod (inside the file)
1952             in the past. Alternatively you can write the magic word
1953             AUTOPODME somewhere in the pm file what signals that this
1954             pm file wants to be pod'ed by autopod.
1955              
1956             The flag pod let will build a separate file. If poddir set,
1957             the generated pod file will be saved to a deparate directory.
1958             With verbose it prints the list of written files.
1959              
1960              
1961              
1962             =head2 readFile
1963              
1964             $self->readFile($filename);
1965              
1966             Reading a Perl class file and loads it to memory.
1967              
1968              
1969             =head2 scanArray
1970              
1971             $self->scanArray();
1972              
1973             This class may scan the perl code.
1974             But it is called automatically when importing a perl code.
1975              
1976              
1977             =head2 setBorderString
1978              
1979             $self->setBorderString($borderstring);
1980              
1981             Set an alternative border string.
1982             If you change this, you have to do it again when updating the pod.
1983              
1984              
1985             =head2 setPerlCode
1986              
1987             $self->setPerlCode($text | \@array, $file);
1988              
1989             Expects Perl code as arrayref
1990             or text (scalar).
1991              
1992             When used, it automatically runs scanArray().
1993             This now passes the filename to be used in case
1994             we are podding a .pl or .cgi file. NW
1995              
1996              
1997             =head2 writeFile
1998              
1999             $self->writeFile($filename);
2000              
2001             writes a pod file
2002              
2003             If the file has a pm or pl or cgi extension, it writes the perl code and the pod
2004             If the file has a pod extension or any, it only writes the pod.
2005              
2006              
2007              
2008             =head1 AUTHOR
2009              
2010             Andreas Hernitscheck ahernit(AT)cpan.org
2011              
2012              
2013             =head1 LICENSE
2014              
2015             You can redistribute it and/or modify it under the conditions of LGPL.
2016              
2017             By the way, the source code is quite bad. So feel free to replace this idea with something better Perl OO code.
2018              
2019              
2020              
2021             =cut
2022