Skip to content
Snippets Groups Projects
make_pdf_from_pod.pl 2.79 KiB
Newer Older
#!/usr/bin/env perl
use Modern::Perl;

## script to generate a single PDF file with all POD documentation
## Based on https://gist.github.com/wki/2277444

BEGIN {
    if (@ARGV != 2) {
        print STDERR "usage: $0 DIR OUTPUT\n";
        exit 1;
    }
}

{
    # a simple class that uses App::pod2pdf to create pdfs containing many pod files
    # The hierarchical outline is generated on the fly while traversing directories

    package MultiPDF;
    use Moose;
    use Path::Class;
    use App::pod2pdf;

    has parser => (
        is => 'ro',
        isa => 'App::pod2pdf',
        lazy => 1,
        default => sub { App::pod2pdf->new },
    );

    has pdf => (
        is => 'ro',
        isa => 'PDF::API2',
        lazy => 1,
        builder => '_build_pdf',
    );

    sub _build_pdf {
        my $self = shift;

        $self->parser->{pdf},
    }

    sub process_file {
        my $self = shift;
        my $file = shift;

        say "processing file: $file";

        $self->parser->parse_from_file($file->stringify);
        $self->parser->formfeed;
        
        return $self;
    }

    sub process_dir {
        my $self = shift;
        my $dir = Path::Class::Dir->new(shift);

        my %structure; # { _outline => PDF::API2::Outline }

        $dir->recurse(
            depthfirst => 1,
            callback => sub {
                my $file = shift;

                return if !-f $file || $file->basename !~ m{[.](?:pm|pod|pl) \z}xms;
                
                ## Look for POD tags to skip files without documentation
                my $fh = $file->open or die "Failed to open ".$file->basename ;
                my $has_pod = 0;
                while (<$fh>) {
                    $has_pod = 1 if (/^=head1/);
                }
                close $fh;
                
                return unless ($has_pod);

                my $nr_pages = $self->pdf->pages;
                $self->process_file($file);

                my $name = $file->basename;
                $name =~ s{[.]\w+ \z}{}xms;

                my $tree = \%structure;
                my $outline = $structure{_outline} ||= $self->pdf->outlines->outline;

                foreach my $part (grep { $_ ne '.' } $file->relative($dir)->dir->dir_list, $name) {
                    $tree = $tree->{$part} ||= { _outline => $outline->outline };
                    $outline = $tree->{_outline};
                    $outline->title($part);
                }
                $outline->dest($self->pdf->openpage($nr_pages));
            }
        );
        
        return $self;
    }

    sub print {
        my $self = shift;

        $self->parser->output;
    }

    sub save_as {
        my $self = shift;
        my $path = shift;

        $self->pdf->saveas($path);
    }
}

MultiPDF->new
        ->process_dir($ARGV[0])
        ->save_as($ARGV[1]);