3 # Copyright (C) 2010 Galen Charlton
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License along
17 # with Koha; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 show-template-structure.pl
29 This script displays the structure of loops and conditional statements
30 in an L<HTML::Template::Pro> template, and is an aid for debugging errors
31 reported by the xt/author/valid-templates.t test. It also identifies
36 =item * TMPL_IF/TMPL_UNLESS/TMPL_LOOP with no closing tag
38 =item * TMPL_ELSE with no initial TMPL_IF or TMPL_UNLESS
40 =item * extra closing tags
42 =item * HTML comment of the form <!-- TMPL_FOO ..., where TMPL_FOO is not a valid L<HTML::Template::Pro> tag
50 xt/author/show-template-structure.pl path/to/template.tt
54 Output is sent to STDOUT.
58 scalar(@ARGV) == 1 or die "Usage: $0 template-file\n";
60 open IN
, $file or die "Failed to open template file $file: $!\n";
62 my %valid_tmpl_tags = (
72 my %tmpl_structure_tags = (
73 tmpl_if
=> 1, # hash value controls whether to push/pop from the tag stack
86 # print message with indentation
87 my $level = scalar(@tag_stack);
88 print " " x
( $level - 1 ), shift;
94 # look for TMPL_IF, TMPL_ELSE, TMPL_UNLESS, and TMPL_LOOPs in HTML comments
95 # this makes the assumption that these control statements are never
96 # spread across multiple lines
97 foreach my $comment (/<!-- (.*?) -->/g) {
99 my $norm_comment = lc $comment;
100 $norm_comment =~ s/^\s+//;
101 next unless $norm_comment =~ m!^/{0,1}tmpl_!;
102 my ( $tmpl_tag_close, $tmpl_tag ) = $norm_comment =~ m!^(/{0,1})(tmpl_\S+)!;
103 $tmpl_tag_close = "" unless defined $tmpl_tag_close;
105 unless ( exists $valid_tmpl_tags{$tmpl_tag} ) {
106 print "ERROR (line $lineno): $tmpl_tag is not a valid HTML::Template::Pro tag\n";
108 next unless exists $tmpl_structure_tags{$tmpl_tag}; # only care about tags that affect loop or conditional structure
109 if ( $tmpl_structure_tags{$tmpl_tag} ) {
111 # we'll either be pushing or popping the tag stack
112 if ($tmpl_tag_close) {
115 emit
"${tmpl_tag_close}${tmpl_tag} (line $lineno)";
116 if ( scalar(@tag_stack) < 1 ) {
117 print "\nERROR (line $lineno): $tmpl_tag causes tag stack underflow\n";
119 my ( $popped_tag, $target, $popped_lineno ) = @
{ pop @tag_stack };
120 if ( $tmpl_tag ne $popped_tag ) {
121 print "\nERROR (line $lineno): got /$tmpl_tag but expected /$popped_tag to",
122 " match $popped_tag from line $popped_lineno\n";
124 print " # $target from $popped_lineno\n";
127 } elsif ( $tmpl_structure_tags{$tmpl_tag} ) {
130 my ($target) = $comment =~ /(?:EXPR|NAME)\s*=\s*['"](.*?)['"]/i;
131 push @tag_stack, [ $tmpl_tag, $target, $lineno ];
132 emit
"${tmpl_tag_close}${tmpl_tag} ($target, line $lineno)\n";
136 # we're either a tmpl_else or tmpl_elsif, so make sure that
137 # top of stack contains a tmpl_if
138 emit
"${tmpl_tag_close}${tmpl_tag} (line $lineno)\n";
139 if ( scalar @tag_stack < 1 ) {
140 print "ERROR: found $tmpl_tag, but tag stack is empty.\n";
142 my ( $peeked_tag, $target, $peeked_lineno ) = @
{ $tag_stack[0] };
143 if ( $peeked_tag ne "tmpl_if" and $peeked_tag ne "tmpl_unless" ) {
144 print "ERROR: found $tmpl_tag, but it does not appear to match a tmpl_if. Top of stack is $peeked_tag.\n";
153 # anything left in the stack?
154 if (scalar @tag_stack > 0) {
155 print "ERROR: tag stack is not empty - the following template structures have not been closed:\n";
157 while (my $entry = pop @tag_stack) {
159 my ( $popped_tag, $target, $popped_lineno ) = @
{ $entry };
160 print "$i: $popped_tag $target (line $popped_lineno)\n";
168 Koha Development Team <http://koha-community.org/>
170 Galen Charlton <gmcharlt@gmail.com>