Perrin Harkins wrote:

> Myk Melez wrote:
>
>> The approach I am taking is to add a method to Context.pm for sending 
>> processed content to the output stream and then call that method in 
>> compiled templates for each chunk of generated content rather than 
>> saving it all up and sending it at the end.  I'm also adding an 
>> "INCREMENTAL" configuration variable that enables this functionality 
>> (disabled by default).
>
>
> I think a better approach would be to add a keyword for flushing all 
> generated text so far.  You could start by implemening this as a plugin.

I couldn't figure out how to implement it as a plug-in, since plug-ins 
have no access (that I could find) to the generated content of a 
template, so I implemented it as an additional directive.  Attached to 
this message is my first shot at adding a FLUSH directive to TT that 
flushes generated content out to the output stream.

I did it by passing the output stream from the Template object to the 
Service object and from there to the Context object.  I then added a 
method "output" to the Context object that outputs data back to the 
output stream by calling a Template method "output", which in turn calls 
the Template internal method "_output".  I then added a FLUSH directive 
into Parser.yp that calls Context->output with the current value of 
$output and then resets that value to a blank string.

This implementation of FLUSH is "dumb" in that it doesn't handle nested 
block processing.  If you FLUSH within a block you flush the block's 
$output without flushing its containing block's $output, reordering the 
content, so you have to be careful about where you put the directive. 
 The general rule (per my limited experience testing this patch) is to 
flush before entering a block and at the beginning of loop blocks.

I haven't added documentation or tests yet because I expect that I've 
done it all wrong and will have to redo it.  Note that the patch does 
not include the actual changes to lib/Template/Grammar.pm, since those 
changes would have ballooned the patch up to a humongous size.  Instead, 
you must run ./yc in your parser/ directory after applying the patch in 
order to generate Grammar.pm.

Please take a look and let me know what you think and what needs to be 
done next.

> With most web apps, you do want to save the content until the end so 
> that you can be sure that nothing went wrong.  If you have a serious 
> error and you already sent half the page, you're in trouble.  However, 
> there are specific situations when sending just a part of the page 
> while you do a slow search or something is very useful, and in those 
> cases you generally know how you want to chunk up the page (e.g. send 
> the topbar then wait for the rest).  An explicit keyword should be 
> fine for this.

I agree, but in this case I am following the philosophy of doing all the 
heavy lifting in Perl code and using TT at the end to format the data, 
so I expect very few errors by the time the template gets processed. 
 And, of course, this is indeed case where a long-running search returns 
a complex and possibly large data set whose filtering and display in TT 
takes a non-negligible amount of time (thus making it useful to write 
partial result sets back to the browser).

-myk

diff -Naur Template-Toolkit-2.06d/lib/Template/Context.pm 
Template-Toolkit-2.06d-flush/lib/Template/Context.pm
--- Template-Toolkit-2.06d/lib/Template/Context.pm      Tue Jan 22 19:09:32 2002
+++ Template-Toolkit-2.06d-flush/lib/Template/Context.pm        Thu Feb 28 02:43:54 
+2002
@@ -258,7 +258,7 @@
 #------------------------------------------------------------------------
 
 sub process {
-    my ($self, $template, $params) = @_;
+    my ($self, $template, $outstream, $params) = @_;
     my ($trim, $blocks) = @$self{ qw( TRIM BLOCKS ) };
     my (@compiled, $name, $compiled);
     my ($stash, $tblocks, $error, $tmpout);
@@ -267,6 +267,9 @@
 #    my ($blocks, $output);
 #    my $name = $template;
 
+    $self->{ OUTSTREAM } = $outstream
+       if UNIVERSAL::isa($template, 'Template::Document');
+    
     $template = [ $template ] unless ref $template eq 'ARRAY';
 
     # fetch compiled template for each name specified
@@ -679,6 +682,18 @@
 }
 
 
+#------------------------------------------------------------------------
+# output()
+#
+# Outputs generated content to the output stream.
+#------------------------------------------------------------------------
+
+sub output {
+    my ($self, $output) = @_;
+    return Template::output($self->{ OUTSTREAM }, $output);
+}
+
+
 #------------------------------------------------------------------------
 # AUTOLOAD
 #
diff -Naur Template-Toolkit-2.06d/lib/Template/Directive.pm 
Template-Toolkit-2.06d-flush/lib/Template/Directive.pm
--- Template-Toolkit-2.06d/lib/Template/Directive.pm    Tue Nov 20 12:29:28 2001
+++ Template-Toolkit-2.06d-flush/lib/Template/Directive.pm      Thu Feb 28 02:25:07 
+2002
@@ -694,6 +694,16 @@
 }
 
 #------------------------------------------------------------------------
+# flush()                                                     [% FLUSH %]
+#
+# NOTE: this is redundant, being hard-coded (for now) into Parser.yp
+#------------------------------------------------------------------------
+
+sub flush {
+    return "\$context->output(\$output); \$output = '';";
+}
+
+#------------------------------------------------------------------------
 # break()                                                     [% BREAK %]
 #
 # NOTE: this is redundant, being hard-coded (for now) into Parser.yp
