NAME

Text::PageLayout - Distribute paragraphs onto pages, with headers and footers.

SYNOPSIS

use 5.010;
use Text::PageLayout;

my @paragraphs = ("a\nb\nc\nd\n") x 6,

# simple example
my $layout = Text::PageLayout->new(
    page_size   => 20,      # number of lines per page
    header      => "head\n",
    footer      => "foot\n",
    paragraphs  => \@paragraphs,    # REQUIRED
);

for my $p ( $layout->pages ) {
    say "Page No. ", $p->page_number;
    say $p;
}

# more complex example:
sub header {
    my %param = @_;
    if ($param{page_number} == 1) {
        return "header for first page\n";
    }
    return "== page %d of %d == \n";
}
sub process_template {
    my %param = @_;
    my $t = $param{template};
    if ($t =~ /%/) {
        return sprintf $t, $param{page_number}, $param{total_pages};
    }
    else {
        return $t;
    }
}
sub split_paragraph {
    my %param = @_;
    my ($first, $rest) = split /\n\n/, $param{paragraph}, 2;
    return ("$first\n", $rest);
}


$layout = Text::PageLayout->new(
    page_size           => 42,
    tolerance           => 2,
    paragraphs          => [ ... ],
    separator           => "\n\n",
    footer              => "\nCopyright (C) 2014 by M. Lenz\n",
    header              => \&header,
    process_template    => \&process_template,
    split_paragraph     => \&split_paragraph,
);

DESCRIPTION

Text::PageLayout breaks up a list of paragraphs into pages. It supports headers and footers, possibly varying by page number.

It operates under the assumption that all text blocks that are passed to (header, footer, paragraphs, separator) are either the empty string, or terminated by a newline. It also assumes that all those text blocks are properly line-wrapped already.

The header and footer can either be strings, or subroutines that will be called, and must return the string that is then used as a header or a footer. In both cases, the string that is used as header or footer can be post-processed with a custom callback process_template.

The layout of a result page is always the header first, then as many paragraphs as fit on the page, separated by separator, followed by as many blank lines as necessary to fill the page (if fillup_pages is set, which it is by default), followed by the footer.

If the naive layouting algorithm (take as many paragraphs as fit) leaves more than tolerance empty fill lines, the split_paragraph callback is called, which can attempt to split the paragraph into small chunks, which are nicer to format.

ATTRIBUTES

Attributes should be set in the constructor (Text::PageLayout->new), but most of them can also be set later on, for example the page_size attribute with $layout->page_size(42).

Note that all callbacks receive named arguments, i.e. are called like this:

$callback->(
    page_number => 1,
    total_pages => 2,
);

Callbacks must accept additional named arguments (future versions of this module might pass more arguments).

page_size

Max. number of lines on a result page.

Default: 67

tolerance

Number of empty lines to accept on a page before attempting to split paragraphs.

Default: 6 (subject to change)

paragraphs

An array reference of paragraphs (newline-terminated strings) that is to be split up in pages.

This attribute is required.

A string that is used as a per-page header (or header template, if process_template is set), or a callback that returns the header.

If used as a callback, it receives page_number as a named argument.

Default: empty string.

A string that is used as a per-page footer (or footer template, if process_template is set), or a callback that returns the footer.

If used as a callback, it receives page_number as a named argument.

Default: empty string.

fillup_pages

If set to a true value, pages are filled up to their maximum length by adding newlines before the footer.

Default: 1.

separator

A string that is used to separate multiple paragraphs on the same page.

Default: "\n" (newline)

split_paragraph

A callback that can split a paragraph into smaller chunks to create nicer layouts. If paragraphs exist that exceed the number of free lines on a page that only contains header or footer, this callback must split such a paragraph into smaller chunks, the first of which must fit on a page.

The return value must be a list of paragraphs.

It receives the arguments paragraph, max_lines and page_number. max_lines is the maximal number of lines that fit on the current page.

The default split_paragraph simply splits off the first max_lines as a sparate chunk, without any consideration for its content.

process_template

A callback that turns a header or footer template into the actual header or footer. It receives the named arguments template, element (which can be header or footer), page_number and total_pages.

It must return a string with the same number of lines as the template.

The default template callback simply returns the template.

METHODS

new

Creates a new Text::PageLayout object. Expects attributes as named arguments, with paragraphs being the only required attribute.

pages

Returns a list of Text::PageLayout::Page objects (which you can use like strings, if you want to).

AUTHOR

Moritz Lenz, <moritz at faui2k3.org>

BUGS

Please report any bugs or feature requests to bug-text-pagelayout at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Text-PageLayout. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

perldoc Text::PageLayout

You can also look for information at:

ACKNOWLEDGEMENTS

Thanks to noris network AG for letting the author develop and open-source this module.

LICENSE AND COPYRIGHT

Copyright 2014 Moritz Lenz. Written for noris network AG.

This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.

DEVELOPMENT

Development happens at github, see https://github.com/moritz/perl5-Text-Layout. Pull requests welcome!