[Templates-cvs] cvs commit: TT3/lib/Template Tag.pm
cvs@template-toolkit.org
cvs@template-toolkit.org
Tue, 09 Nov 2004 13:24:01 +0000
cvs 04/11/09 13:24:01
Modified: lib/Template Tag.pm
Log:
* made what was previously known as an "open" tag the default, but changed
it to scan ahead for an end tag if defined.
Revision Changes Path
1.2 +66 -96 TT3/lib/Template/Tag.pm
Index: Tag.pm
===================================================================
RCS file: /template-toolkit/TT3/lib/Template/Tag.pm,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Tag.pm 2004/11/08 18:46:59 1.1
+++ Tag.pm 2004/11/09 13:24:01 1.2
@@ -16,7 +16,7 @@
# modify it under the same terms as Perl itself.
#
# REVISION
-# $Id: Tag.pm,v 1.1 2004/11/08 18:46:59 abw Exp $
+# $Id: Tag.pm,v 1.2 2004/11/09 13:24:01 abw Exp $
#
#========================================================================
@@ -24,19 +24,20 @@
use strict;
use warnings;
+use Template::Parser;
use Template::Base;
-use vars qw( $VERSION $DEBUG $ERROR $TAG );
use base qw( Template::Base );
-$VERSION = sprintf("%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/);
-$DEBUG = 0 unless defined $DEBUG;
-$ERROR = '';
-$TAG = {
- start => '[%',
- end => '%]',
+our $VERSION = sprintf("%d.%02d", q$Revision: 1.2 $ =~ /(\d+)\.(\d+)/);
+our $DEBUG = 0 unless defined $DEBUG;
+our $ERROR = '';
+our $TAG = {
+ start => '[%',
+ end => '%]',
};
+
#------------------------------------------------------------------------
# init(\%config)
#
@@ -67,104 +68,75 @@
#------------------------------------------------------------------------
# scan($textref, $handler, $match)
#
-# Default scan method which looks to see if an end token is defined or
-# not, and then calls scan_open() or scan_closed() as appropriate.
+# Method to scan the contents of a tag.
#------------------------------------------------------------------------
sub scan {
- my $self = shift;
- my $end;
-
- $self->debug("scan()\n") if $DEBUG;
-
- if (defined ($end = $self->{ end }) && length($end)) {
- return $self->scan_closed(@_);
- }
- else {
- return $self->scan_open(@_);
- }
-}
-
-
-#------------------------------------------------------------------------
-# scan_open($textref, $handler, $match)
-#
-# Method to scan the text of an open tag that has a start token but no
-# pre-defined end token.
-#------------------------------------------------------------------------
-
-sub scan_open {
my ($self, $textref, $handler, $match) = @_;
+ my $ignore = $self->{ ignore } || '';
+ my $error;
- $self->debug("scan_open()\n") if $DEBUG;
+ $self->debug("scan()\n") if $DEBUG;
# save match info locally to make protect re-entrancy
local $self->{ match } = $match;
+ $match->{ lines } = 0;
+
+ # ignore any leading whitespace or whatever else 'ignore' is set to match
+ $$textref =~ / \G $ignore /cogsx if $ignore;
- # call parse() method to parse forwards, scanning whatever it wants.
- # errors can be thrown as exceptions (hence the eval) or set via
- # $self->error(), returning an undef value for $handler
eval {
+ # call parse() method to parse forwards through the text until it is
+ # satisfied. errors can be thrown as exceptions (hence the eval) or
+ # set via $self->error(), returning an undef value for $handler.
$handler = $self->parse($textref, $handler, $match);
};
+ $error = $@;
+
+ # an error may have occurred, but before reporting it back to our caller
+ # we should first update the $match with details of the current regex match
+ # position so that the error generated shows the correct position in the
+ # source template. if we don't get an error then we can go ahead and look
+ # for the end token
+
+ if ($handler && ! $error) {
+ my $endtag = $self->{ end };
+
+ if (defined $endtag and length $endtag) {
+ # compile regex to match end token, ignoring whitespace but checking
+ # out for any other text that shouldn't be there
+ my $regex = $self->{ end_regex } ||= do {
+ $endtag = ref $endtag eq 'Regexp' ? $endtag : quotemeta($endtag);
+ qr/ \G $ignore (.*?) $ignore ($endtag) /sox;
+ };
+ $self->debug("scanning for end of open tag: $regex\n") if $DEBUG;
+
+ # scan for end token, noting error if not found
+ if ($$textref =~ /$regex/gc) {
+ if (defined($1) && length($1)) {
+ # any text coming before end token shouldn't be there
+ $error = "unexpected text in tag: $1";
+ }
+
+ # save end token in $match data
+ $match->{ end } = $2;
+ }
+ else {
+ $error = "no closing tag to match $match->{ start }";
+ }
+ }
+ }
+
# count any newlines consumed by parser between start and end positions
my $start_pos = $match->{ offset };
my $end_pos = pos $$textref || 0;
my $substr = substr($$textref, $start_pos, $end_pos - $start_pos);
- $match->{ lines } = ($substr =~ tr/\n//);
-
- return $@ ? $self->error($@) : $handler;
-}
-
-
-#------------------------------------------------------------------------
-# scan_closed($textref, $handler, $match)
-#
-# Method to scan the text of an open tag that has both start and end
-# tokens defined.
-#------------------------------------------------------------------------
-
-sub scan_closed {
- my ($self, $textref, $handler, $match) = @_;
-
- $self->debug("scan_closed()\n") if $DEBUG;
-
- # save match info locally to make protect re-entrancy
- local $self->{ match } = $match;
-
- my $endtag = $self->{ end };
- return $self->tag_error('no end token defined for tag')
- unless defined $endtag and length $endtag;
-
- # compile regex to match end tag
- my $regex = $self->{ end_regex } ||= do {
- $endtag = ref $endtag eq 'Regexp' ? $endtag : quotemeta($endtag);
- qr/ \G (.*?) ($endtag) /sx;
- };
-
- $self->debug("scanning for end with $regex\n") if $DEBUG;
-
- # scan for closing tag and report error if not found
- return $self->error("no closing tag to match $match->{ start }")
- unless $$textref =~ /$regex/gc;
-
- # TODO: change 'size' to 'length', 'lines', etc.
-
- my ($body, $end) = ($1, $2);
- $match->{ text } = \$body;
- $match->{ end } = $end;
- $match->{ lines } =
- ( $match->{ start } =~ tr/\n// )
- + ( $body =~ tr/\n// )
- + ( $end =~ tr/\n// );
-
- # call parse() method, catching errors thrown or reported via error()
- eval {
- $handler = $self->parse(\$body, $handler, $match);
- };
+ $match->{ lines } += ($substr =~ tr/\n//);
- return $@ ? $self->error($@) : $handler;
+ # NOTE: $handler may be undef, but we assume that an error has already
+ # been set by a call to $self->error($msg) (e.g. in the parse() method)
+ return $error ? $self->error($error) : $handler;
}
@@ -847,13 +819,11 @@
=head1 VERSION
-$Revision: 1.1 $
+$Revision: 1.2 $
=head1 COPYRIGHT
- Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved.
- Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
- Copyright (C) 2003-2004 Fotango Ltd.
+Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved.
This module is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
@@ -861,10 +831,10 @@
=head1 SEE ALSO
For examples of tag subclasses that perform more specific processing,
-see L<Template::TT3::Tag::Comment>, L<Template::TT3::Tag::Escape>,
-L<Template::TT3::Tag::Variable>, and L<Template::TT3::Tag::Directive>.
-For more information about the scanner and document classes, see
-L<Template::TT3::Scanner> and L<Template::TT3::Document> respectively.
+see L<Template::Tag::Comment>, L<Template::Tag::Escape>,
+L<Template::Tag::Variable>, and L<Template::Tag::Directive>.
+For more information about the scanner and handler classes, see
+L<Template::Scanner> and L<Template::Handler> respectively.
=cut