Thread: [htmltmpl] Nested templates
Brought to you by:
samtregar
From: Brad B. <bm...@ma...> - 2009-11-25 02:24:56
|
Hi all, I once tried to implement nested templates with HTML::Template. Below is an example of what I came up with: 1 #!/usr/local/bin/perl 2 3 use strict; 4 use warnings; 5 use HTML::Template; 6 7 my $text = <<__; 8 This is a <TMPL_VAR NAME="color"> bird. 9 This is a <TMPL_VAR NAME="<TMPL_VAR NAME="color">"> bird. 10 This is a <TMPL_VAR NAME="<TMPL_VAR NAME="<TMPL_VAR NAME="color">">"> bird. 11 __ 12 13 my $output = ''; 14 my $sref = \$text; 15 my $count; 16 17 while (1) { 18 $count++; 19 20 my $tmpl = HTML::Template->new( 21 scalarref => $sref, 22 strict => 0, 23 die_on_bad_params => 0, 24 case_sensitive => 1, 25 ); 26 27 $tmpl->param( color => 'blue' ); 28 $tmpl->param( blue => 'BLUE' ); 29 $tmpl->param( BLUE => '**BLUE**' ); 30 31 $text = $tmpl->output(); 32 33 print "\n$count:\n$text"; # debug 34 35 last if $output eq $text; # no changes since last time 36 $output = $text; 37 38 } 39 40 print "\nfinal: \n$output"; 41 42 __END__ 1: This is a blue bird. This is a <TMPL_VAR NAME="blue"> bird. This is a <TMPL_VAR NAME="<TMPL_VAR NAME="blue">"> bird. 2: This is a blue bird. This is a BLUE bird. This is a <TMPL_VAR NAME="BLUE"> bird. 3: This is a blue bird. This is a BLUE bird. This is a **BLUE** bird. 4: This is a blue bird. This is a BLUE bird. This is a **BLUE** bird. final: This is a blue bird. This is a BLUE bird. This is a **BLUE** bird. I would like a better way of doing this. The calls to new() on line 20, the copies on lines 31 and 36, and the compares on line 36 just seem all a bit much for what ought (I think) to be more like 1 while s/from/to/g; Is there a better way? Apologies if this has been beat to death in the past ... Regards, Brad |
From: Mathew R. <mat...@ne...> - 2009-11-25 03:15:34
|
<snip> that seems somewhat complicated - you could use a regex in the while loop, as in: while ($text =~ /<TMPL_/) { ... } instead of using a loop variable or breaking out of the loop. In particular it would save you having to do any string comparisons and would avoid the extra loop iteration. Mathew Robertson |
From: Michael P. <mp...@pl...> - 2009-11-25 14:34:31
|
On 11/24/2009 09:24 PM, Brad Baxter wrote: > Is there a better way? I've done this by using a different name for each pass. So something like: <pass2_var name="<tmpl_var name=foo>"> So you run it through HTML::Template once to get the output and then s/<pass2_/<tmpl_/gi; And then run it again. -- Michael Peters Plus Three, LP |
From: Alex T. <al...@ac...> - 2009-11-25 15:58:22
|
On Tue, 24 Nov 2009 21:24:30 -0500, Brad Baxter wrote > Hi all, > > I once tried to implement nested templates with HTML::Template. > Below is an example of what I came up with: > > 1 #!/usr/local/bin/perl > 2 > 3 use strict; > 4 use warnings; > 5 use HTML::Template; > 6 > 7 my $text = <<__; > 8 This is a <TMPL_VAR NAME="color"> bird. > 9 This is a <TMPL_VAR NAME="<TMPL_VAR NAME="color">"> bird. > 10 This is a <TMPL_VAR NAME="<TMPL_VAR NAME="<TMPL_VAR > NAME="color">">"> bird. > 11 __ > 12 > 13 my $output = ''; > 14 my $sref = \$text; > 15 my $count; > 16 > 17 while (1) { > 18 $count++; > 19 > 20 my $tmpl = HTML::Template->new( > 21 scalarref => $sref, > 22 strict => 0, > 23 die_on_bad_params => 0, > 24 case_sensitive => 1, > 25 ); > 26 > 27 $tmpl->param( color => 'blue' ); > 28 $tmpl->param( blue => 'BLUE' ); > 29 $tmpl->param( BLUE => '**BLUE**' ); > 30 > 31 $text = $tmpl->output(); > 32 > 33 print "\n$count:\n$text"; # debug > 34 > 35 last if $output eq $text; # no changes since last time > 36 $output = $text; > 37 > 38 } > 39 > 40 print "\nfinal: \n$output"; > 41 > 42 __END__ > > 1: > This is a blue bird. > This is a <TMPL_VAR NAME="blue"> bird. > This is a <TMPL_VAR NAME="<TMPL_VAR NAME="blue">"> bird. > > 2: > This is a blue bird. > This is a BLUE bird. > This is a <TMPL_VAR NAME="BLUE"> bird. > > 3: > This is a blue bird. > This is a BLUE bird. > This is a **BLUE** bird. > > 4: > This is a blue bird. > This is a BLUE bird. > This is a **BLUE** bird. > > final: > This is a blue bird. > This is a BLUE bird. > This is a **BLUE** bird. > > I would like a better way of doing this. The calls to > new() on line 20, the copies on lines 31 and 36, and > the compares on line 36 just seem all a bit much for > what ought (I think) to be more like > > 1 while s/from/to/g; > > Is there a better way? I would just do: #!/usr/local/bin/perl use strict; use warnings; use HTML::Template; my $template = qq| This is a <tmpl_var color> bird. This is a <tmpl_if is_blue>BLUE</tmpl_if> bird. This is a <tmpl_if is_blue>**BLUE**</tmpl_if> bird. |; # all the logic of what the color will be goes here my $color = 'blue'; my $tmpl = HTML::Template->new( scalarref => \$template, strict => 0, die_on_bad_params => 0, case_sensitive => 1, ); $tmpl->param( color => $color, is_blue => $color eq 'blue' ? 1 : 0, ); print $tmpl->output(); So many advantages. The logic is completely separate from the presentation. If you send the template to a speaker of a different language, they can localize that with no problems. The code is much shorter at 29 lines vs. 42 lines, and its much more clear to a future maintainer what is happening without any brain gymnastics. HTH, Alex |
From: Brad B. <bm...@ma...> - 2009-11-30 16:55:19
|
Yes, that solves a slightly different problem than my (admittedly somewhat pointless) example, but it doesn't address the nesting that I'm after. I don't do it a lot, but there are key points where I want to, and I like to be able to count on it working. I'd like there to be an option to new() that says, "Do repeated substitutions until there aren't any more". I suspect that would still incur a 'compile' step each time, but I'd hope it could avoid the copy from output() and the repeated param() calls. Thanks, Brad On Wed, Nov 25, 2009 at 10:58 AM, Alex Teslik <al...@ac...> wrote: > On Tue, 24 Nov 2009 21:24:30 -0500, Brad Baxter wrote >> >> Is there a better way? > > I would just do: > > #!/usr/local/bin/perl > > use strict; > use warnings; > use HTML::Template; > > my $template = qq| > This is a <tmpl_var color> bird. > This is a <tmpl_if is_blue>BLUE</tmpl_if> bird. > This is a <tmpl_if is_blue>**BLUE**</tmpl_if> bird. > |; > > # all the logic of what the color will be goes here > my $color = 'blue'; > > my $tmpl = HTML::Template->new( > scalarref => \$template, > strict => 0, > die_on_bad_params => 0, > case_sensitive => 1, > ); > > $tmpl->param( > color => $color, > is_blue => $color eq 'blue' ? 1 : 0, > ); > > print $tmpl->output(); > > So many advantages. The logic is completely separate from the presentation. If you send the template > to a speaker of a different language, they can localize that with no problems. The code is much > shorter at 29 lines vs. 42 lines, and its much more clear to a future maintainer what is happening > without any brain gymnastics. > > HTH, > Alex > -- Brad Baxter ---------------------------------------------------------------------- |
From: Brad B. <bm...@ma...> - 2009-11-30 16:42:15
|
Yes, that's better. It replaces a copy and compare (and extra loop) as you say with a regx match. I still have a copy, object creation, and repeated param settings that bother me, but I suspect this is the best I'm going to get without a significant change to H::T. Thanks, Brad On Tue, Nov 24, 2009 at 9:48 PM, Mathew Robertson <mat...@ne...> wrote: > <snip> > > that seems somewhat complicated - you could use a regex in the while loop, > as in: > > while ($text =~ /<TMPL_/) { ... } > > instead of using a loop variable or breaking out of the loop. In particular > it would save you having to do any string comparisons and would avoid the > extra loop iteration. > > Mathew Robertson > > -- Brad Baxter ---------------------------------------------------------------------- |
From: Brad B. <bm...@ma...> - 2009-11-30 19:45:00
|
FWIW, below is my final version of code to fill in nested templates. It's down to a call to new() and a call to output() in each loop (besides the pattern match). Of course, there's a hidden param operation via the assoc object. Whether or not this benchmarks better, I don't know, but it comes across as simpler IMO. Of course, it introduces a bit of a dummy class for the associate option, but I don't mind that too much. Thanks all, Brad 1 #!/usr/local/bin/perl 2 3 use strict; 4 use warnings; 5 use HTML::Template; 6 7 my $assoc = My::Param->new( 8 { color => 'blue', blue => 'BLUE', BLUE => '**BLUE**' } 9 ); 10 11 my $text = <<__; 12 This is a <TMPL_VAR NAME="color"> bird. 13 This is a <TMPL_VAR NAME="<TMPL_VAR NAME="color">"> bird. 14 This is a <TMPL_VAR NAME="<TMPL_VAR NAME="<TMPL_VAR NAME="color">">"> bird. 15 __ 16 17 my $sref = \$text; 18 my $count; 19 20 while ( $text =~ /<TMPL_/i ) { 21 22 my $tmpl = HTML::Template->new( 23 scalarref => $sref, 24 strict => 0, 25 case_sensitive => 1, 26 associate => $assoc, 27 ); 28 29 $text = $tmpl->output(); 30 31 print "\n".++$count.":\n$text"; # debug 32 } 33 34 print "\nfinal: \n$text"; 35 36 package My::Param; 37 sub new { bless $_[1], $_[0] } 38 sub param { my $self = shift; 39 return keys %$self if wantarray; 40 return $self->{ $_[0] } } 41 42 __END__ 1: This is a blue bird. This is a <TMPL_VAR NAME="blue"> bird. This is a <TMPL_VAR NAME="<TMPL_VAR NAME="blue">"> bird. 2: This is a blue bird. This is a BLUE bird. This is a <TMPL_VAR NAME="BLUE"> bird. 3: This is a blue bird. This is a BLUE bird. This is a **BLUE** bird. final: This is a blue bird. This is a BLUE bird. This is a **BLUE** bird. |