Hi all,

The other day, one of my templates started doing something mysterious.
I couldn't figure it out for a good while.  After a night's sleep, the
explanation occurred to me, and I thought I'd share it, in case it
helps someone else.

Below is some code that demonstrates what was mysterious.

The first subroutine, var_test() shows that you can set a TMPL_VAR from
outside a TMPL_LOOP, as long as you include global_vars=>1.  This works
even if the TMPL_VAR does not appear elsewhere in the template outside
the loop.

The second subroutine, loop_test1() shows that you can also set a
TMPL_LOOP from outside another TMPL_LOOP, as long as you again include
global_vars=>1, but--and here's the mystery--only as long as the one
TMPL_LOOP *also* appears in the template somewhere *outside* the other
loop.

The third subroutine, loop_test2() is just like loop_test1(), except
that the trees TMPL_LOOP *only* appears *inside* the forest loop.
Because of this (apparently), the values in the trees loop are not set
by H::T->param().

So the mystery was that my TMPL_VAR (global) settings were showing up
inside my loop (even when they didn't appear anywhere else in the
template), but my TMPL_LOOP ("global") settings where disappearing from
inside my loop when I removed them from elsewhere in the template.
Very much head scratching occurred.

This is an obscure problem, and reorganizing the template and the code
was dead simple.  But I just had to track down the explanation so I
would know what to avoid next time.

The use case where this came up was a spreadsheet report with subtotals
and grand totals.  I was using the labels from the grand totals loop
for each of the sub-groups.  When I wanted to use the same code to
generate a report for just one sub-group, without grand totals, I
removed the grand totals loop from the bottom of the template, and all
of a sudden the labels for the one sub-group just disappeared.

Regards,

Brad

#!/usr/local/bin/perl

use strict;
use warnings;
use HTML::Template;

var_test();    # [maple trees, rotten logs]
loop_test1();  # [maple trees, rotten logs] {maple trees}
loop_test2();  # [ trees, rotten logs]

#---------------------------------------------------------------------
# want to use short-hand tags TV => TMPL_VAR, TL => TMPL_LOOP
sub filter {
    for( ${$_[0]} ) {
        s| <TV (.*?)> |<TMPL_VAR $1>|gx;
        s| <TL (.*?)> |<TMPL_LOOP $1>|gx;
        s| </TL>      |</TMPL_LOOP>|gx;
    }
}

#---------------------------------------------------------------------
sub var_test {
    my $text =
"[<TL forest><TV trees> trees, <TV logs> logs</TL>]\n";

    my $sref = \$text;
    my $tmpl = HTML::Template->new(
        scalarref         => $sref,
        global_vars       => 1,
        die_on_bad_params => 0,  # not strictly needed here
        filter            => \&filter,
        );

    # trees var is set "outside" of forest, so needs global_vars=>1
    $tmpl->param( trees  => 'maple' );
    $tmpl->param( forest => [{ logs => 'rotten' }] );

    print $tmpl->output;
}

#---------------------------------------------------------------------
sub loop_test1 {
    my $text = join '' =>
"[<TL forest><TL trees><TV type></TL> trees, <TV logs> logs</TL>] ",
"{<TL trees><TV type></TL> trees}\n";

    my $sref = \$text;
    my $tmpl = HTML::Template->new(
        scalarref         => $sref,
        global_vars       => 1,
        die_on_bad_params => 0,  # not strictly needed here
        filter            => \&filter,
        );

    # trees loop is set "outside" of forest, so needs global_vars=>1
    $tmpl->param( trees  => [{ type => 'maple'  }] );
    $tmpl->param( forest => [{ logs => 'rotten' }] );

    print $tmpl->output;
}

#---------------------------------------------------------------------
sub loop_test2 {
    my $text =
"[<TL forest><TL trees><TV type></TL> trees, <TV logs> logs</TL>]\n";

    my $sref = \$text;
    my $tmpl = HTML::Template->new(
        scalarref         => $sref,
        global_vars       => 1,
        die_on_bad_params => 0,  # definitely needed here
        filter            => \&filter,
        );

    # trees loop is set "outside" of forest, so needs global_vars=>1
    # but also needs die_on_bad_param=>0 to avoid error
    $tmpl->param( trees  => [{ type => 'maple'  }] );
    $tmpl->param( forest => [{ logs => 'rotten' }] );

    print $tmpl->output;
}

__END__