File Coverage

blib/lib/Templ/Tag.pm
Criterion Covered Total %
statement 18 78 23.0
branch 0 24 0.0
condition 0 12 0.0
subroutine 6 15 40.0
pod 0 9 0.0
total 24 138 17.3


line stmt bran cond sub pod time code
1             package Templ::Tag;
2              
3 1     1   3 use strict;
  1         1  
  1         25  
4 1     1   3 use warnings;
  1         1  
  1         20  
5              
6 1     1   3 use Carp qw(carp croak);
  1         1  
  1         35  
7 1     1   3 use Data::Dumper;
  1         1  
  1         288  
8              
9             # Keyed by start char, value of end char
10             my %char_pairs = (
11             '(' => ')',
12             '{' => '}',
13             '[' => ']',
14             '<' => '>',
15             );
16             my %invalid_chars = map { $_ => 1 } ( '+', '-', '=', '/' );
17              
18             sub add {
19 0     0 0   my $class = shift;
20 0 0 0       if ( not defined $class || ref $class || $class !~ m/^(\w+\:\:)*\w+$/ ) {
      0        
21 0           croak "Can only be called as ".__PACKAGE__."->new";
22             }
23 0 0         if ( $class eq 'Templ::Tag' ) {
24 0           croak "Can't instantiate a Templ::Tag object, please use a subclass";
25             }
26 0           my $char = shift;
27 0 0         if ( not defined $char ) {
28 0           croak "No character specification";
29             }
30 0 0         unless (length($char) == 1) {
31 0           croak "Tag object character specification can only be 1 character long";
32             }
33 0 0 0       if ($char !~ m/[[:print:]]/ || $char =~ m/[[:alnum:]]/i || $char !~ m/[[:ascii:]]/) {
      0        
34 0           croak "Tag object specification must be a printable non-alphanumeric ASCII character";
35             }
36 0 0         if ($invalid_chars{$char}) {
37 0           croak "Tag object character specification cannot be $char";
38             }
39 0           my $self = bless { 'char' => $char, 'params' => [ @_ ] }, $class;
40 1     1   4 no strict 'refs';
  1         1  
  1         24  
41 1     1   3 no warnings 'once';
  1         1  
  1         585  
42 0           push @{ caller().'::TEMPL_TAGS' }, $self;
  0            
43 0           return $self;
44             }
45              
46             *new = *add;
47              
48             sub char {
49 0     0 0   my $self = shift;
50 0           return $self->{'char'};
51             }
52              
53             sub end_char {
54 0     0 0   my $self = shift;
55 0 0         if (exists $char_pairs{$self->{'char'}}) {
56 0           return $char_pairs{$self->{'char'}}
57             }
58 0           return $self->{'char'};
59             }
60              
61             sub params {
62 0     0 0   my $self = shift;
63 0 0         if (not defined $self->{'params'}) { $self->{'params'} = [] }
  0            
64 0 0         return wantarray ? @{$self->{'params'}} : $self->{'params'};
  0            
65             }
66              
67             # Regex for matching the beginning of the tag, with optional
68             # whitespace removal greediness
69             #
70             #
71             #
72             #
73             #
74             sub pre_rx {
75 0     0 0   my $self = shift;
76 0 0         if ( not defined $self->{'_pre_rx'} ) {
77 0           my $char = qr/\Q${\$self->char}\E/;
  0            
78 0           $self->{'_pre_rx'} = qr/
79             (?: < $char \+ |
80             \s* < $char \- |
81             [ \t]* < $char \= |
82             (?:(?:(?<=\r\n)|(?<=\n))[\t ]*)? < $char
83             ) \s+
84             /x;
85             }
86 0           return $self->{'_pre_rx'};
87             }
88              
89             # Regex for matching the end of the tag, with optional
90             # whitespace removal greediness
91             #
92             # +?> Don't trim any trailing whitespace
93             # -?> Trim all trailing whitespace
94             # ?> Default, trim trailing whitespace including a newline, only if
95             # there's a newline
96             sub post_rx {
97 0     0 0   my $self = shift;
98 0 0         if ( not defined $self->{'_post_rx'} ) {
99 0           my $char = qr/\Q${\$self->end_char}\E/;
  0            
100 0           $self->{'_post_rx'} = qr/
101             \s+
102             (?:
103             \+ $char > |
104             \- $char > \s* |
105             $char > (?:[\t ]*\r?\n)?
106             )
107             /x;
108             }
109 0           return $self->{'_post_rx'};
110             }
111              
112             sub perl {
113 0     0 0   die "Cannot call ->perl() method of Templ::Tag (must be subclassed)";
114             }
115              
116             # For the given template input string, change any appearance of the tag
117             # into the appropriate substitution
118             sub process {
119 0     0 0   my $self = shift;
120 0           my $perl = shift; # Perl version of the template
121 0           my $parser = shift;
122              
123 0           my $pre_rx = $self->pre_rx;
124 0           my $post_rx = $self->post_rx;
125            
126 0           my $append = $parser->append;
127              
128 0           $perl =~ s{ ($pre_rx) (.*?) $post_rx }
129             {
130 0           my $pre = $1;
131 0           my $content = $2;
132 0           $content =~ s|\\\\|\\|gs;
133 0           $content =~ s|\\'|'|gs;
134 0           my $indent = '';
135 0 0         if ($pre =~ m/^([ \t]*).*\=/) { $indent = $1; }
  0            
136 0           "';\n".$self->perl($content,$indent,$append)."\n$append'"
137             }egsx;
138              
139 0           return $perl;
140             }
141              
142             sub dump {
143 0     0 0   my $self = shift;
144 0           return Data::Dumper->Dump( [$self], ['tag'] );
145             }
146              
147             1;