NAME
LaTeX::Replicase - Perl extension implementing a minimalistic engine for filling real TeX-LaTeX files that act as templates.
SYNOPSIS
Activate the module:
use LaTeX::Replicase qw( replication );
or
use LaTeX::Replicase qw(:all);
Usage examples:
- 1. Using
replication()with default options. -
The following pseudo-code extract demonstrates this:
Fragment of the original (source) TeX file with fillable fields
myParam,myArray,myHash,myTable_array, andmyTable_hash:SPECIFY VALUE of myParam! %%%V: myParam -- substitutes Variable etc... \begin{tcolorbox} \rule{0mm}{4.5em}%%%VAR: myParam -- substitutes Variable as well ... ... SPECIFY VALUE of myParam! ... %%%END: \end{tcolorbox} \begin{tabular}{lllll} % head of table Expense item & %%%VAR: myArray \multicolumn{1}{c}{% %%%ADD: 2020 %%%V:@% there will be no line break } %%%ADD: & %%%ADDX: 2021 & 2022 & 2023 %%%END: \\ \hline etc... \\ \hline Summary %%%VAR: myHash & %%%ADD: 00000 %%%V: year0 & 11111 %%%V: year1 & 22222 %%%V: year2% there will be no line break & 33333 %%%V: year3 %%%END: \\ \hline \end{tabular} \begin{tabular}{ccccc} column0 & column1 & column2 & column3 & column4 \\ \toprule %%%VAR: myTable_array %%%ADD: %add " \n" at beginning of value in the 0th column without any conditions for all rows %%%ADD1: \midrule %%%ADD1: ... % continuation of ADD1 %%%ADD2: ... %%%ADD3: ... SPECIFY VALUE 0! %%%V:0 & %%%ADD: %add " &\n" at beginning of value in the 1st column without any conditions for all rows %%%ADD1: ... %%%ADD2: ... SPECIFY VALUE 1! %%%V:1 & %%%ADD: %%%ADD1: ... %%%ADD2: ... SPECIFY VALUE 2! %%%V:2 & %%%ADD: %%%ADD1: ... %%%ADD2: ... SPECIFY VALUE 3! %%%V:3 & %%%ADD: SPECIFY VALUE 4! %%%V:4 \\%%%ADD: \midrule%%%ADD: %%%ADD5: ... ... VALUE 0 & VALUE 1 & VALUE 2 & VALUE 3 & VALUE 4 % All of this will be replaced until %%%END: \\ \midrule ... %%%END: \end{tabular} ... \begin{tabbing} %%%VAR: myTable_hash %%%ADDX: \\ SPECIFY VALUE 'A'! %%%V: A \= %%%ADD: SPECIFY VALUE 'B'! %%%V: B% there will be no line break \= %%%ADD: SPECIFY VALUE 'C'! %%%V: C \= %%%ADD: SPECIFY VALUE 'D'! %%%V: D \= %%%ADD: SPECIFY VALUE 'E'! %%%V: E %%%END: \end{tabbing}Data to fill TeX file (see above):
my $info = { data => { # mandatory data section myParam => 'Blah-blah blah-blah blah-blah', myArray => [2024, 2025, 2026, 2027], myHash => {year0 => 123456, year1 => 789012, year2 => 345678, year3 => 901234,} myTable_array => [ # custom user variable ARRAY-ARRAY [00, 01, 02, 03, 04,], # row 0 [10, 11, 12, 13, 14,], # row 1 [20, 21, 22, 23, 24,], # row 2 [30, 31, 32, 33, 34,], # row 3 ], myTable_hash => [ # custom user variable ARRAY-HASH {A=>00, B=>01, C=>02, D=>03, E=>04,}, # row 0 {A=>10, B=>11, C=>12, D=>13, E=>14,}, # row 1 {A=>20, B=>21, C=>22, D=>23, E=>24,}, # row 2 {A=>30, B=>31, C=>32, D=>33, E=>34,}, # row 3 ], }, cases => { # optional auxiliary data section myTable_array => { 0 => { # table row 0 3 => [1, 2], # extract from document %%%ADD1: and %%%ADD2: for 3-rd table column #... }, 2 => { # table row 2 0 => [1, 3], # extract %%%ADD1: and %%%ADD3: for 0-th column 1 => 2, # extract only %%%ADD2: for 1-st column #... # '' -- empty parameter (without column idx) '' => 5, # extract only %%%ADD5: located at the very "tail" of row }, }, myTable_hash => { 1 => { # table row 1 B => 1, # extract %%%ADD1: (if exists) for 'B' key (1-st position) A => [1, 3], # extract %%%ADD1: and %%%ADD3: (if exists) for 'A' key (0-th position) #... }, 0 => { # table row 0 B => 2, # extract %%%ADD2: (if exists) C => [1, 2], # extract %%%ADD1: and %%%ADD2: for 'C' key (2-nd position) #... }, }, }, }; my $msg = replication( $file, $info );
A new TeX
base_filefrom the template$filefilled with data from$infowill be created in random subdirectory (its name is stored in$$variable) of current directory. File name of source$filecan be absolute, i.e. with a full path (include directories and subdirectories).base_filename is extracted (same) from source$file. Under no circumstances will source$filebe overwritten by newbase_file. - 2. Using
outdiroption: -
my $msg = replication( $file, $info, outdir => $target_dir );A new
$filewill be created in$target_dirdirectory. - 3. Using
ofileoption: -
my $msg = replication( $file, $info, ofile => $ofile );A new
$ofilewill be created.ofileoption suppresses (eliminates)outdiroption, i.e. file name of$ofilecan be absolute. Under no circumstances will source$filebe overwritten by new$ofile. - 4. Set the
$DEBUGpackage variable to enable debugging messages (global debug mode): -
$LaTeX::Replicase::DEBUG = 1;
LIMITATIONS
This module have reason only for SCALAR, ARRAY, HASH, ARRAY.ARRAY, ARRAY.HASH, ARRAY.ARRAY.ARRAY, ARRAY.HASH.ARRAY data with perl 5.10 and higher. =head1 ABSTRACT
Replicase is minimalistic (ascetic) interpreter (uses only 3-4 control tags) which can be used for processing (filling) real TeX-LaTeX files that act as templates.
DESCRIPTION
This module is a Perl 5 extension implementing Replicase subroutines which processes TeX-LaTeX files, interpreting and executing built-in control directives (tags) of Replicase.
Replicase can: define and substitute variable values, execute conditional actions and capture the resulting output into a new document. Replicase was originally designed for creating programmatically configurable TeX-LaTeX documents.
Unlike other template engines, here the logic and cycles are completely separated from TeX-LaTeX document and are moved to your Perl program using this module. It's well suited for this and similar tasks, allowing you to dynamically create PDF documents that are consistent with each other, yet easily customisable.
Replicase is a standalones, safe as a TeX-LaTeX, and fast template engine with remarkable features. All markup is based on following "three pillars" (directives, tags):
%%%V: variable_nameis a short form of a regular (SCALAR) variable_name that completely replaces the string in which it is located, e.g.Blah, blah, \ldots blah. %%%V: myParamwill be completely replaced by contents of
myParamvariable.It can be nested in an ARRAY or HASH
%%%VAR:tag, but in SCALAR%%%VAR:it will not work and will be discarded.There's a special name
@, which means to use all elements of an ARRAY. Therefore, this only makes sense for ARRAY variables (see example above).If a
variable_nameends in % (i.e.variable_name%), a newline is suppressed. (By default, a newline always occurs after value substitution).%%%VAR: variable_nameis start of full form of regular (SCALAR) or complex (ARRAY, HASH) variable_name, preserving preceding TeX up to %%%VAR: but completely replacing everything up to first%%%END:(or a new%%%VAR:) tag inclusive.Blah, blah, \ldots blah. %%%VAR: myParam Blah, blah, \ldots \ldots Blah, \ldots %%%END:Usually ARRAY and HASH variable_name are used in the template to create (fill) tables.
CONCLUSION: Nested
%%%VAR:tags will not work and are treated as%%%END:tags.%%%END:is used to specify the end of%%%VAR:tag. Text located in line with%%%END:will be discarded.BTW: If this tag is omitted and there are no further
%%%VAR:tag, all text to the end of document will be replaced byvariable_namespecified in%%%VAR:tag.
The following tags can be located within the block limited by ARRAY and HASH %%%VAR: and %%%END: tags:
%%%V: key|indexwith setting ofkey(in case of HASH%%%VAR:, i.e.%%%V: keyA,%%%V:keyB, etc.) orindex(in case ARRAY%%%VAR:, i.e.%%%V:0,%%%V:1,%%%V:2, etc.). Herekeysorindexesare columns (or positions) of the table (filled area) being created.%%%ADD:without any conditions adds text before (or after) all%%%ADD[\d+]:tags (if exists) and before variable specified in%%%V:tag. The added text is taken from the beginning of the line to the beginning of%%%ADD:(i.e. text located on the left), e.g.Head blah, blah, \ldots blah. %%%ADD: Tail blah, blah, \ldotsthis text will be added:
Head blah, blah, \ldots blah.Or, if
%%%ADD:is located at the very beginning of line, then after it to the end of line (i.e. text located on the right), e.g.%%%ADD: Tail blah, blah, \ldotsthis text will be added:
Tail blah, blah, \ldots.If the following
%%%V:tag is not present, then the text is output at the end of allkeysorindexes(columns) each table row, before (or after) text-blocks of all%%%ADD[\d+]:tags (if exists).%%%ADDX:similar to%%%ADD:for all lines (records) eXcept the first column (0) of first record (0) or after the last column of last record (i.e. if key '' exists).%%%ADD0:,%%%ADD1:, ...%%%ADD[\d+]:conditionally adds text before variable specified in%%%V:tag. This tag is triggered if its[\d+]index is specified for the corresponding row(s) in additional settingscaseshash.Similar to
%%%ADD:, here the added text is taken from the beginning of the line to the beginning of%%%ADD[\d+]:(i.e. text located on the left) or, if%%%ADD[\d+]:is located at the very beginning of line, then after it to the end of line (i.e. text located on the right).There can be as many
%%%ADD[\d+]:tags as you like.If
%%%ADD[\d+]:tags within the same%%%V:have the same[\d+]index, their texts are merged.%%%ADD[\d+]:tags are only valid when%%%VAR:is ARRAY, and following%%%V:tag exists, and is defined in the inputdata.If there is no following
%%%V:tag, text is output at the end of allkeysorindexes(columns) each table row. In the additional settingscaseshash these%%%ADD[\d+]:must correspond to key with a name of zero length (i.e'').BTW: in general,
%%%ADD[\d+]:tag existence is extremely redundant and is intended for the lazy (author himself rarely uses it). This tag can easily be replaced with a combination of auxiliary parameters and thedefoption (see below), which specifies discarding (ignoring)undefinedvalues and associated structures%%%ADD:. For example:%%%VAR: myTable \\ %%%ADD: % %%%V: head etc... \\ %%%ADD: \midrule %%%ADD: % %%%V: rule my $info = { data => { myTable => [ {head =>'%', ... }, # 'rule' is undefined {rule =>'%', ... }, # 'head' is undefined ... ] ... } }; my $msg = replication( $file, $info, def =>1 );
Only ONE tag can be located on ONE line of input $file (document).
Tag names must be in %%%UPPERCASE:.
SUBROUTINES
LaTeX::Replicase provides these subroutines:
replication( $file, $info [, %facultative_options ] );
tex_escape( $value [, '~'] );
replication( $file, $info [, %facultative_options ] )
Creates a new output file from the specified TeX $file, which is a template. $info hash is used to fill template.
File name of source $file can be absolute, i.e. with a full path (include directories and subdirectories).
The output file name is extracted (the same) from the source $file. Under no circumstances will source $file be overwritten by the new one.
When replication processes a $file it identifies tags and replaces them with the result of whatever the tag represents (e.g. variable value for %%%V: or from %%%VAR: to %%%END:). Anything outside the tag(s), including newline characters, are left intact.
The following %facultative_options can be used when calling replication:
outdir:-
my $msg = replication( $file, $info, outdir => $target_dir );A new
$filewill be created in$target_dirdirectory. ofile:-
my $msg = replication( $file, $info, ofile => $ofile );A new
$ofilewill be created.ofileoption suppresses (eliminates)outdiroption, i.e. file name of$ofilecan be absolute. utf8-
This option specifies the template and output files' character encoding as utf8:
my $msg = replication( $file, $info, utf8 =>1 ); esc-
This option applies
tex_escape()subroutine to all incoming values to mask active TeX characters:&%$#_{}~^\.my $msg = replication( $file, $info, esc =>1 ); # or esc =>'~'BTW: If the value starts with the
%%%:tag, then this tag is removed (e.g.%%%:$\frac{12345}{67890}$to$\frac{12345}{67890}$), and the value itself is not masked, it is skipped. def-
This option specifies discarding (ignoring)
undefinedvalues and associated structures (%%%ADD...), i.e. take into account onlydefinedvalues.my $msg = replication( $file, $info, def =>1 );This option is useful, for example, for creating merged cells in tables (using
\multicolumnLaTeX-command). This option applies to all incoming data. ignore-
This option specifies silently ignore undefined name|key|index of
%%%V:and%%%VAR:tags:my $msg = replication( $file, $info, ignore =>1 ); silent-
This option activates silent mode of operation:
my $msg = replication( $file, $info, silent =>1 ); debug-
This option sets local debug mode:
my $msg = replication( $file, $info, debug =>1 ); if( ! $msg ) { say 'Ok'; } else { say for @$msg; }Another way is to set the
$DEBUGpackage variable to enable debugging messages (global debug mode).$LaTeX::Replicase::DEBUG = 1;
replication returns undef or a reference to an error (and/or debug) message(s) array.
tex_escape( $value [, '~'] )
Masks (or replaces with equivalents) the active TeX characters & % $ # _ { } ^ \ to \& \% \$ \# \_ \{ \} \^{} \textbackslash in the input $value.
tex_escape( $value );
With the facultative (optional) option ~ you can replace the character ~ with \texttt{\~{}}.
tex_escape( $value, '~');
If the $value starts with the %%%: tag, then this tag is removed (e.g. $value = '%%%:$\frac{12345}{67890}$' to $value = '$\frac{12345}{67890}$'), and the value itself is not masked, it is skipped.
EXPORT
LaTeX::Replicase exports nothing by default. Each of the subroutines can be exported on demand, as in
use LaTeX::Replicase qw( replication );
and the tag all exports them all:
use LaTeX::Replicase qw( :all );
DEPENDENCIES
LaTeX::Replicase is known to run under perl 5.10.0 on Linux. The distribution uses File::Basename, File::Path, File::Compare, and Carp.
SEE ALSO
Perl modules that offer similar functionality:
Template::Latex, LaTeX::Easy::Templates
AUTHOR
Alessandro N. Gorohovski, <an.gorohovski@gmail.com>
COPYRIGHT AND LICENSE
Copyright (C) 2025 by Alessandro N. Gorohovski
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.10.0 or, at your option, any later version of Perl 5 you may have available.