home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / tsw / TSW_3.4.0.exe / Apache2 / perl / HtmlTree.pm < prev    next >
Encoding:
Perl POD Document  |  2003-07-19  |  12.1 KB  |  454 lines

  1. ############################################################
  2. package Pod::HtmlTree;
  3. ############################################################
  4. use strict;
  5. use warnings;
  6.  
  7. use Exporter;
  8. use Pod::Html;
  9. use Text::Wrap;
  10. use File::Find;
  11. use File::Spec;
  12. use File::Basename;
  13. use File::Path;
  14. use Pod::Html;
  15. use Cwd;
  16. use File::Temp qw(tempfile);
  17.  
  18. our $VERSION     = '0.96';
  19.  
  20. our @ISA = qw(Exporter);
  21.  
  22. our %EXPORT_TAGS = ( 'all' => [ qw( ) ] );
  23. our @EXPORT_OK   = ( @{ $EXPORT_TAGS{'all'} }, 
  24.                      qw(pms modules
  25.                         pod2htmltree banner
  26.                        ) );
  27. our @EXPORT      = qw( );
  28.  
  29. my $HTML_DIR      = "docs/html";
  30. my $BASE          = cwd();
  31. my @SEARCH_DIRS   = qw(. lib);
  32. my $SEARCH_DIRS_PATTERN = join('|', map { "^" . quotemeta($_) } @SEARCH_DIRS);
  33.  
  34. ############################################################
  35. # Get a list of all *.pm files in the specified directory
  36. # and recursively in its subdirectories. Prune the find
  37. # tree in the given dirs.
  38. ############################################################
  39. sub pms {
  40. ############################################################
  41.     my($start_dir, $prune_dirs) = @_;
  42.  
  43.         # Default if no prune_dirs are given
  44.     $prune_dirs ||= ['blib', 'docs'];
  45.  
  46.     my @pms = ();
  47.  
  48.     File::Find::find( sub {
  49.  
  50.         if(-d $_) {
  51.             for my $dir (@$prune_dirs) {
  52.                 if($_ eq $dir) {
  53.                     $File::Find::prune = 1;
  54.                     return;
  55.                 }
  56.             }
  57.         }
  58.                     
  59.         return if ! -f or ! /\.pm$/;
  60.  
  61.         (my $path = $File::Find::name) =~ s#^./##;
  62.  
  63.         push @pms, $path;
  64.     }, $start_dir );
  65.  
  66.     return @pms;
  67. }
  68.  
  69. ############################################################
  70. # Get a list of all modules (pm files) in the tree.
  71. ############################################################
  72. sub modules {
  73. ############################################################
  74.     my($start_dir, $prune_dirs) = @_;
  75.  
  76.     my @pms = paths_to_modules(pms($start_dir, $prune_dirs));
  77.  
  78.     return @pms;
  79. }
  80.  
  81. ############################################################
  82. # Format something in form of a banner
  83. ############################################################
  84. sub banner {
  85. ############################################################
  86.  
  87.     my $TOTAL_LEN = 50;
  88.  
  89.     my $out = "*" x $TOTAL_LEN;
  90.     $out .= "\n";
  91.     $Text::Wrap::columns = $TOTAL_LEN - 2;
  92.     for my $line (split /\n/, Text::Wrap::fill('* ','* ', @_)) {
  93.         chomp $line;
  94.         if(length($line) < $TOTAL_LEN - 2) {
  95.             $line .= (" " x ($TOTAL_LEN - 2 - length($line))) . " *\n";
  96.         }
  97.         $out .= $line;
  98.     }
  99.     $out .= "*" x $TOTAL_LEN;
  100.     $out .= "\n";
  101.  
  102.     return $out;
  103. }
  104.  
  105. ############################################################
  106. sub paths_to_modules {
  107. ############################################################
  108.     my(@paths) = @_;
  109.  
  110.     my @modules = map { s#$SEARCH_DIRS_PATTERN##o;
  111.                         s#^/##;
  112.                         s#/#::#g; 
  113.                         s#\.pm##; 
  114.                         $_; 
  115.                       } @paths;
  116.  
  117.     return @modules;
  118. }
  119.  
  120. ############################################################
  121. # Set up the doc tree
  122. ############################################################
  123. sub pod2htmltree {
  124. ############################################################
  125.     my($htmlroot_to_module, $htmldocdir) = @_;
  126.  
  127.     $htmldocdir = $HTML_DIR unless defined $htmldocdir;
  128.  
  129.     my ($fh,$tmpfile) = tempfile();
  130.     close $fh;
  131.  
  132.     my @dirs    = pms(".");
  133.     my @modules = modules(".");
  134.  
  135.     my $see_also = "=head1 SEE ALSO\n\n";
  136.     $see_also .= join ', ', map( { "L<$_|$_>" } @modules );
  137.     $see_also .= "\n\n";
  138.     $see_also .= "B<Source Code:> _SRC_HERE_\n\n";
  139.  
  140.     mkpath $htmldocdir unless -d $htmldocdir;
  141.  
  142.     for my $pm (@dirs) {
  143.         (my $module) = paths_to_modules($pm);
  144.         (my $relpath = $pm) =~ s#$SEARCH_DIRS_PATTERN##o;
  145.         my $htmlfile = File::Spec->catfile($htmldocdir, $relpath); 
  146.         $htmlfile =~ s/\.pm$/\.html/;
  147.  
  148.         my $dir     = dirname($htmlfile);
  149.  
  150.         mkpath($dir) unless -d $dir;
  151.  
  152.         open FILE, "<$pm" or die "Cannot open $pm";
  153.         my $data = join '', <FILE>;
  154.         close FILE;
  155.  
  156.         $data =~ s/^=head1 SEE ALSO.*?(?=^=)/$see_also/ms;
  157.  
  158.         open FILE, ">$tmpfile" or die "Cannot open $tmpfile";
  159.         print FILE $data;
  160.         close FILE;
  161.  
  162.         my $podroot = (-d "lib" ? "lib" : ".");
  163.  
  164.         pod2html("--infile=$tmpfile",
  165.                  "--outfile=$htmlfile",
  166.                  "--podroot=$podroot",
  167.                  "--podpath=.",
  168.                  '--recurse',
  169.                  "--htmlroot=$htmlroot_to_module/$htmldocdir",
  170.                  "--css=$htmlroot_to_module/$htmldocdir/default.css",
  171.         );
  172.  
  173.         # Patch src link
  174.         open FILE, "<$htmlfile" or die "Cannot open $htmlfile";
  175.         $data = join '', <FILE>;
  176.         close FILE;
  177.         open FILE, ">$htmlfile" or die "Cannot open $htmlfile";
  178.         $data =~ s#_SRC_HERE_#<A HREF=$htmlroot_to_module/$pm>$module</A>#g;
  179.         print FILE $data;
  180.         close FILE;
  181.     }
  182.  
  183.     #unlink $tmpfile;
  184.     stylesheet_write(File::Spec->catfile($htmldocdir, "default.css"));
  185. }
  186.  
  187. ############################################################
  188. sub stylesheet_write {
  189. ############################################################
  190.     my($dstfile, $csstext) = @_;
  191.  
  192.     $csstext = stylesheet_default() unless defined $csstext;
  193.  
  194.     open FILE, ">$dstfile" or die "Cannot open $dstfile";
  195.     print FILE $csstext;
  196.     close FILE;
  197. }
  198.  
  199. ############################################################
  200. # Default style sheet
  201. ############################################################
  202. sub stylesheet_default {
  203. ############################################################
  204.     return <<EOT;
  205. body {
  206.     background:  #FFFFFF;
  207.     font-family: Arial;
  208. }    
  209. input {
  210.     font-size: 12px;
  211. }
  212. select {
  213.     font-size: 12px;
  214. }
  215. tt {
  216.     font-family: Lucida Console;
  217.     font-size: 10px;
  218. }
  219. pre {
  220.     font-family: Lucida Console;
  221.     font-size: 12px;
  222. }
  223. code {
  224.     font-family: Lucida Console;
  225.     font-size: 12px;
  226. }
  227. p {
  228.     color: #000000;
  229.     font-size: 12px;
  230.     font-family: Arial;
  231.     }
  232. blockquote {
  233.     color: #000000;
  234.     font-size: 12px;
  235.     font-family: Arial;
  236.     font-weight: normal;
  237. }
  238. b {
  239.     font-weight: bold;
  240. }
  241.  
  242. h1 { 
  243.     font-family: Arial;
  244.     font-size: 16px;
  245.     font-weight: bold;
  246.     color: #B82831;
  247. }
  248. h2 { 
  249.     font-family: Arial;
  250.     font-size: 14px;
  251.     font-weight: bold;
  252.     color: #B82831;
  253. }
  254. a:link { 
  255.     color: #B82831;
  256.         text-decoration: underline;
  257. }
  258. a:visited { 
  259.     color: #80933F;
  260.         text-decoration: underline;
  261. }
  262. EOT
  263. }
  264.  
  265. 1;
  266.  
  267. __END__
  268.  
  269. =head1 NAME
  270.  
  271. Pod::HtmlTree - Create a hierarchy of HTML documents from your module's PMs.
  272.  
  273. =head1 SYNOPSIS
  274.  
  275.   use Pod::HtmlTree qw(pod2htmltree);
  276.   pod2htmltree($httproot);
  277.  
  278. =head1 DESCRIPTION
  279.  
  280. So you've just created a great new Perl module distribution including
  281. several *.pm files?
  282. You've added nice POD documentation to each of them and now you'd like
  283. to view it nicely formatted in a web browser? And you'd also
  284. like to navigate between all those manual pages in your distribution
  285. and even view their source code? Read on, C<Pod::HtmlTree> is what you need.
  286.  
  287. It traverses your module's distribution directory (which you've probably 
  288. created using C<h2xs>), finds all *.pm files recursivly and calls C<pod2html()>
  289. on them, hereby resolving all POD links (LE<lt>...E<gt> style).
  290.  
  291. =head2 Patching SEE ALSO and WHERE'S THE SOURCE?
  292.  
  293. It then saves the nicely formatted HTML files under C<docs/html> and 
  294. updates each's C<SEE ALSO> section to contain links to every other *.pm file
  295. in you're module's distribution. So, if you want that, please
  296. make sure your documentation contains a C<SEE ALSO> section.
  297.  
  298. Also, at the end of the C<SEE ALSO> section, it'll add a link to the
  299. source code of the current *.pm file, 
  300. just in case a user wants to browse it because
  301. there's issues which aren't clear from the documentation.
  302.  
  303. It also adds a stylesheet to C<docs/html>, which is referenced by every HTML 
  304. file.
  305.  
  306. So, in order to obtain HTML documentation for all your distribution's files, 
  307. just call the script (which comes with the distribution of this module)
  308.  
  309.     pod2htmltree httproot
  310.  
  311. while you're located in the top directory of your module's distribution.
  312. What's in C<httproot> is explained below.
  313.  
  314. The script C<pod2htmltree> just calls
  315.  
  316.     use Pod::HtmlTree;
  317.     Pod::HtmlTree::pod2htmltree($ARGV[0]);
  318.  
  319. internally, if you want to call it from within Perl, that's the way to go.
  320.  
  321. =head1 FUNCTIONS
  322.  
  323. =over 4
  324.  
  325. =item pod2htmltree( $httproot );
  326.  
  327. Make sure you've C<chdir()>ed to 
  328. your module's top directory when calling this function.
  329.  
  330. Recursively finds all C<*.pm> files under the current directory,
  331. transforms them to HTML and places the result files in a tree starting
  332. at C<docs/html> from the current directory.
  333.  
  334. C<$httproot> is the URL (absolute like C<"http://..."> or relative like
  335. C</mymodule>) to the top directory of your module, as seen from your web 
  336. browser.
  337.  
  338. If you don't like the HTML documents to be created under C<docs/html>,
  339. you can specify the relative (!) directory in the additional parameter
  340. C<$htmldocdir>:
  341.  
  342.     pod2htmltree( $httproot, $htmldocdir );
  343.  
  344. If not specified, C<$htmldocdir> defaults to C<docs/html>, therefore the
  345. one-parameter syntax shown above.
  346.  
  347. =item banner( $text );
  348.  
  349. Prints the passed text string nicely formatted as a screen warning. E. g., to notify
  350. the user after running C<pod2htmltree> to C<"Make sure 
  351. http://localhost/perldoc/Pod-HtmlTree points to /u/mschilli/DEV/Pod-HtmlTree">, 
  352. just pass it to C<banner()> and print the return value:
  353.  
  354.     **************************************************
  355.     * Make sure                                      *
  356.     * http://localhost/perldoc/Pod-HtmlTree points   *
  357.     * to /u/mschilli/DEV/Pod-HtmlTree                *
  358.     **************************************************
  359.  
  360. =back
  361.  
  362. =head1 EXAMPLE
  363.  
  364. So, if your module is under
  365.  
  366.     /u/mschilli/MYPROJECTS/Spiffy-Module
  367.  
  368. and has the files
  369.  
  370.     Spiffy-Module
  371.     Spiffy-Module/Changes
  372.     Spiffy-Module/MANIFEST
  373.     Spiffy-Module/Makefile.PL
  374.     Spiffy-Module/README
  375.     Spiffy-Module/lib
  376.     Spiffy-Module/lib/Spiffy.pm
  377.     Spiffy-Module/lib/Spiffy/Subspiffy.pm
  378.     Spiffy-Module/lib/Spiffy/Subspiffy/Subsub.pm
  379.     Spiffy-Module/t
  380.     Spiffy-Module/t/1.t
  381.  
  382. a call to 
  383.  
  384.     cd Spiffy-Module
  385.     pod2htmltree http://localhost/Spiffy
  386.  
  387. from within the shell or
  388.  
  389.     use Pod::HtmlTree;
  390.     Pod::HtmlTree::pod2htmltree("http://localhost/Spiffy");
  391.  
  392. from within Perl will C<pod2html>-transform the files
  393. C<Spiffy.pm>, C<Subspiffy.pm> and C<Subsub.pm> to HTML and put the result there:
  394.  
  395.     Spiffy-Module/docs/html/Spiffy.html
  396.     Spiffy-Module/docs/html/Spiffy/Subspiffy.html
  397.     Spiffy-Module/docs/html/Spiffy/Subspiffy/Subspiffy.html
  398.  
  399. Directories are created on the fly as necessary.
  400. To view them on your web server via a browser, you need to create a symbolic link
  401. from your web server's document root.
  402.  
  403. If the module's distribution is located under
  404.  
  405.     /u/mschilli/MYPROJECTS/Spiffy-Module
  406.  
  407. and your web server's doc root is C</opt/netscape/htdocs>, you need to create a symlink
  408. like
  409.  
  410.     ln -s /u/mschilli/MYPROJECTS/Spiffy-Module /opt/netscape/htdocs/Spiffy
  411.  
  412. Then, if you point your browser to 
  413.  
  414.     http://localhost/Spiffy/docs/html/Spiffy.html
  415.  
  416. you'll see the documentation. If you've specified a (probably empty) 
  417. C<SEE ALSO> section, it will be automatically populated with other modules
  418. in your distribution and a link to the current module's source code.
  419.  
  420. =head2 Or, call it in Makefile.PL
  421.  
  422. If you want to give the user of your distribution the opportunity to
  423. create their own browsable HTML-documentation of your module, just
  424. include the following in the Makefil.PL of your distribution:
  425.  
  426.     use ExtUtils::MakeMaker;
  427.  
  428.     >>  # Generate documentation?
  429.     >>  if (prompt("Generate HTML documentation?", "n") =~ /^y/) {
  430.     >>      require Pod::HtmlTree;
  431.     >>      Pod::HtmlTree::pod2htmltree("/mymodule");
  432.     >>      print Pod::HtmlTree::banner(
  433.     >>          "Make sure http://localhost/mymodule points to ", `pwd`);
  434.     >>   }
  435.  
  436.     WriteMakefile(
  437.         ...
  438.     );
  439.  
  440. =head1 SEE ALSO
  441.  
  442. =head1 AUTHOR
  443.  
  444. Mike Schilli, E<lt>mschilli1@aol.comE<gt>
  445.  
  446. =head1 COPYRIGHT AND LICENSE
  447.  
  448. Copyright 2002 by Mike Schilli
  449.  
  450. This library is free software; you can redistribute it and/or modify
  451. it under the same terms as Perl itself. 
  452.  
  453. =cut
  454.