Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@wki
Created April 1, 2012 18:08
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save wki/2277444 to your computer and use it in GitHub Desktop.
Save wki/2277444 to your computer and use it in GitHub Desktop.
create single PDF from many .pod or .pm files
#!/usr/bin/env perl
use Modern::Perl;
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) \z}xms;
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]);
@mlawren
Copy link

mlawren commented Apr 2, 2012

Hi Wolfgang,

I like the idea. I got this running on v5.10.1 by dropping the '2012' argument to Modern::Perl and it generates pages for each file found, but did not generate an outline. I don't know anything about PDF::API2 to know why this is the case.

For usability I also added the following (inside a BEGIN block because I hate waiting for Moose to start up when arguments are missing):

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

And this at the bottom:

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

Regards,
Mark.

@wki
Copy link
Author

wki commented Apr 3, 2012

Mark,

you are absolutely right. There is no need to force usage of Perl 5.14. There are more things to improve like handling .pm versus .pod files, omitting files without any documentation and maybe much more cases not handled right now. But for a first try I think it is not that bad.

I will try to operate with different versions of Perl in order to find out why outlines seem to work unreliably. The outline handling in PDF::API2 by itself is available since 2005 if I correctly read the 'Changes' file. So it looks like I did not handle this part right.

Thanks for your feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment