File Coverage

blib/lib/Template/Direct/Base.pm
Criterion Covered Total %
statement 113 122 92.6
branch 25 36 69.4
condition 6 8 75.0
subroutine 35 39 89.7
pod 32 32 100.0
total 211 237 89.0


line stmt bran cond sub pod time code
1             package Template::Direct::Base;
2              
3 2     2   18 use strict;
  2         4  
  2         75  
4 2     2   11 use warnings;
  2         4  
  2         71  
5              
6             =head1 NAME
7              
8             Template::Direct::Base - Basic class for content sections
9              
10             =head1 DESCRIPTION
11              
12             Provide the low level functions applicable to all content sections
13              
14             =head1 METHODS
15              
16             =cut
17              
18 2     2   1513 use Template::Direct::Conditional;
  2         6  
  2         159  
19 2     2   1366 use Template::Direct::List;
  2         6  
  2         79  
20 2     2   2001 use Template::Direct::SubPage;
  2         5  
  2         66  
21 2     2   1165 use Template::Direct::Maths;
  2         7  
  2         63  
22 2     2   14 use Carp;
  2         17  
  2         4650  
23              
24             =head2 I<$class>->new( $data )
25              
26             Create a new instance object.
27              
28             =cut
29             sub new {
30 59     59 1 166 my ($class, %p) = @_;
31 59         264 my $self = bless { 'subtagindex' => {}, %p }, $class;
32 59         183 return $self;
33             }
34              
35             =head2 I<$construct>->singleTag( )
36              
37             Return true if this construct will be a single tag.
38             i.e [tag/]
39              
40             =cut
41 50     50 1 132 sub singleTag { 0 }
42              
43             =head2 I<$construct>->subTags( )
44              
45             Should return a list of valid child tags.
46              
47             =cut
48 0     0 1 0 sub subTags { die "SubTags needs to be created in the parent class of: ".ref($_[0])."\n" }
49              
50             =head2 I<$construct>->hasTag( $name )
51              
52             Return true if this construct has a named tag.
53              
54             =cut
55             sub hasTag {
56 140     140 1 230 my ($self, $tagName) = @_;
57 140         341 return defined($self->subTags()->{$tagName})
58             }
59              
60             =head2 I<$construct>->hasSubTag( $name )
61              
62             Return true if this construct has a named sub tag.
63              
64             =cut
65             sub hasSubTag {
66 38     38 1 59 my ($self, $name) = @_;
67 38         166 return defined($self->{'subtagindex'}->{$name});
68             }
69              
70             =head2 I<$construct>->allSubTags( )
71              
72             Return an ARRAY ref of sub tag objects.
73              
74             =cut
75 550   100 550 1 2511 sub allSubTags { return $_[0]->{'subtags'} || [] }
76              
77             =head2 I<$construct>->addSubTag( $name, $index, $data )
78              
79             Used internally to add a sub tag element to this construct.
80              
81             =cut
82             sub addSubTag {
83 85     85 1 180 my ($self, $name, $index, $data) = @_;
84 85 100       268 $self->{'subtags'} = [] if not defined($self->{'subtags'});
85 85         131 push @{$self->{'subtags'}}, [ $name, $index, $data ];
  85         376  
86 85         315 $self->{'subtagindex'}->{$name} = $index;
87             }
88              
89             =head2 I<$construct>->addEndSubTag( $name, $index )
90              
91             Complete a sub tag by closing it, used internally.
92              
93             =cut
94             sub addEndSubTag {
95 56     56 1 100 my ($self, $name, $index) = @_;
96 56         73 push @{$self->{'subtags'}}, [ $name, $index, 'END' ];
  56         294  
97             }
98              
99             =head2 I<$construct>->endTag( )
100              
101             The tag id for the end tag of this construct.
102              
103             =cut
104 135     135 1 401 sub endTag { $_[0]->{'endTag'}; }
105              
106             =head2 I<$construct>->startTag( )
107              
108             The tag id for the start tag of this construct.
109              
110             =cut
111 135     135 1 434 sub startTag { $_[0]->{'startTag'} }
112              
113             =head2 I<$construct>->setEndTag( $index )
114              
115             Set the id of the end tag of this construct.
116              
117             =cut
118             sub setEndTag {
119 50     50 1 85 my ($self, $index) = @_;
120 50         173 $self->{'endTag'} = $index;
121             }
122              
123             =head2 I<$construct>->addChild( $object )
124              
125             Used internally to add a child construct to this one.
126              
127             =cut
128             sub addChild {
129 58     58 1 81 my ($self, $object) = @_;
130 58 100       164 $self->{'children'} = [] if not defined($self->{'children'});
131 58         68 push @{$self->{'children'}}, $object;
  58         199  
132             }
133              
134             =head2 I<$construct>->setParent( $object )
135              
136             Set the parent object of this construct to $object.
137              
138             =cut
139             sub setParent {
140 58     58 1 78 my ($self, $object) = @_;
141 58         90 $self->{'parent'} = $object;
142 58         159 $self->{'depth'} = $object->depth() + 1;
143             }
144              
145             =head2 I<$construct>->setClassParent( $object )
146              
147             Set the last parent which had the same class as this construct.
148              
149             =cut
150             sub setClassParent {
151 12     12 1 16 my ($self, $object) = @_;
152 12         22 $self->{'classParent'} = $object;
153 12         19 $self->{'classDepth'} = $object->depth() + 1;
154             }
155              
156             =head2 I<$construct>->children( )
157              
158             Return an ARRAY ref of child constructs.
159              
160             =cut
161 296 100   296 1 1753 sub children { shift->{'children'} || [] }
162              
163             =head2 I<$construct>->parent( )
164              
165             Return the parent construct (if available)
166              
167             =cut
168 0 0   0 1 0 sub parent { shift->{'parent'} || undef }
169              
170             =head2 I<$construct>->depth( )
171              
172             Return the depth number for this tag.
173              
174             =cut
175 30 50   30 1 148 sub depth { shift->{'depth'} || 0 }
176              
177             =head2 I<$construct>->classParent( )
178              
179             Return the next parent with the same class as this one.
180              
181             =cut
182 12 50   12 1 50 sub classParent { shift->{'classParent'} || undef }
183              
184             =head2 I<$construct>->classDepth( )
185              
186             Return the depth number for this tag counting only tags
187             of the same class as this one.
188              
189             =cut
190 0 0   0 1 0 sub classDepth { shift->{'classDepth'} || 0 }
191              
192             =head2 I<$construct>->getParent( $depth )
193              
194             Get a parent at a certain depth.
195              
196             =cut
197             sub getParent {
198 0     0 1 0 my ($self, $depth) = @_;
199 0 0       0 $depth = 0 if not $depth;
200 0 0       0 if($depth == 0) {
201 0         0 return $self;
202             }
203 0         0 return $self->parent($depth-1);
204             }
205              
206             =head2 I<$construct>->getClassParent( $depth )
207              
208             Get the class parent of a certin depth.
209              
210             =cut
211             sub getClassParent {
212 22     22 1 31 my ($self, $depth) = @_;
213 22 100       53 $depth = 0 if not $depth;
214 22 100       50 if($depth == 0) {
215 10         26 return $self;
216             }
217 12         43 return $self->classParent($depth-1);
218             }
219              
220             =head2 I<$construct>->compile( $data, $content, %p )
221              
222             Used internally to cascade the compilation to all children
223             and replace and variables with $data as required.
224              
225             =cut
226             sub compile {
227 240     240 1 610 my ($self, $data, $content, %p) = @_;
228 240         625 $self->compileChildren( $data, $content, %p );
229 240         713 $self->replaceData( $content, $data );
230             }
231              
232             =head2 I<$construct>->compileChildren( $data, $content, %p )
233              
234             Used internally, loop through all children and compile them
235             with the same data and content.
236              
237             =cut
238             sub compileChildren {
239 296     296 1 549 my ($self, $data, $content, %p) = @_;
240 296         313 foreach my $child (@{$self->children()}) {
  296         600  
241 143         504 $child->compile( $data, $content, %p );
242             }
243             }
244              
245             =head2 I<$object>->getOptions( $line )
246              
247             Returns a hash ref of name vale pairs and described as a string in line.
248              
249             The line: "var='xyz' depth=0" becomes { var => 'xyz', depth => '0' }
250              
251             =cut
252             sub getOptions {
253 50     50 1 80 my ($self, $opt) = @_;
254 50         73 my $results = {};
255              
256 50         208 while($opt =~ s/(\w+)=["']([^"']*)(?
257 36         207 $results->{$1} = $2;
258             }
259              
260 50         157 foreach my $o (split(/(?
261 2 50       7 if($o =~ /(\w+)=(.*)?/) {
262 0         0 $results->{$1} = $2;
263             } else {
264 2         7 $results->{$o} = 1;
265             }
266             }
267              
268 50         175 return $results;
269             }
270              
271             =head2 I<$object>->getSection( $content, $start, $end )
272              
273             Returns a section of a content between two tag indexes.
274             Having two sections with the same tag indexes is not valid
275             It's expected that code that deals with listing splits up
276             it's calls to this method as a matter of structure.
277              
278             =cut
279             sub getSection {
280 206     206 1 360 my ($self, $content, $start, $end) = @_;
281 206         254 my $result = '';
282 206 100       9612 if($$content =~ s/\{\{TAG$start\}\}([\w\W]*?)\{\{TAG$end\}\}/{{PH}}/) {
283 151         357 $result = $1;
284             }
285 206         956 return $result;
286             }
287              
288             =head2 I<$construct>->getLocation( $content, $tagIndex )
289              
290             Replaces a tag location with a temporty pointer.
291              
292             =cut
293             sub getLocation {
294 1     1 1 3 my ($self, $content, $tagindex) = @_;
295 1         17 $$content =~ s/\{\{TAG$tagindex\}\}/{{PH}}/;
296 1         4 return 1;
297             }
298              
299             =head2 I<$construct>->getFullSection( $content )
300              
301             Returns getSection of the current objects start and end tags
302              
303             =cut
304             sub getFullSection {
305 135     135 1 164 my ($self, $content) = @_;
306 135         273 return $self->getSection($content, $self->startTag(), $self->endTag());
307             }
308              
309             =head2 I<$construct>->setSection( $content, $result )
310              
311             Sets the section back into the content (see getSection)
312              
313             =cut
314             sub setSection {
315 192     192 1 297 my ($self, $content, $result) = @_;
316 192 100       344 if(defined $result) {
317 180         1015 $$content =~ s/\{\{PH\}\}/$result/;
318             } else {
319 12         103 $$content =~ s/\{\{PH\}\}//;
320             }
321             }
322              
323             =head2 I<$construct>->setTagSection( $content, $tagIndex, $with )
324              
325             Sets the section back into the content tag directly
326              
327             =cut
328             sub setTagSection {
329 29     29 1 53 my ($self, $content, $index, $result) = @_;
330 29         327 $$content =~ s/\{\{TAG$index\}\}/$result/;
331             }
332              
333             =head2 I<$construct>->getAppendedSection( $content, $startEntry, $endEntry )
334              
335             Returns the content between start and end tags, removing the start tag but
336             only removing the end tag if it's an end tag for the start tag.
337              
338             =cut
339             sub getAppendedSection {
340 75     75 1 114 my ($self, $content, $start, $end) = @_;
341              
342 75         92 my $result = '';
343 75         81 my $replaceWith = '';
344 75         119 my $startIndex = $start->[1];
345 75 100       155 my $endIndex = defined($end) ? $end->[1] : 'FAKEEND';
346              
347             # The start tag must be the same as the end tag and the
348             # end tag must BE an offical END tag.
349 75 100 66     452 if(defined($end) and ($start->[0] ne $end->[0] or $end->[2] ne 'END')) {
    100 66        
350             # The end tag isn't related so we just put it back.
351             # It's used as a marker for where the current start
352             # tag ends rather than a real end tag, although I'd
353             # like for people to use end tags properly and I
354             # figure html gurus will as a matter of habbit.
355 23         51 $replaceWith = '{{TAG'.$end->[1].'}}';
356             } elsif(not defined($end)) {
357             # Should also deal with tags that reach to the end of the scope.
358 1         3 $$content .= '{{TAGFAKEEND}}';
359             }
360              
361 75 100       2716 if($$content =~ s/\{\{TAG$startIndex\}\}([\w\W]*?)\{\{TAG$endIndex\}\}/$replaceWith/) {
362 57         131 $result = $1;
363             }
364              
365 75         542 return $result;
366             }
367              
368             =head2 I<$construct>->replaceData( \$content, $data )
369              
370             Replace all instances in content with required data
371              
372             =cut
373             sub replaceData
374             {
375 240     240 1 313 my ($self, $content, $data) = @_;
376             # The extra 1 in getDatum forces a scalar string (no undefs or structs)
377 240         836 $$content =~ s/(?getDatum($1, forceString => 1) /eg;
  183         542  
378 240         460 $$content =~ s/(?getDatum($1, forceString => 1) /eg;
  8         29  
379 240         690 return $content;
380             }
381              
382              
383             =head2 I<$construct>->cleanContent( \$content )
384              
385             Removes any remaining content syntax from content
386              
387             =cut
388             sub cleanContent {
389 2     2 1 6 my ($self, $content) = @_;
390             # We could remove spare structures here:
391             #$$content =~ s/(?
392             # Remove variables,remove stroked variables
393 2         6 $$content =~ s/(?
394 2         7 $$content =~ s/(?
395             # Unescape brackets and dollar signs
396 2         19 $$content =~ s/\\([\[\]\$])/$1/g;
397 2         6 return $content;
398             }
399              
400             =head1 AUTHOR
401              
402             Martin Owens - Copyright 2007, AGPL
403              
404             =cut
405             1;