Odd inconsistency with H::T->param()

Brad Baxter <[email protected]> Thu, 10 Dec 2009 13:29:03 -0500
Newsgroups gmane.comp.lang.perl.modules.html-template
Message-ID <[email protected]>
--===============4225771234999874162==
Content-Type: multipart/alternative; boundary=00151774177a7c3d1e047a63fc89

--00151774177a7c3d1e047a63fc89
Content-Type: text/plain; charset=ISO-8859-1

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__

--00151774177a7c3d1e047a63fc89
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

Hi all,<br><div class=3D"gmail_quote"><br>The other day, one of my template=
s started doing something mysterious.<br>I couldn&#39;t figure it out for a=
 good while.=A0 After a night&#39;s sleep, the<br>explanation occurred to m=
e, and I thought I&#39;d share it, in case it<br>


helps someone else.<br><br>Below is some code that demonstrates what was my=
sterious.<br><br>The first subroutine, var_test() shows that you can set a =
TMPL_VAR from<br>outside a TMPL_LOOP, as long as you include global_vars=3D=
&gt;1.=A0 This works<br>


even if the TMPL_VAR does not appear elsewhere in the template outside<br>t=
he loop.<br><br>The second subroutine, loop_test1() shows that you can also=
 set a<br>TMPL_LOOP from outside another TMPL_LOOP, as long as you again in=
clude<br>


global_vars=3D&gt;1, but--and here&#39;s the mystery--only as long as the o=
ne<br>TMPL_LOOP *also* appears in the template somewhere *outside* the othe=
r<br>loop.<br><br>The third subroutine, loop_test2() is just like loop_test=
1(), except<br>


that the trees TMPL_LOOP *only* appears *inside* the forest loop.<br>Becaus=
e of this (apparently), the values in the trees loop are not set<br>by H::T=
-&gt;param().<br><br>So the mystery was that my TMPL_VAR (global) settings =
were showing up<br>


inside my loop (even when they didn&#39;t appear anywhere else in the<br>te=
mplate), but my TMPL_LOOP (&quot;global&quot;) settings where disappearing =
from<br>inside my loop when I removed them from elsewhere in the template.<=
br>


Very much head scratching occurred.<br><br>This is an obscure problem, and =
reorganizing the template and the code<br>was dead simple.=A0 But I just ha=
d to track down the explanation so I<br>would know what to avoid next time.=
<br>


<br>The use case where this came up was a spreadsheet report with subtotals=
<br>and grand totals.=A0 I was using the labels from the grand totals loop<=
br>for each of the sub-groups.=A0 When I wanted to use the same code to<br>


generate a report for just one sub-group, without grand totals, I<br>remove=
d the grand totals loop from the bottom of the template, and all<br>of a su=
dden the labels for the one sub-group just disappeared.<br><br>Regards,<br>


<br>Brad<br><br>#!/usr/local/bin/perl<br><br>use strict;<br>use warnings;<b=
r>use HTML::Template;<br><br>var_test();=A0=A0=A0 # [maple trees, rotten lo=
gs]<br>loop_test1();=A0 # [maple trees, rotten logs] {maple trees} <br>loop=
_test2();=A0 # [ trees, rotten logs]<br>


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