diff -Naur Template-Toolkit-2.06d/lib/Template/Service.pm 
Template-Toolkit-2.06d-flush/lib/Template/Service.pm
--- Template-Toolkit-2.06d/lib/Template/Service.pm      Tue Jan 22 19:09:32 2002
+++ Template-Toolkit-2.06d-flush/lib/Template/Service.pm        Thu Feb 28 02:46:04 
+2002
@@ -54,7 +54,7 @@
 #------------------------------------------------------------------------
 
 sub process {
-    my ($self, $template, $params) = @_;
+    my ($self, $template, $outstream, $params) = @_;
     my $context = $self->{ CONTEXT };
     my ($name, $output, $procout, $error);
     $output = '';
@@ -79,7 +79,7 @@
        # PRE_PROCESS
        eval {
            foreach $name (@{ $self->{ PRE_PROCESS } }) {
-               $output .= $context->process($name);
+               $output .= $context->process($name, $outstream);
            }
        };
        last SERVICE if ($error = $@);
@@ -87,7 +87,7 @@
        # PROCESS
        eval {
            foreach $name (@{ $self->{ PROCESS } || [ $template ] }) {
-               $procout .= $context->process($name);
+               $procout .= $context->process($name, $outstream);
            }
        };
        if ($error = $@) {
@@ -99,7 +99,7 @@
        # POST_PROCESS
        eval {
            foreach $name (@{ $self->{ POST_PROCESS } }) {
-               $output .= $context->process($name);
+               $output .= $context->process($name, $outstream);
            }
        };
        last SERVICE if ($error = $@);
diff -Naur Template-Toolkit-2.06d/lib/Template.pm 
Template-Toolkit-2.06d-flush/lib/Template.pm
--- Template-Toolkit-2.06d/lib/Template.pm      Tue Jan 22 19:09:32 2002
+++ Template-Toolkit-2.06d-flush/lib/Template.pm        Thu Feb 28 02:26:50 2002
@@ -47,29 +47,25 @@
 #------------------------------------------------------------------------
 # process($input, \%replace, $output)
 #
-# Main entry point for the Template Toolkit.  The Template module 
+# Main entry point for the Template Toolkit.  The Template module
 # delegates most of the processing effort to the underlying SERVICE
-# object, an instance of the Template::Service class.  
+# object, an instance of the Template::Service class.
 #------------------------------------------------------------------------
 
 sub process {
     my ($self, $template, $vars, $outstream) = @_;
     my ($output, $error);
 
-    $output = $self->{ SERVICE }->process($template, $vars);
-    
-    if (defined $output) {
-       $outstream ||= $self->{ OUTPUT };
-       unless (ref $outstream) {
-           my $outpath = $self->{ OUTPUT_PATH };
-           $outstream = "$outpath/$outstream" if $outpath;
-       }       
+    $outstream ||= $self->{ OUTPUT };
+    unless (ref $outstream) {
+       my $outpath = $self->{ OUTPUT_PATH };
+       $outstream = "$outpath/$outstream" if $outpath;
+    }
 
-       # send processed template to output stream, checking for error
-       return ($self->error($error))
-           if ($error = &_output($outstream, $output));
+    $output = $self->{ SERVICE }->process($template, $outstream, $vars);
 
-       return 1;
+    if (defined $output) {
+       return &output($outstream, $output);
     }
     else {
        return $self->error($self->{ SERVICE }->error);
@@ -77,6 +73,26 @@
 }
 
 
+#------------------------------------------------------------------------
+# output()
+#
+# Outputs generated content to the output stream.
+#------------------------------------------------------------------------
+
+sub output {
+    my ($outstream, $output) = @_;
+    my ($error);
+
+    if (defined $output) {
+       # send processed template to output stream, checking for error
+       return (Template::Base::error($error))
+           if ($error = &_output($outstream, $output));
+    }
+
+    return 1;
+}
+
+
 #------------------------------------------------------------------------
 # service()
 #
diff -Naur Template-Toolkit-2.06d/parser/Grammar.pm.skel 
Template-Toolkit-2.06d-flush/parser/Grammar.pm.skel
--- Template-Toolkit-2.06d/parser/Grammar.pm.skel       Thu Nov 29 17:44:36 2001
+++ Template-Toolkit-2.06d-flush/parser/Grammar.pm.skel Wed Feb 27 22:24:43 2002
@@ -52,7 +52,7 @@
        GET CALL SET DEFAULT INSERT INCLUDE PROCESS WRAPPER BLOCK END
        USE PLUGIN FILTER MACRO PERL RAWPERL TO STEP AND OR NOT DIV MOD
        IF UNLESS ELSE ELSIF FOR NEXT WHILE SWITCH CASE META
-       TRY THROW CATCH FINAL LAST RETURN STOP CLEAR VIEW
+       TRY THROW CATCH FINAL LAST RETURN STOP CLEAR VIEW FLUSH
     );
 
 # for historical reasons, != and == are converted to ne and eq to perform 
diff -Naur Template-Toolkit-2.06d/parser/Parser.yp 
Template-Toolkit-2.06d-flush/parser/Parser.yp
--- Template-Toolkit-2.06d/parser/Parser.yp     Thu Nov 29 17:44:36 2001
+++ Template-Toolkit-2.06d-flush/parser/Parser.yp       Wed Feb 27 22:26:17 2002
@@ -120,6 +120,7 @@
        |   RETURN                  { $factory->return()                  }
        |   STOP                    { $factory->stop()                    }
        |   CLEAR                   { "\$output = '';";                   }
+       |   FLUSH                   { "\$context->output(\$output); \$output = '';"; }
        |   LAST                    { $_[0]->{ INFOR } || $_[0]->{ INWHILE }
                                         ? 'last LOOP;'
                                         : 'last;'                         }

Reply via email to