Thread: [htmltmpl] Alternate loops
Brought to you by:
samtregar
From: Jonathan L. <dat...@gm...> - 2005-12-02 03:04:11
|
Requiring that all loops be handled by iterating through lists of hashes leads to a lot of extra work on the script writer's end, and results in the template writer having rather inflexible data to work with. I'd like to propose a more flexible alternative, which ought to be usable in addition to the current approach: Allow the script writer to pass ordinary lists to a template. Allow the template writer to access them using a modified version of <TMPL_LOOP>: <TMPL_LOOP> <!-- that's right; no loop control variable is given. --> <TMPL_VAR list1> <!-- list1 is an ordinary list that got passed to the template. --> <TMPL_VAR list2> <!-- list2 is another such list. --> </TMPL_LOOP> This loop construct would display the first elements of list1 and list2 on its first pass, the second elements of each list on its second pass, and so on until it exhausts one of the lists (at which point it stops). Without a loop control variable, any variable could be used within the loop, not just list-like variables. So you could do something like: <ul> <TMPL_LOOP> <li><TMPL_VAR value_set>: <TMPL_VAR count_distribution> out of <TMPL_VAR sum_of_counts></li> </TMPL_LOOP> </ul> Given: @value_set =3D (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); @count_distribution =3D (1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1); $sum_of_counts =3D 36; This would produce: <ul> <li>2: 1 out of 36</li> <li>3: 2 out of 36</li> <li>4: 3 out of 36</li> <li>5: 4 out of 36</li> <li>6: 5 out of 36</li> <li>7: 6 out of 36</li> <li>8: 5 out of 36</li> <li>9: 4 out of 36</li> <li>10: 3 out of 36</li> <li>11: 2 out of 36</li> <li>12: 1 out of 36</li> </ul> The only restriction would be that ordinary lists can only be used within a TMPL_LOOP. To me, this seems a lot more intuitive (on both ends of the design) than the current approach, where the script writer would have to say something like: @loop =3D ( {value_set =3D> 2, count_distribution =3D> 1, sum_of_counts =3D> 36 }, {value_set =3D> 3, count_distribution =3D> 2, sum_of_counts =3D> 36 }, {value_set =3D> 4, count_distribution =3D> 3, sum_of_counts =3D> 36 }, {value_set =3D> 5, count_distribution =3D> 4, sum_of_counts =3D> 36 }, {value_set =3D> 6, count_distribution =3D> 5, sum_of_counts =3D> 36 }, {value_set =3D> 7, count_distribution =3D> 6, sum_of_counts =3D> 36 }, {value_set =3D> 8, count_distribution =3D> 5, sum_of_counts =3D> 36 }, {value_set =3D> 9, count_distribution =3D> 4, sum_of_counts =3D> 36 }, {value_set =3D> 10, count_distribution =3D> 3, sum_of_counts =3D> 36 }, {value_set =3D> 11, count_distribution =3D> 2, sum_of_counts =3D> 36 }, {value_set =3D> 12, count_distribution =3D> 1, sum_of_counts =3D> 36 }, ) Bulky and painful. - You might even have it handle lists of lists, by nesting TMPL_LOOPs: <table> <TMPL_LOOP> <tr><TMPL_LOOP><td><TMPL_VAR count></td></TMPL_LOOP></tr> </TMPL_LOOP> </table> and @count =3D ([2, 3, 4, 5, 6, 7], [3, 4, 5, 6, 7, 8], [4, 5, 6, 7, 8, 9], [5, 6, 7, 8, 9, 10], [6, 7, 8, 9, 10, 11], [7, 8, 9, 10, 11, 12]); produces: <table> <tr><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td></tr> <tr><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td></tr> <tr><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr> <tr><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td><td>10</td></tr> <tr><td>6</td><td>7</td><td>8</td><td>9</td><td>10</td><td>11</td></tr> <tr><td>7</td><td>8</td><td>9</td><td>10</td><td>11</td><td>12</td></tr> </table> lists of lists of lists would also be possible, but the usefulness of lists of lists is already getting close to marginal. - I have an idea that would allow script writers to load hashes into a template as well; but IMHO that's not nearly as useful as loading ordinary list variables. -- Jonathan "Dataweaver" Lang |
From: Mathew R. <mat...@ne...> - 2005-12-02 08:17:30
|
Hi Jonathan, I think the exampe of: @loop =3D ( ... {value_set =3D> 2, count_distribution =3D> 1, sum_of_counts =3D> 36 },= ... ) is invalid, since you never generate the loop contruct like that. Usuall= y you would do something like: for ($min..$max) { # - loop through to max rows push @loop, { # \ value_set =3D> $_, # - make row values count_distribution =3D> make_value($_), # / }; } $ht->param(some_loop =3D> \@loop); # - make rows available $ht->param(sum_of_counts =3D> 36); # - make max count availabl= e The point being that usually you build up loop content dynamicaly, say fr= om a database or a computation, rather than simply outputting static cont= ent. Also, I'm not confident that H::T could be extended with the list-of-list= case (without some re-work), as H::T uses recursion for TMPL_LOOPS (eg: = when a loop begins, a new instance of H::T is created -> it becomes the c= urrent context). Note that most of my templates use lists-of-lists to pr= oduce tables, so I do consider this to be a must have. The idea of unnamed template loops is a interesting idea, but all it real= ly does is to increase the complexity of H::T, for no real increase in us= eability. That said, there may be a very slight increase in performance = when output'ing as you are no longer dealing with associative arrays. Mathew PS. In all of my templates, I know of exactly _zero_ cases where I could = use un-named loop variables. Jonathan Lang wrote: >Requiring that all loops be handled by iterating through lists of >hashes leads to a lot of extra work on the script writer's end, and >results in the template writer having rather inflexible data to work >with. I'd like to propose a more flexible alternative, which ought to >be usable in addition to the current approach: > >Allow the script writer to pass ordinary lists to a template. > >Allow the template writer to access them using a modified version of ><TMPL_LOOP>: > ><TMPL_LOOP> <!-- that's right; no loop control variable is given. --> > <TMPL_VAR list1> <!-- list1 is an ordinary list that got passed to >the template. --> > <TMPL_VAR list2> <!-- list2 is another such list. --> ></TMPL_LOOP> > >This loop construct would display the first elements of list1 and >list2 on its first pass, the second elements of each list on its >second pass, and so on until it exhausts one of the lists (at which >point it stops). > >Without a loop control variable, any variable could be used within the >loop, not just list-like variables. So you could do something like: > > <ul> > <TMPL_LOOP> > <li><TMPL_VAR value_set>: <TMPL_VAR count_distribution> out of ><TMPL_VAR sum_of_counts></li> > </TMPL_LOOP> > </ul> > >Given: > @value_set =3D (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); > @count_distribution =3D (1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1); > $sum_of_counts =3D 36; > >This would produce: > > <ul> > <li>2: 1 out of 36</li> > <li>3: 2 out of 36</li> > <li>4: 3 out of 36</li> > <li>5: 4 out of 36</li> > <li>6: 5 out of 36</li> > <li>7: 6 out of 36</li> > <li>8: 5 out of 36</li> > <li>9: 4 out of 36</li> > <li>10: 3 out of 36</li> > <li>11: 2 out of 36</li> > <li>12: 1 out of 36</li> > </ul> > >The only restriction would be that ordinary lists can only be used >within a TMPL_LOOP. > >To me, this seems a lot more intuitive (on both ends of the design) >than the current approach, where the script writer would have to say >something like: > >@loop =3D ( > {value_set =3D> 2, count_distribution =3D> 1, sum_of_counts =3D> 36 }, > {value_set =3D> 3, count_distribution =3D> 2, sum_of_counts =3D> 36 }, > {value_set =3D> 4, count_distribution =3D> 3, sum_of_counts =3D> 36 }, > {value_set =3D> 5, count_distribution =3D> 4, sum_of_counts =3D> 36 }, > {value_set =3D> 6, count_distribution =3D> 5, sum_of_counts =3D> 36 }, > {value_set =3D> 7, count_distribution =3D> 6, sum_of_counts =3D> 36 }, > {value_set =3D> 8, count_distribution =3D> 5, sum_of_counts =3D> 36 }, > {value_set =3D> 9, count_distribution =3D> 4, sum_of_counts =3D> 36 }, > {value_set =3D> 10, count_distribution =3D> 3, sum_of_counts =3D> 36 },= > {value_set =3D> 11, count_distribution =3D> 2, sum_of_counts =3D> 36 },= > {value_set =3D> 12, count_distribution =3D> 1, sum_of_counts =3D> 36 },= >) > >Bulky and painful. > >- > >You might even have it handle lists of lists, by nesting TMPL_LOOPs: > > <table> > <TMPL_LOOP> > <tr><TMPL_LOOP><td><TMPL_VAR count></td></TMPL_LOOP></tr> > </TMPL_LOOP> > </table> > >and > > @count =3D ([2, 3, 4, 5, 6, 7], > [3, 4, 5, 6, 7, 8], > [4, 5, 6, 7, 8, 9], > [5, 6, 7, 8, 9, 10], > [6, 7, 8, 9, 10, 11], > [7, 8, 9, 10, 11, 12]); > >produces: > > <table> > <tr><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td></tr> > <tr><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td></tr> > <tr><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td></tr> > <tr><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td><td>10</td></tr>= > <tr><td>6</td><td>7</td><td>8</td><td>9</td><td>10</td><td>11</td></tr= > > <tr><td>7</td><td>8</td><td>9</td><td>10</td><td>11</td><td>12</td></t= r> > </table> > >lists of lists of lists would also be possible, but the usefulness of >lists of lists is already getting close to marginal. > >- > >I have an idea that would allow script writers to load hashes into a >template as well; but IMHO that's not nearly as useful as loading >ordinary list variables. > >-- >Jonathan "Dataweaver" Lang > > >------------------------------------------------------- >This SF.net email is sponsored by: Splunk Inc. Do you grep through log f= iles >for problems? Stop! Download the new AJAX search engine that makes >searching your log files as easy as surfing the web. DOWNLOAD SPLUNK! >http://ads.osdn.com/?ad_idv37&alloc_id=16865&op=3Dclick >_______________________________________________ >Html-template-users mailing list >Htm...@li... >https://lists.sourceforge.net/lists/listinfo/html-template-users > =20 > |
From: Jonathan L. <dat...@gm...> - 2005-12-02 19:15:42
|
Mathew Robertson wrote: > Hi Jonathan, > > I think the exampe of: > > @loop =3D ( > ... > {value_set =3D> 2, count_distribution =3D> 1, sum_of_counts =3D> 36 }, > ... > ) > > is invalid, since you never generate the loop contruct like that. "invalid" may be too strong of a word; maybe you mean "unlikely"? For brevity's sake, I was describing the contents of a variable that's about to be loaded into the template; I was not intending to address the question of how it gets put together in the first place. That said: > Usually you would do something like: > > for ($min..$max) { # - loop through to max rows > push @loop, { # \ > value_set =3D> $_, # - make row values > count_distribution =3D> make_value($_), # / > }; > } > $ht->param(some_loop =3D> \@loop); # - make rows available > $ht->param(sum_of_counts =3D> 36); # - make max count availabl= e > > The point being that usually you build up loop content dynamicaly, say fr= om a database > or a computation, rather than simply outputting static content. True, but not a point that has much of an impact on my proposal. Take the example given in the documentation: my @words =3D qw(I Am Cool); my @numbers =3D qw(1 2 3); my @loop_data =3D (); while (@words and @numbers) { my %row_data; $row_data{WORD} =3D shift @words; $row_data{NUMBER} =3D shift @numbers; push (@loop_data, \%row_data); } $template->param(THIS_LOOP =3D> \@loop_data); -- <TMPL_LOOP NAME=3D"THIS_LOOP"> Word: <TMPL_VAR NAME=3D"WORD"> <br> Number: <TMPL_VAR NAME=3D"NUMBER"> <p> </TMPL_LOOP> Everything after the "my @numbers" line and before the "$template->param" line is an example of having to jump through hoops in order to get the information into a "table format" that H::T can use. Furthermore, the related template is under some severe limitations, in that information that has not been put into @loop_data cannot be displayed from inside a <TMPL_LOOP> tag. Looking at the same example, but implementing my proposal, you'd have this: my @words =3D qw(I Am Cool); my @numbers =3D qw(1 2 3); $template->param(WORDS =3D> \@words); $template->param(NUMBERS =3D> \@numbers); -- <TMPL_LOOP> Word: <TMPL_VAR NAME=3D"WORDS"> <br> Number: <TMPL_VAR NAME=3D"NUMBERS"> <p> </TMPL_LOOP> Much simpler, no? > Also, I'm not confident that H::T could be extended with the > list-of-list case (without some re-work), as H::T uses > recursion for TMPL_LOOPS (eg: when a loop begins, a new > instance of H::T is created -> it becomes the current context). > Note that most of my templates use lists-of-lists to produce > tables, so I do consider this to be a must have. See, that "current context" bit is something else that I'd like to get away from with unnamed template loops. Going back to what you have in the second quote above: if I use <TMPL_LOOP NAME=3D"some_loop">, I can only use <TMPL_VAR NAME=3D"value_set"> and <TMPL_VAR NAME=3D"count_distribution"> within it; I cannot use <TMPL_VAR NAME=3D"sum_of_counts"> in there, because "sum_of_counts" isn't in the current context. Unnamed template loops wouldn't change the current context, so I'd be able to make use of any or all of the appropriate arrays or scalars within it. > The idea of unnamed template loops is a interesting idea, but > all it really does is to increase the complexity of H::T, for > no real increase in useability. I'll have to beg to differ. As things stand, the script writer has to have a strong feel for how the data that he provides is going to be used, and needs to set up the lists of hashes accordingly. The template writer is then constrained to display each list-of-hashes in a separate loop, even if he thinks that the data makes more sense bundled together in a single loop. And that's not even mentioning the "current context" constraint. With unnamed template loops, the template writer is free to bundle as much or as little of the available data into a given loop as he feels is appropriate. If that's not a real increase in useability, what is? > PS. In all of my templates, I know of exactly _zero_ cases where I could = use un-named > loop variables. Correction: Every last case you know of _could_ use unnamed loops, since unnamed loops can do everything that regular loops can. Not one of your cases _does_, obviously, since unnamed loops aren't currently implemented; but that's not the same thing. And I can think of a number of cases where unnamed loops would streamline the script writer's job without complicating the template writer's job. -- Jonathan "Dataweaver" Lang |