Juerd complained about unreadable templating code here Juerd then supplied a snippet that was nice, but non-nestable and non-assignable. Here is an attempt to maintain the niceness of the original snippet, and also make it reusable and assignable.
=for comment Here we retain Juerd's nice readable curly-brace syntax, and we also allow for reusable code (by assigning to global output string) allow for paramaterized tags (by using array ref with prm_table) allow for multiple-nested tags of any nesting-depth =cut ### INIT ### ---------------------------------------------- use strict; use warnings; ### INIT vars; global output string buffer; params for the parent +table; my $out; my $set_prm_table = [qw(red 1 100%)]; sub prm_table (&@){ my $st = $_[1] || ""; $out .= "<table bgcolor='$st->[0]' border='$st->[1]' width='$s +t->[2]'>"; $_[0]->(); $out .= "</table>"; } sub row (&) { $out .= "\n<tr>"; shift->(); $out .= "</tr>"; } sub cell (&) { $out .= "\n<td>"; shift->(); $out .= "</td>";} ### DISPLAY OUTPUT ### ---------------------------------------------- prm_table { for (1 .. 3){ row { cell {$out .= "foo $_"} } } }$set_prm_table; print $out; print "\n---------------------------\n";

Replies are listed 'Best First'.
Re: Readable HTML tables (revisited)
by matija (Priest) on Apr 24, 2004 at 18:06 UTC
    The idea is interesting, but the execution is lacking. I am uncomfortable with the caller having to remember to assign to $out in order to get a value into the cell. In fact, I don't really see what you gain by taking a sub reference instead of a string. (If taking the reference has an advantage, why not check the type of parameter, and handle both?)

    I am even more unhappy with the method you use to pass in the table parameters. It's an array, which you interpolate in the print. But if it's not passed, you assign it an empty string! If $st is an empty string, what is $st->[2] ?

    IMHO, you should use a hash instead of an array, and check all the values passed in - then only fill out those attributes of the table which have the attribute set.

    And to the same for the row and cell, of course - people often need to set their attributes.

      Hi matija, You mention some good points, here is some more details to clarify. Detail Orange is new stuff, the rest is just background...
      *detailOrange* RE: how about accepting *both* (aka either a sub ref or a string); This is a good idea. I expirimented with this prior to posting, yet the expirments revealed some caveats.
      CAVEAT1: You have to declare your prototype with the 'typeglob' syntax (aka star, asterisk)
      table(*){ my $vInput = shift; if(ref $vInput eq 'CODE') {$vInput->(); } ### fill in the rest... }
      CAVEAT2: You have to use the 'sub' keyword to indicate a code block. Some may feel this reduces readability and 'coolness factor' (entirely subjective). Failure to do so causes the curly brackets to be interpreted as a hashref.
      table sub { for (0 .. 3){ ### fill in the rest... } }

      *detailX* RE: script 'execution'; this snippet is really meant to be a brief 'sketch'. Everything you see in the ### INIT section is just one (of many) possible way to support the concise syntax proposed by Juerd. The ### DISPLAY OUTPUT section is the main emphasis (proof of concept), to show that Juerd need not totally sacrifice 'reusability' 'parameterization' and 'nesting', as he first might have thought. (see original thread).
      *detailFoo* RE: why to accept sub ref instead of a string; the main 'coolness factor' of Juerd's original idea was the fact that you could use concise curly-brace syntax to specify a table, and put things like 'for loops' inside of it. Q:Why would someone want to do that? A:Personal preference and readability (again, see original thread).
      *detailQ* indeed, if this were a 'real world' implementation, my personal preference would be to: 0) make the code its own standalone package; 1) dispense with the $out variable altogether, and instead make output buffering an OOP-style method of the package; 2) use name-value-pair oriented parameters (aka hash, hashref, objects) instead of numerically-indexed oriented parameters (aka array) *although sometimes array is good too*; 3) support attributes on all output elements; 4) avoid obvious type mismatches like the one you correctly indicated in the assignment to $st *which I dont like as a variable name btw, like i said, this was a sketch* 5) avoid unduly restricting the caller of the types of parameters it can pass (aka allow string as well as subroutine ref) *this is just a general design principle that I like to follow in most cases, (the law of mutual satisfaction)*