views:

715

answers:

2

Is there a way to make Perl's Template display warnings for all undefined values that I attempt to use the GET directive on (via [% %]) during Template::process?

The default behavior is to ignore and move on. I'd like to warn only in the case of undefined values, if possible, and to log messages to STDERR.

+6  A: 

Yes. If you pass the DEBUG option to Template->new, TT will warn you about undefined values.

See the docs here: http://search.cpan.org/~abw/Template-Toolkit-2.20/lib/Template/Manual/Variables.pod

jrockway
Saw that, but was unsure whether it would spew a bunch of other stuff as well.
cdleary
Also, is there a way to make it go to a particular file handle?
cdleary
Dunno, sorry :) I use Template::Refine.
jrockway
+7  A: 

You are looking for:

DEBUG_UNDEF

This option causes the Template Toolkit to throw an 'undef' error whenever it encounters an undefined variable value.

use Template::Constants qw( :debug );

my $template = Template->new({
    DEBUG => DEBUG_UNDEF,
});

(From http://search.cpan.org/~abw/Template-Toolkit-2.20/lib/Template/Manual/Config.pod.)

If you want to do some special handling of the exception, you'll need to catch it or replace the __DIE__ signal handler.


Let's put it together:

#!/usr/bin/perl

use strict;
use warnings;

use Template;
use Template::Constants qw( :debug );

my $debug_tt = Template->new({
   DEBUG => DEBUG_UNDEF,
});

my $tt = Template->new();

my $vars = {
    something => "42",
};

my $template = <<EOF;
First something undefined: [% nothing %].
And now something defined: [% something %].
EOF

my $output = '';

eval {$debug_tt->process(\$template, $vars, \$output)};
warn $debug_tt->error() if $debug_tt->error();

$tt->process(\$template, $vars);

The output is:

undef error - nothing is undefined
First something undefined: .
And now something defined: 42.

My approach was to use two different instances of the Template class:

  1. $debug_tt which has the DEBUG_UNDEF flag turned on and hides its output in the $output variable.

  2. $tt which is a vanilla instance and prints its output to STDOUT as is the default.

Both instances use the same template stored in $template and the same variable hash stored in $vars. $debug_tt is wrapped in an eval to avoid exiting prematurely and a warning is emitted if $debug_tt->error() is true. $tt is executed normally. I think this satisfies your main requirements although it probably isn't efficient. We need to parse $template twice using this method.

Some thoughts I had working on this:

  1. It would have been nice if Template::Toolkit had used Carp so that we could get a bit more context on the warning.

  2. One could probably derive a class from Template that would warn instead of die on error. I didn't feel like doing that.

  3. Depending on how your templates are set up, it might make sense to feed it in one line at a time so that you could emit line numbers when an undefined value is found.

  4. It should be possible to alter the templates to test for their own errors and emit more sensible text in the face of undefined values.

Jon Ericson
Is there a way to have it *warn* on all undefined values but still render the template to completion?
cdleary
Crap, I missed the deadline... sorry Jon, but thanks for the help!
cdleary

related questions