=A0=A0=A0=A0=A0=A0=A0 s| &lt;TL (.*?)&gt; |&lt;TMPL_LOOP $1&gt;|gx;<br>=A0=
=A0=A0=A0=A0=A0=A0 s| &lt;/TL&gt;=A0=A0=A0=A0=A0 |&lt;/TMPL_LOOP&gt;|gx;<br=
>=A0=A0=A0 }<br>}<br><br>#-------------------------------------------------=
--------------------<br>sub var_test { <br>


=A0=A0=A0 my $text =3D<br>&quot;[&lt;TL forest&gt;&lt;TV trees&gt; trees, &=
lt;TV logs&gt; logs&lt;/TL&gt;]\n&quot;;<br><br>=A0=A0=A0 my $sref =3D \$te=
xt;<br>=A0=A0=A0 my $tmpl =3D HTML::Template-&gt;new(<br>=A0=A0=A0=A0=A0=A0=
=A0 scalarref=A0=A0=A0=A0=A0=A0=A0=A0 =3D&gt; $sref,<br>


=A0=A0=A0=A0=A0=A0=A0 global_vars=A0=A0=A0=A0=A0=A0 =3D&gt; 1,<br>=A0=A0=A0=
=A0=A0=A0=A0 die_on_bad_params =3D&gt; 0,=A0 # not strictly needed here<br>=
=A0=A0=A0=A0=A0=A0=A0 filter=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D&gt; \&amp=
;filter,<br>=A0=A0=A0=A0=A0=A0=A0 );<br><br>=A0=A0=A0 # trees var is set &q=
uot;outside&quot; of forest, so needs global_vars=3D&gt;1<br>


=A0=A0=A0 $tmpl-&gt;param( trees=A0 =3D&gt; &#39;maple&#39; );<br>=A0=A0=A0=
 $tmpl-&gt;param( forest =3D&gt; [{ logs =3D&gt; &#39;rotten&#39; }] );<br>=
<br>=A0=A0=A0 print $tmpl-&gt;output;<br>}<br><br>#------------------------=
---------------------------------------------<br>


sub loop_test1 {<br>=A0=A0=A0 my $text =3D join &#39;&#39; =3D&gt;<br>&quot=
;[&lt;TL forest&gt;&lt;TL trees&gt;&lt;TV type&gt;&lt;/TL&gt; trees, &lt;TV=
 logs&gt; logs&lt;/TL&gt;] &quot;,<br>&quot;{&lt;TL trees&gt;&lt;TV type&gt=
;&lt;/TL&gt; trees}\n&quot;;<br>


<br>=A0=A0=A0 my $sref =3D \$text;<br>=A0=A0=A0 my $tmpl =3D HTML::Template=
-&gt;new(<br>=A0=A0=A0=A0=A0=A0=A0 scalarref=A0=A0=A0=A0=A0=A0=A0=A0 =3D&gt=
; $sref,<br>=A0=A0=A0=A0=A0=A0=A0 global_vars=A0=A0=A0=A0=A0=A0 =3D&gt; 1,<=
br>=A0=A0=A0=A0=A0=A0=A0 die_on_bad_params =3D&gt; 0,=A0 # not strictly nee=
ded here<br>=A0=A0=A0=A0=A0=A0=A0 filter=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =
=3D&gt; \&amp;filter,<br>


=A0=A0=A0=A0=A0=A0=A0 );<br><br>=A0=A0=A0 # trees loop is set &quot;outside=
&quot; of forest, so needs global_vars=3D&gt;1<br>=A0=A0=A0 $tmpl-&gt;param=
( trees=A0 =3D&gt; [{ type =3D&gt; &#39;maple&#39;=A0 }] );<br>=A0=A0=A0 $t=
mpl-&gt;param( forest =3D&gt; [{ logs =3D&gt; &#39;rotten&#39; }] );<br>


<br>=A0=A0=A0 print $tmpl-&gt;output;<br>}<br><br>#------------------------=
---------------------------------------------<br>sub loop_test2 {<br>=A0=A0=
=A0 my $text =3D<br>&quot;[&lt;TL forest&gt;&lt;TL trees&gt;&lt;TV type&gt;=
&lt;/TL&gt; trees, &lt;TV logs&gt; logs&lt;/TL&gt;]\n&quot;;<br>


<br>=A0=A0=A0 my $sref =3D \$text;<br>=A0=A0=A0 my $tmpl =3D HTML::Template=
-&gt;new(<br>=A0=A0=A0=A0=A0=A0=A0 scalarref=A0=A0=A0=A0=A0=A0=A0=A0 =3D&gt=
; $sref,<br>=A0=A0=A0=A0=A0=A0=A0 global_vars=A0=A0=A0=A0=A0=A0 =3D&gt; 1,<=
br>=A0=A0=A0=A0=A0=A0=A0 die_on_bad_params =3D&gt; 0,=A0 # definitely neede=
d here<br>=A0=A0=A0=A0=A0=A0=A0 filter=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =3D=
&gt; \&amp;filter,<br>


=A0=A0=A0=A0=A0=A0=A0 );<br><br>=A0=A0=A0 # trees loop is set &quot;outside=
&quot; of forest, so needs global_vars=3D&gt;1<br>=A0=A0=A0 # but also need=
s die_on_bad_param=3D&gt;0 to avoid error<br>=A0=A0=A0 $tmpl-&gt;param( tre=
es=A0 =3D&gt; [{ type =3D&gt; &#39;maple&#39;=A0 }] );<br>


=A0=A0=A0 $tmpl-&gt;param( forest =3D&gt; [{ logs =3D&gt; &#39;rotten&#39; =
}] );<br><br>=A0=A0=A0 print $tmpl-&gt;output;<br>}<br><br>__END__<br><br>
</div>

--00151774177a7c3d1e047a63fc89--


--===============4225771234999874162==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

------------------------------------------------------------------------------
Return on Information:
Google Enterprise Search pays you back
Get the facts.
http://p.sf.net/sfu/google-dev2dev

--===============4225771234999874162==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
Html-template-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/html-template-users

--===============4225771234999874162==--