in reply to Re: Output should have multiple segments
in thread Output should have multiple segments

I think a template model like Mason's could benefit from having multiple passes. That is, don't only have an output pass. First, just instantiate all the components that are being laid out or aggregated. Then do a compute pass on each one, where they all know about the complete page. Then do an output pass, which should gather and format results but not change anything.

  • Comment on Re^2: Output should have multiple segments

Replies are listed 'Best First'.
Re^3: Output should have multiple segments
by moritz (Cardinal) on Jul 16, 2008 at 07:46 UTC
    I think a template model like Mason's could benefit from having multiple passes.

    That's exactly where we differ. I think that a template system should only do the final pass - convert data structures to text.

    Try to think about it this way: if your application has two different views (for example a Template::Toolkit one that produces HTML, and a Mason one that produces XML), how much many of these passes would be duplicate in these two views?

    Let's say you have a web application that can produce both HTML pages and PDF files. In both cases you have a table of contents, and for each section you add to the output you also add a line to the table of contents.

    If you do the logic for adding that TOC line (which essentially requires either two passes or two output segments) in the template, you duplicate your effort in the two different template systems.

    OTOH if your perl code first assembles a data structure that represents the TOC, both of your templates just have to do their job: convert a data structure into text output. No more duplicate logic in there.

      Right. So instead of loading one subtemplate that receives the data structure I have to produce two datastructures (or often just remember which subtemplates will I want to use) and call two subtemplates. Lovely. Messy!

        If the structure of your desired output requires two data structures, you create them.

        For me that's not a good reason for moving program logic into the template.

        If you're not convinced, think of what happens when you chose to add more views. There are plenty of possible output formats, like html, xml, pdf, json, yaml, plain text, ... - would you really want to duplicate code for all of those templates?

Re^3: Output should have multiple segments
by ForgotPasswordAgain (Vicar) on Jul 16, 2008 at 07:15 UTC

    You should probably bring that up on the mason devel list. It would help (me at least, fwiw) also if you elaborated on the instantiate and compute phases.

    You might be able to do what you're talking about already with Mason's so-called object-oriented techniques. For example, for altering the attributes of the <body> tag you might use a method or attribute, which can be overridden by subcomponents.

Re^3: Output should have multiple segments
by AltBlue (Chaplain) on Jul 19, 2008 at 15:24 UTC

    That's how Mason works after all, but using a single output buffer. Ok, that's shallow, I hope the fellow masonites will forgive me for this one ;-)

    You should be able to quickly build yourself such a "multi-pass" system using your own conventions, following Mason's request cycle (briefly: gather output by running orderly each component in the inheritance chain)

    For the sake of example, here's a possible approach for such an autohandler:

    <%doc> # document everything (conventions, hacks etc) :P~ </%doc> <%once> # load modules at this step only if you're not able to load them "a +t startup" # (e.g. preloading them under a mod_perl enabled HTTPd) use My::App; </%once> <%init> # set up runtime/dynamic default configuration parameters $m->comp( '_conf', %ARGS ); # ^ these should all be "notes" ($m->notes) # a <%shared> replacement (yeah, that's me, # I always avoided it for not doing what I meant) ;-/ if ( $m->request_comp->method_exists('_init') ) { $m->request_comp->call_method('_init', %ARGS); } # fetch page content $m->notes( 'page_content' => $m->scomp( $m->fetch_next, %ARGS ) ); # ^ remember that you have to *handle* the "exceptions" # <%cleanup> replacement if ( $m->request_comp->method_exists('_cleanup') ) { $m->request_comp->call_method( '_cleanup', %ARGS ); } # render output return $m->comp( '_render', %ARGS ); </%init>
    Also notice that you can optimize this by moving out more app. logic into your My::App modules ;-)

    --
    altblue.