Search code examples
htmlperlbuild-processbuildperl-tidy

Can I use perltidy's HTML formatter in my automated Perl build?


I'm using Module::Build to perform build, test, testpod, html, & install actions on my Perl module that I'm developing. The HTML files that are generated are okay, but I'd be much happier if I could somehow configure Module::Build to use the perltidy -html formatting utility instead of its own HTML formatter.

Anyone know of a way I can replace the HTML formatter that comes with Module::Build with the prettier perltidy HTML formatter?

Addendum: When I said "replace" above, that was probably misleading. I don't really want to write code to replace the html formatter that comes with Module::Build. I really want to know if Module::Build has any other HTML formatter options. The HTML it generates is so plain and generic looking. It's so boring. I like perltidy's output a lot.

Here is how I got it working right now in a build script that I wrote, but it's totally a hack ... falling out to the command line perltidy script:

use strict;
use warnings;

# get list of files in directory
my $libLocation = "lib/EDF";
opendir( DIR, $libLocation );
my @filenameArray = readdir(DIR);

# iterate over all files to find *.pm set
for my $file (@filenameArray) {
    if ( $file =~ m/      # matching regex
                      \.  # literal period character
                      pm  # the pm file extenstion
                  /x      # end of regex
       )
    {

        my $return = `perl D:/Perl/site/bin/perltidy -q --indent-columns=4 --maximum-line-length=80 -html -opath blib/libhtml2 -toc $libLocation/$file`;

        if ($return eq "") {
            print "HTMLized " . $file . "\n";
        }
        else {
            print "Error: " . $return . "\n";
        }

    }

}

But I was really hoping there was a way to use Module::Build and just tell it with a flag or an argument or whatever to tell it to use a different HTML formatter. I guess that's a pipe dream, though:

use strict;
use warnings;
use Module::Build;

my $build = Module::Build->resume (
  properties => {
    config_dir => '_build',
  },
);

$build->dispatch('build');
$build->dispatch('html', engine => 'perltidy');

or maybe:

$build->dispatch('htmltidy');

Solution

  • Well, the action is implemented in

    htmlify_pods
    

    in Module::Build::Base.

    It should be possible to override that method.

    Much Later ...

    Here is my attempt (tested only once):

    package My::Builder;
    
    use strict;
    use warnings;
    
    use base 'Module::Build';
    
    sub htmlify_pods {
      my $self = shift;
      my $type = shift;
      my $htmldir = shift || File::Spec->catdir($self->blib, "${type}html");
    
      require Module::Build::Base;
      require Module::Build::PodParser;
      require Perl::Tidy;
    
      $self->add_to_cleanup('pod2htm*');
    
      my $pods = $self->_find_pods( 
          $self->{properties}{"${type}doc_dirs"},
          exclude => [ Module::Build::Base::file_qr('\.(?:bat|com|html)$') ] );
      return unless %$pods;  # nothing to do
    
      unless ( -d $htmldir ) {
        File::Path::mkpath($htmldir, 0, oct(755))
          or die "Couldn't mkdir $htmldir: $!";
      }
    
      my @rootdirs = ($type eq 'bin') ? qw(bin) :
          $self->installdirs eq 'core' ? qw(lib) : qw(site lib);
    
      my $podpath = join ':',
                    map  $_->[1],
                    grep -e $_->[0],
                    map  [File::Spec->catdir($self->blib, $_), $_],
                    qw( script lib );
    
      foreach my $pod ( keys %$pods ) {
    
        my ($name, $path) = File::Basename::fileparse($pods->{$pod},
            Module::Build::Base::file_qr('\.(?:pm|plx?|pod)$'));
        my @dirs = File::Spec->splitdir( File::Spec->canonpath( $path ) );
        pop( @dirs ) if $dirs[-1] eq File::Spec->curdir;
    
        my $fulldir = File::Spec->catfile($htmldir, @rootdirs, @dirs);
        my $outfile = File::Spec->catfile($fulldir, "${name}.html");
        my $infile  = File::Spec->abs2rel($pod);
    
        next if $self->up_to_date($infile, $outfile);
    
        unless ( -d $fulldir ){
          File::Path::mkpath($fulldir, 0, oct(755))
            or die "Couldn't mkdir $fulldir: $!";
        }
    
        my $path2root = join( '/', ('..') x (@rootdirs+@dirs) );
        my $htmlroot = join( '/',
                 ($path2root,
                  $self->installdirs eq 'core' ? () : qw(site) ) );
    
        my $fh = IO::File->new($infile) or die "Can't read $infile: $!";
        my $abstract = Module::Build::PodParser->new(fh => $fh)->get_abstract();
    
        my $title = join( '::', (@dirs, $name) );
        $title .= " - $abstract" if $abstract;
    
        my %opts = (
            argv => join(" ", 
                qw( -html --podflush ),
                "--title=$title",
                '--podroot='.$self->blib,
                "--htmlroot=$htmlroot",
                "--podpath=$podpath",
            ),
            source => $infile,
            destination => $outfile,
        );
    
        if ( eval{Pod::Html->VERSION(1.03)} ) {
          $opts{argv} .= ' --podheader';
          $opts{argv} .= ' --backlink=Back to Top';
          if ( $self->html_css ) {
              $opts{argv} .= " --css=$path2root/" . $self->html_css;
          }
        }
    
        $self->log_info("HTMLifying $infile -> $outfile\n");
        $self->log_verbose("perltidy %opts\n");
        Perl::Tidy::perltidy(%opts);    # or warn "pod2html @opts failed: $!";
      }
    }
    1;
    

    ** To use it .. **

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use My::Builder;
    
    my $builder = My::Builder->new(
        module_name => 'My::Test',
        license     => 'perl',
    );
    
    $builder->create_build_script;