Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend Template Toolkit with a new directive that inherits from INCLUDE directive #59

Open
hakonhagland opened this issue Dec 16, 2016 · 3 comments

Comments

@hakonhagland
Copy link

Hi!

I am considering to use the Template Toolkit to parse LaTeX. I would like to create a system of snippets
similar to the Perl module hierarchy of reusable code. This should help me not repeating paragraphs, sections, or chapters that are similar across several LaTeX documents.

Consider: main.tex

\documentclass[11pt,a4paper]{amsart}
\begin{document}
\title{Testing TTK}
\date{\today}
\maketitle

[[ IMPORT my/math/article/derivation1
   intro_sec='Introduction' ]]

From \eqref{eq:my:math:article:derivation1:1} it follows that ...
   
\bibliographystyle{plain}
\bibliography{myarticles}
\end{document}

and my/math/article/derivation1.tex

\section{[[ intro_sec ]]}
The equation of state is expressed in the form of the Helmholtz energy
as \cite{spa96:eqs}  
\begin{align}
  \label{eq:1}
  \frac{A(\rho, T)}{RT} = \phi(\delta, \tau) =
  \phi^o(\delta,\tau)+\phi^r(\delta, \tau)
\end{align}
where
\begin{align}
  \label{eq:2}
  \delta &= \frac{\rho}{\rho_c}\\
  \tau &= \frac{T_c}{T}.
\end{align}

So I created a new directive IMPORT that will be a superset of the INCLUDE directive. I would like the IMPORT directive to do the same as INCLUDE but also expand equation labels (and possibly more stuff). So \label{eq:1} should be converted to \label{eq:my:math:article:derivation1:1}, such that the parent document does not have to worry about conflicts in equation labels when importing a snippet.

My question is then: Is this a good idea, and is it possible to extend the Template Toolkit with new directives like IMPORT?

@hakonhagland
Copy link
Author

I checked the source code and I think it should be possible to add this functionality as configuration option, for example PRE_COMPILE_HOOK. I did some basic testing and it is currently working (see the pull #60).

@abw
Copy link
Owner

abw commented Dec 20, 2016

Hi Håkon, thanks for the patch.

It's a long time since I've written any LaTeX so I might be missing something. My apologies in advance if that's the case.

If you need to encode the template name in the \label{eq:1} then perhaps you could use component.name?

For example, here's a main.tt2 which defines a MACRO called eq(n) which adds n onto a colon-delimited form of the component template name:

[%  MACRO eq(n)
      BLOCK;
        component.name.remove('\.\w+$').replace('/', ':', 1); ':'; n;
      END;

    INCLUDE my/math/derivation.tt2;
%]

Here's my/math/derivation.tt2

LABEL:[% eq(1) %]
LABEL:[% eq(2) %]

The output when I run tpage main.tt2:

LABEL:my:math:derivation:1
LABEL:my:math:derivation:2

Does that solve your problem?

The other possibility here would be to create your own custom Template::Provider module which implements a wrapper around the _load() method. That gives you a way to manipulate the template text before it is compiled.

I'm not averse to adding new functionality to TT but I do need to be convinced that it's sufficiently useful to enough people to warrant adding to the core.

@hakonhagland
Copy link
Author

Hi abw. Thanks for the quick response and for letting me know about these options!

The macro seems nice, but I think I would try to keep the style \label{eq:1} instead of
\label{[[ eq(1) ]]} in the template files. In this way, it will not confuse AucTeX mode in the Emacs editor. Of course I could try to reprogram the editing modes in Emacs such that they can understand this new type of labels, but I think that would be more difficult than changing how the Perl Template Toolkit works.

Creating a custom provider works fine though! For example, to get the same functionality as the PRE_COMPILE_HOOK suggested in the pull request (main.pl) I did the following:

use Template;
use Template::Config;
use Template::Provider::Latex;

use lib './lib';

$Template::Config::PROVIDER = 'Template::Provider::Latex';
$Template::Provider::Latex::PRE_COMPILE_HOOK = \&my_pre_compile_hook;

my $config = {
    INCLUDE_PATH => '.', 
    POST_CHOMP   => 1,               # cleanup whitespace
    START_TAG => quotemeta('[['),
    END_TAG   => quotemeta(']]'),
};

my $tt = Template->new($config);

$tt->process( 'test.tt2' )  || die $tt->error(), "\n";

sub my_pre_compile_hook {
    my ( $data, $filename, $name )   = @_;

    $name =~ s/\.tt2$//;
    $name =~ s{/}{:}g;
    $data =~ 
      s/ (\\(?:eqref|ref|label)\{)  ((?:eq|tab|fig):)  (.*?) (\}) 
       / _my_pre_compile_do_subs( $name, $1, $2, $3, $4 )/gex;

    return $data;
}

sub _my_pre_compile_do_subs {
    my ( $name, $pre, $type, $label, $post ) = @_;

    $label = $name . ':' . $label;
    return $pre . $type . $label . $post;
}

And Template::Provider::Latex (lib/Template/Provider/Latex.pm) :

package Template::Provider::Latex;

use parent 'Template::Provider';

our $PRE_COMPILE_HOOK;

sub _load {
    my ($self, $name, $alias) = @_;
    my ($template, $error) = $self->SUPER::_load($name, $alias);
    if ( defined $PRE_COMPILE_HOOK ) {
        $template->{text} = $PRE_COMPILE_HOOK->(
            $template->{text}, $template->{path}, $template->{name}
        );
    }

    return ( $template, $error );
}

1;

The test templates: test.tt2:

Start..
[[ INCLUDE my/derivation.tt2 ]]
End..

and my/derivation.tt2:

\begin{align}
  \label{eq:1}
  y = x^2
\end{align}

and finally, the output from running main.pl :

Start..
\begin{align}
  \label{eq:my:derivation:1}
  y = x^2
\end{align}
End..

So the config option PRE_COMPILE_HOOK may not be warranted since the same effect can be achieved by subclassing Template::Provider as shown above.

Anyway, I am glad I discovered this toolkit, it looks very powerful :)
I wish to you a nice Christmas :)

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

No branches or pull requests

3 participants