Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Re: RFC - Template::Empty

by Rhandom (Curate)
on Feb 25, 2008 at 16:32 UTC ( [id://670045]=note: print w/replies, xml ) Need Help??


in reply to RFC - Template::Empty

It seems that there is always a knee-jerk reaction to not having control flow in your HTML - and sometimes rightfully so. I very often see posters decrying systems such as Template::Toolkit because it has its own language - which it does - which may or may not be a problem. But that is a separate issue from that introduced by the Tal, Seamstress, and now the "Empty" concept.

The problem introduced by Tal, Seamstress, this new "Empty", and sometimes even HTML::Template with its "LOOP" construct - is that the Perl code has to know too much about the template.

Obviously the Perl code has to know which variables the template is going to need. However the Tal and Seamstress models go a little further - the Perl code for these has to know a little (sometimes a lot) about how the template is going to present the data. We've made sure the logic is out of the presentation layer - but now we've made the code layer manipulate the presentation layer. I think this is worse than having control flow in the template.

The nice thing about template systems with at least a minimal amount of language capability (such as Template::Toolkit) is that my Perl layer can generate data and pass it to the presentation layer. The presentation layer is then free to manipulate the data into a form suitable for presentation.

In the end, it really is developer preference. But for myself I've found that Template::Toolkit syntax and particularly Template::Alloy (which I authored) if used properly are the perfect separation between model and view. And it is the perfect separation from both directions.

my @a=qw(random brilliant braindead); print $a[rand(@a)];

Replies are listed 'Best First'.
Re^2: RFC - Template::Empty
by fergal (Chaplain) on Feb 25, 2008 at 18:15 UTC
    The problem introduced by Tal, Seamstress, this new "Empty", and sometimes even HTML::Template with its "LOOP" construct - is that the Perl code has to know too much about the template.

    In TAL, Perl builds the data and TAL renders it. Quite like TT but just with less generality built into the template language (generality that often just gets you into trouble). If you need to transform data for display (eg reorient a table, turning rows into columns and vice versa), the template can actually call out to perl helpers. This continues the separation of coding and presentation while giving almost as much flexibility as having a fully programmable template language.

    However the Tal and Seamstress models go a little further... now we've made the code layer manipulate the presentation layer.

    This is just simply not true at all, the perl layer cannot manipulate the presentation layer, TAL is nothing like Seamstress or Empty in this respect.

    The second comment makes me wonder if you actually know TAL at all. Perhaps you have been misled by the comments above into thinking that it is similar to Seamstress and Empty.

      This is just simply not true at all
      You are very right and I am very wrong. To a point.

      I was very wrong about the model of TAL which seems to be implemented more along the lines of TT or HTML::Template - just with an XML based mini language.

      However, the process of calling back in to the perl layer in order to reorganize your data frames TAL in the light that I was mentioning before and is why I also indicated that HTML::Template also falls into that level. If you want the data in a different form - you HAVE to call into perl on TAL and HTML::Template. Seamstress doesn't give you the option - so you have to manipulate your data before hand.

      In TT and Template::Alloy - you can call into perl to manipulate your data - but the language has enough flexibility that you don't have to.

      my @a=qw(random brilliant braindead); print $a[rand(@a)];
        Paul, I'm enjoying this discussion. i think it is useful for both of us as well as the perl community at large... so dont think I'm making any personal attacks. The more we compare and contrast, the stronger our respective camps can become.
        In TT and Template::Alloy - you can call into perl to manipulate your data - but the language has enough flexibility that you don't have to.
        In terms of separation of concerns where do you think data manipulation should be done:
        1. model
        2. view
        3. controller

        In Seamstress, the answer is clear and my code backs it up. Data manipulation, in any way shape or form belongs in the MODEL

        your comments about sticking template code in the database almost gave me a heart attack.. What you call "flexibility" I call "confusion of concerns

        Taking a presentation tool and involving it in data manipulation... it is bound to fall short. At one point, TT was released and didnt even have numeric comparison... essential for data manipulation.

        I have beheld the tarball of 22.1 on ftp.gnu.org with my own eyes. How can you say that there is no God in the Church of Emacs? -- David Kastrup
        [tag://software-engineering,html,templating]
        Enforce strict model-view separation in template engines via HTML::Seamstress The car is in the cdr, not the cdr in the car
        In TT and Template::Alloy - you can call into perl to manipulate your data - but the language has enough flexibility that you don't have to.

        Really it's a matter of whether you want this flexibility. I find that I don't want it and I also claim that having it just tempts you into doing things in your templates that you should really be doing in your code. Those with a stronger will may differ :)

object-oriented composition of model-view with HTML::Seamstress
by metaperl (Curate) on Feb 25, 2008 at 17:22 UTC
    it was rhandomly stated:
    but now we've made the code layer manipulate the presentation layer. I think this is worse than having control flow in the template. I've found that Template::Toolkit syntax and particularly Template::Alloy (which I authored) if used properly are the perfect separation between model and view. And it is the perfect separation from both directions.
    If you would like to come up with an empirical measure of "perfect" or give examples which show how Alloy is better than Seamstress, I will be more than happy to provide fully working Seamstress counterparts.

    You chief expressed concern is:

    but now we've made the code layer manipulate the presentation layer.
    I dont know what a "code layer" is... please tell me what a code layer is, preferably with an example showing how horrible it makes the seamstress experience.

    for me, dynamic html consists of:

    accessing the model and storing it in an iterator or in-memory data structure

    my $records = Data::Object->load(welcome_data => $cookie->user) ;

    accessing the view and storing in a seamstress object (a subclass of HTML::Tree)

    my $tree = html::welcome->new;

    executing presentation logic

    $tree->replace_content(user_name => $records->[0]{user_name});
    That is clear, clean and simple and allows maximum independence of HTML developer and Perl programmer... I have zero need to touch the HTML. and complete ability to swap model loading and presentation logic using any of a number of object oriented techniques...
    I have beheld the tarball of 22.1 on ftp.gnu.org with my own eyes. How can you say that there is no God in the Church of Emacs? -- David Kastrup
    [tag://oop,html,templating]
    Enforce strict model-view separation in template engines via HTML::Seamstress The car is in the cdr, not the cdr in the car
      Thanks for the softball.

      Here is your job. I will give you an array of text strings. Without manipulating the data in the perl layer, please provide one template that shows them in a bullet list and another template that shows them in a table with three columns with data oriented in columns with one item per cell. On the column oriented version fill in   wherever there isn't a defined value. Be sure external whitespace is nice and consistent.

      For extra credit - make the template decide conditionally that if you have less than n items use the bullet list - otherwise use the table.

      For extra extra credit - do this exercise - but do it in a text-only based email that will be sent to a user (ie - no html tags).

      ----- bullet.tt --------- <ul> [%- FOREACH i IN items %] <li>[% i %]</li> [%- END %] </ul> ----- columns.tt -------- [%- cols = 3; rows = items.size div cols; rows = rows+1 IF items.size % cols %] [%- FOR i IN [0 .. rows - 1] %] <tr> [%- FOR j IN [0 .. cols -1] %] <td>[% items.${ i + rows * j } %]</td> [%- END %] </tr> [%- END %] </table> ------ optional.tt [% PROCESS ${ items.size > 10 ? "columns.tt" : "bullet.tt" } %] ------ my_perl.pl ------ use Template::Alloy; my $t = Template::Alloy->new; my $data = { items => [1 .. 10], }; $t->process("bullet.tt", $data) || die $t->error; $t->process("columns.tt", $data) || die $t->error; __END__ prints <ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> <li>6</li> <li>7</li> <li>8</li> <li>9</li> <li>10</li> </ul> <table> <tr> <td>1</td> <td>5</td> <td>9</td> </tr> <tr> <td>2</td> <td>6</td> <td>10</td> </tr> <tr> <td>3</td> <td>7</td> <td>&nbsp;</td> </tr> <tr> <td>4</td> <td>8</td> <td>&nbsp;</td> </tr> </table>


      Update To me the code layer would be your perl modules and your cgi script (or your mod_perl application). The example given is simplified and contrived - but represents real life situations.
      Update 2 s/specifying/manipulating the data/

      my @a=qw(random brilliant braindead); print $a[rand(@a)];
        Thanks for the softball.
        and thank you for taking a swing :)
        Without manipulating the data in the perl layer, please provide one template that shows them in a bullet list and another template that shows them in a table with three columns with data oriented in columns with one item per cell.
        I read your definition of Perl layer below. The first comment is that Perl layer is not a fine-grained term. It is a monolithic concept which does not accurately point out the (supposed) source of problems with push-style dynamic html generation. The second comment is that Perl is the practical extraction and report language. It excels at manipulating data. I therefore refuse to use a template system for manipulating data. Model actions belong in model, not anywhere else. And the model is best done in pure perl.

        Your sample tt code mixes concerns. Data processing should be testable completely offline.. and completely free of any view. Mine is. Yours isn't.

        On the column oriented version fill in   wherever there isn't a defined value.
        uh... no. I will fill in space in my model code function reformat_data. Then delegate the conversion of space to &nbsp; to the HTML renderer....
        Be sure external whitespace is nice and consistent.
        What is external whitespace?
        For extra credit - make the template decide conditionally that if you have less than n items use the bullet list - otherwise use the table.
        That's really just basic Perl:
        my $model = Model->new; @$model < $n ? render_bullets($model) : render_table($model);
        For extra extra credit - do this exercise - but do it in a text-only based email that will be sent to a user (ie - no html tags).
        Well you didnt do it. I'm not sure how I would do that. Maybe an html2text tool?
        To me the code layer would be your perl modules and your cgi script (or your mod_perl application). The example given is simplified and contrived - but represents real life situations.
        It's a good example. But once you see my code, please point out the perrin-rhandom syndrome in the push-style approach or recant the criticism.
        Update 2 s/specifying/manipulating the data/
        Again a request I cannot comply with. I will never forget the time that Ovid tried to justify things like this, by calling it "presentation logic" and saying that a "presentation tool" like tt would be good for it. I disagreed with him then and with you now. No one should request data processing anywhere but a data processing giant (Perl).

        Now, it has taken me probably 1 hour to write that code. I'm sure it took you less than 5 minutes. I'm a bit rusty in Perl, since I mainly convert Perl ETL scripts to Ab Initio data flow graphs these days. But I would not have been much faster. Push-style development is much slower. And I am grateful to have had a chance to shake the rust off myself :)

        Code post follows.

        I have beheld the tarball of 22.1 on ftp.gnu.org with my own eyes. How can you say that there is no God in the Church of Emacs? -- David Kastrup
        [tag://long,live,html,seamstress,and,template,alloy,too]
        Enforce strict model-view separation in template engines via HTML::Seamstress The car is in the cdr, not the cdr in the car
        Here is your job.
        And here is the code obtainable via hg clone http://hg.metaperl.com/seamstress

        Driver script

        use strict; use warnings; use Model; use View::bullet; use View::table; my $model = Model->new; # View 1 my $view = View::bullet->new; $view->render($model); warn $view->as_HTML; # View 2 my $cols = 3; my $tabular_model = $model->reform_data($cols); my $view = View::table->new; $view->render($tabular_model); warn $view->as_HTML;

        Model package

        package Model; use Array::Group; use Data::Dumper; # A model is overkill for this example, but lets plan for # scaleability sub new { my $data = [1 .. 10] ; bless $data, __PACKAGE__ ; return $data; } sub reform_data { my $aref = shift; my $cols = shift; my $tabdata = Array::Group::ngroup $cols => $aref ; # This filling of the last row should be an option to # Array::Group... my $last_row = $tabdata->[$#$tabdata] ; my $diff = $cols - @$last_row; my @nbsp = (' ') x $diff; push @$last_row, @nbsp; return $tabdata; } 1 ;

        View code

        bullet

        package View::bullet; use base qw(HTML::Seamstress); my $file = 'html/bullet.html'; sub new { __PACKAGE__->new_from_file($file); } sub render { my $tree = shift; my $model = shift; my $li = $tree->look_down(class => 'nums'); $tree->iter($li => @$model) ; return $tree; } 1;

        table

        package View::table; use base qw(HTML::Seamstress); my $file = 'html/table.html'; sub new { __PACKAGE__->new_from_file($file); } sub render { my $tree = shift; my $data = shift; $tree->table2 ( table_data => $data, td_proc => sub { my ($tr, $data) = @_; my @td = $tr->look_down('_tag' => 'td'); for my $i (0..$#td) { $td[$i]->splice_content(0, 1, $data->[$i]); } } ) ; return $tree; } 1;
        I have beheld the tarball of 22.1 on ftp.gnu.org with my own eyes. How can you say that there is no God in the Church of Emacs? -- David Kastrup
        [tag://html,templating]
        Enforce strict model-view separation in template engines via HTML::Seamstress The car is in the cdr, not the cdr in the car

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://670045]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others exploiting the Monastery: (1)
As of 2024-04-25 00:16 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found