[Templates-cvs] cvs commit: TT3/lib/Template/TT3 Tag.pm
cvs@template-toolkit.org
cvs@template-toolkit.org
Thu, 11 Dec 2003 15:11:01 +0000
cvs 03/12/11 15:11:01
Modified: lib/Template/TT3 Tag.pm
Log:
* improved scanning logic to handle open/closed tags and account for
line numbers automagically
Revision Changes Path
1.2 +120 -69 TT3/lib/Template/TT3/Tag.pm
Index: Tag.pm
===================================================================
RCS file: /template-toolkit/TT3/lib/Template/TT3/Tag.pm,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Tag.pm 2003/12/10 14:15:24 1.1
+++ Tag.pm 2003/12/11 15:11:01 1.2
@@ -17,7 +17,7 @@
# modify it under the same terms as Perl itself.
#
# REVISION
-# $Id: Tag.pm,v 1.1 2003/12/10 14:15:24 abw Exp $
+# $Id: Tag.pm,v 1.2 2003/12/11 15:11:01 abw Exp $
#
#========================================================================
@@ -29,13 +29,13 @@
use vars qw( $VERSION $DEBUG $ERROR $WARNING $TAG );
use base qw( Template::TT3::Base );
-$VERSION = sprintf("%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/);
+$VERSION = sprintf("%d.%02d", q$Revision: 1.2 $ =~ /(\d+)\.(\d+)/);
$DEBUG = 0 unless defined $DEBUG;
$ERROR = '';
$TAG = {
start => '[%',
end => '%]',
- name => 'tt3tag',
+ name => 'tag',
};
@@ -70,49 +70,6 @@
#------------------------------------------------------------------------
-# name()
-# name($name)
-#
-# Accessor method to get/set the optional tag name.
-#------------------------------------------------------------------------
-
-sub name {
- my $self = shift;
- return @_ ? ($self->{ name } = shift) : $self->{ name };
-}
-
-
-#------------------------------------------------------------------------
-# start()
-# start($token)
-#
-# Accessor method to get/set the start token.
-#------------------------------------------------------------------------
-
-sub start {
- my $self = shift;
- return @_ ? ($self->{ start } = shift) : $self->{ start };
-}
-
-
-#------------------------------------------------------------------------
-# end()
-# end($token)
-#
-# Accessor method to get/set the end token.
-#------------------------------------------------------------------------
-
-sub end {
- my $self = shift;
- if (@_) {
- $self->{ end } = shift;
- delete $self->{ end_regex };
- }
- return $self->{ end };
-}
-
-
-#------------------------------------------------------------------------
# scan($start_tag, $textref, $document)
#
# Called when a start tag is matched, this method scans up to any defined
@@ -121,12 +78,17 @@
sub scan {
my ($self, $start, $textref, $document) = @_;
- my ($end, $regex, $content);
+ my ($end, $regex, $content, $size, $result);
$self->{ start_match } = $start;
$self->debug("Tag<$self->{ name }> scan()\n") if $DEBUG;
+
+ if (defined ($end = $self->{ end }) && length($end)) {
+ # this is a closed tag that has pre-defined start and end tokens.
+ # we scan up to the end tag, figure out how many lines the directive
+ # covers and then call the parse() method to parse the contents
- if (defined ($end = $self->{ end })) {
+ # generate regex to match end tag
$regex = $self->{ end_regex } ||= do {
$end = ref $end eq 'Regexp' ? $end : quotemeta($end);
qr/ \G (.*?) ($end) /sx;
@@ -134,23 +96,52 @@
$self->debug("scanning for end with $end\n") if $DEBUG;
- if ($$textref =~ /$regex/gc) {
- my $content = $1;
- $self->{ end_match } = $2;
- $self->debug( 'matched content: "',
- $self->_inspect_text($content),
- "\"\n") if $DEBUG;
- return $self->parse(\$content, $document);
- }
- else {
- return $self->error("missing end tag: $self->{ end }");
- }
+ # scan for closing tag and report error if not found
+ return $self->error("no closing tag to match $start")
+ unless $$textref =~ /$regex/gc;
+ $content = $1;
+ $end = $self->{ end_match } = $2;
+
+ # count lines in start tag, content and end tag
+ $size = ($start =~ tr/\n//) + ($content =~ tr/\n//) + ($end =~ tr/\n//);
+ $document->size($size) if $size;
+
+ # call parse method to parse tag content
+ $result = $self->parse(\$content, $document);
+
+ # TODO: check for trailing cruft in content?
+
+ # update document position if required
+ $document->move() if $size;
}
else {
- return $self->parse($textref, $document);
+ # an open tag that has a start but no pre-defined end token.
+ # we save the current regex position, call the parse method to
+ # gobble up as much of the text as it likes, and then examine
+ # the regex position again, and count the newlines in the
+ # intervening text to update the document line position
+
+ # save starting regex position
+ my $start_pos = pos($$textref) || 0;
+
+ # no end match
+ $end = $self->{ end_match } = undef;
+
+ $self->debug("parsing open tag\n") if $DEBUG;
+
+ # parse item
+ $result = $self->parse($textref, $document);
+
+ # count any newlines consumed by parser between start and end positions
+ my $end_pos = pos $$textref || 0;
+ my $substr = substr($$textref, $start_pos, $end_pos - $start_pos);
+ $size = ($substr =~ tr/\n//);
+
+ # update document position if required
+ $document->move($size) if $size;
}
- die 'not reached';
+ return $result;
}
@@ -160,6 +151,8 @@
# Method to parse the tag content, usually redefined by subclasses to do
# something useful. Otherwise, the action() method is called to activate
# any other handler for the tag.
+#
+# TODO: perhaps the default should be to call $document->body()
#------------------------------------------------------------------------
sub parse {
@@ -182,6 +175,8 @@
$result = $action;
}
elsif (! ref $action) {
+ # TODO: not sure about this
+
# method name to call against document
$result = $document->$action($textref)
|| $self->error($document->error());
@@ -195,24 +190,80 @@
#------------------------------------------------------------------------
-# action()
-# action($action)
+# start() / start($token)
+# end() / end($token)
+# name() / name($name)
+# action() / action($name)
#
-# Accessor method to get/set the tag action handler.
+# Accessor methods to get/set the start tag, end tag and optional tag
+# name and action attributes.
#------------------------------------------------------------------------
+sub start {
+ my $self = shift;
+ return @_ ? ($self->{ start } = shift) : $self->{ start };
+}
+
+sub end {
+ my $self = shift;
+ if (@_) {
+ $self->{ end } = shift;
+ delete $self->{ end_regex };
+ }
+ return $self->{ end };
+}
+
+sub name {
+ my $self = shift;
+ return @_ ? ($self->{ name } = shift) : $self->{ name };
+}
+
sub action {
my $self = shift;
return @_ ? ($self->{ action } = shift) : $self->{ action };
}
+#------------------------------------------------------------------------
+# start_match()
+# end_match()
+#
+# Accessor methods to return the actual text matched for the start and
+# end tags respectively. If the start and end tags are strings then
+# these will contain the same values. If the start and end tags are
+# regexen, then the start_match and end_match may vary. These values
+# can only be guaranteed to be correct in the context of a call to the
+# scan() method.
+#------------------------------------------------------------------------
+
+sub start_match {
+ my $self = shift;
+ return @_ ? ($self->{ start_match } = shift) : $self->{ start_match };
+}
+
+sub end_match {
+ my $self = shift;
+ return @_ ? ($self->{ end_match } = shift) : $self->{ end_match };
+}
+
+
+#------------------------------------------------------------------------
+# is_open()
+# is_closed()
+#
+# Methods which return boolean flags to indicate if the tag has an
+# end defined, in which case it is closed, or not, in which case it is
+# open.
+#------------------------------------------------------------------------
+
+sub is_open {
+ my $self = shift;
+ return defined($self->{ end }) && length($self->{ end }) ? 0 : 1;
+}
-sub parse_error {
+sub is_closed {
my $self = shift;
- my $document = shift;
- $document->parse_error(@_);
- return $self->error($document->error());
+ return defined($self->{ end }) && length($self->{ end }) ? 1 : 0;
}
@@ -246,7 +297,7 @@
=head1 VERSION
-$Revision: 1.1 $
+$Revision: 1.2 $
=head1 COPYRIGHT