File Coverage

blib/lib/Template/Direct/Data.pm
Criterion Covered Total %
statement 87 132 65.9
branch 40 70 57.1
condition 5 8 62.5
subroutine 11 18 61.1
pod 9 9 100.0
total 152 237 64.1


line stmt bran cond sub pod time code
1             package Template::Direct::Data;
2              
3 2     2   195 use strict;
  2         6  
  2         988  
4 2     2   13 use warnings;
  2         3  
  2         423  
5              
6             =head1 NAME
7              
8             Template::Direct::Data - Creates a dataset handeler
9              
10             =head1 SYNOPSIS
11              
12             use Template::Direct::Data;
13              
14             my $data = Template::Direct::Data->new( [ Data ] );
15              
16             $datum = $data->getDatum( 'datum_name' );
17             $data = $data->getData( 'datum_name' );
18              
19             If you want to add more data you can push another namespace level
20             This will force the data checking to check this data first then
21             the one before until it reaches the last one.
22              
23             $data->pushData( [ More Data ] )
24             $data->pushDatum( 'datum_name' )
25             $data = $data->popData()
26              
27             =head1 DESCRIPTION
28              
29             Control a set of data namespaces which are defined by the top level
30             set of names in a hash ref.
31              
32             All Data should be in the form { name => value } where value can be
33             any hash ref, scalar, or array ref (should work with overridden objects too)
34              
35             Based on L (version 2.0) which this replaces
36              
37             =head1 METHODS
38              
39             =cut
40              
41 2     2   10 use Carp;
  2         6  
  2         4083  
42              
43             =head2 I->new( $data )
44              
45             Create a new Data instance.
46              
47             =cut
48             sub new {
49 160     160 1 221 my ($class, $data) = @_;
50 160         626 my $self = bless { sets => [ ] }, $class;
51 160 50       497 $self->pushData($data) if $data;
52 160         434 return $self;
53             }
54              
55              
56             =head2 I<$data>->pushData( $data )
57              
58             Add a new data to this data set stack
59              
60             =cut
61             sub pushData {
62 465     465 1 696 my ($self, $data) = @_;
63 465 50       931 if(defined($data)) {
64 465 100       1019 if(UNIVERSAL::isa($data, 'ARRAY')) {
65 1         1 push @{$self->{'sets'}}, @{$data};
  1         5  
  1         14  
66             } else {
67 464         546 push @{$self->{'sets'}}, $data;
  464         970  
68             }
69 465         894 return 1;
70             }
71 0         0 return undef;
72             }
73              
74              
75             =head2 I<$data>->pushNew( $data )
76              
77             Returns a new Data object with $object data plus
78             The new data.
79              
80             =cut
81             sub pushNew {
82 159     159 1 219 my ($self, $adddata) = @_;
83 159         203 my $newobject = undef;
84 159         185 foreach my $data (@{$self->{'sets'}}) {
  159         354  
85 305 100       524 if(not $newobject) {
86 159         367 $newobject = Template::Direct::Data->new( $data );
87             } else {
88 146         255 $newobject->pushData( $data );
89             }
90             }
91 159         353 $newobject->pushData( $adddata );
92 159         384 return $newobject;
93             }
94              
95              
96             =head2 I<$data>->pushDatum( $name )
97              
98             Find an existing data structure within myself
99             And add it as a new namespace; thus bringing it
100             into scope.
101              
102             Returns 1 if found and 0 if failed to find substruct
103              
104             =cut
105             sub pushDatum {
106 0     0 1 0 my ($self, $name) = @_;
107 0         0 my $data = $self->getDatum( $name );
108 0         0 return $self->push( $data );
109             }
110              
111              
112             =head2 I<$data>->pushNewDatum( $name )
113              
114             Find an existing data structure within myself and create
115             A new object to contain my own data and this new sub scope.
116              
117             ( believe it or not this is useful)
118              
119             =cut
120             sub pushNewDatum {
121 0     0 1 0 my ($self, $name) = @_;
122 0         0 my $data = $self->getDatum( $name );
123 0         0 return $self->pushNew( $data );
124             }
125              
126             =head2 I<$data>->popData( )
127              
128             Remove the last pushed data from the stack
129              
130             =cut
131             sub popData {
132 0     0 1 0 my ($self) = @_;
133 0         0 return pop @{$self->{'sets'}};
  0         0  
134             }
135              
136              
137             =head2 I<$data>->getDatum( $name, forceString => 1, maxDepth => undef )
138              
139             Returns the structure or scalar found in the name.
140             The name can be made up of multiple parts:
141              
142             name4_45_value is the same as $data{'name4'}[45]{'value'}
143              
144             forceString - ensures the result is a string and not an array ref
145             or undef values.
146             maxDepth - Maximum number of depths to try before giving up and
147             returning nothing, default: infinate.
148              
149             =cut
150             sub getDatum {
151 351     351 1 863 my ($self, $name, %p) = @_;
152              
153 351 50 33     1452 return '' if not defined $name or $name eq '';
154 351   100     1165 my $depth = $p{'maxDepth'} || -1;
155              
156             # This is a special data controler for
157             # printing the current scopes data to the template.
158             # Useful for debugging and seeing what is available.
159 351 50       596 if($name eq 'doc_debug_print') {
160 0         0 return $self->dataDump();
161             }
162              
163             # Search backwards for the value
164 351         355 foreach my $data (reverse(@{$self->{'sets'}})) {
  351         714  
165              
166             # Control how many of the record sets should be used
167 379 100       757 last if $depth == 0;
168 353         347 $depth--;
169              
170             # Prefix will tell you if we are in any loops
171 353         714 my $pdata = $self->_getSubStructure( $name, $data );
172 353 100       736 next if not defined $pdata;
173              
174             # Print the size of the array when required
175 311 50 66     1541 $pdata = scalar(@{$pdata}) if $p{'forceString'} and UNIVERSAL::isa($pdata, 'ARRAY');
  0         0  
176            
177             # Only return defined values
178 311 50       1706 return $pdata if defined($pdata);
179             }
180 40 100       180 return $p{'forceString'} ? '' : undef;
181             }
182              
183             =head2 I<$data>->getArrayDatum( $name )
184              
185             Like getDatum but forces output to be an array ref or undef if not valid
186              
187             =cut
188             sub getArrayDatum {
189 101     101 1 245 my ($self, $name, %p) = @_;
190 101 100       382 return $self->_makeArray($name) if $name =~ /^\-?\d+$/;
191 100         254 return $self->_makeArray($self->getDatum($name, %p));
192             }
193              
194             =head2 I<$data>->dataDump()
195              
196             Dumps all data using the current variable scope.
197              
198             =cut
199             sub dataDump {
200 0     0 1 0 my ($self) = @_;
201 0         0 return "
".$self->_debugArray($self->{'sets'}, undef)."
";
202             }
203              
204             sub _debugArray {
205 0     0   0 my ($self, $array, $prefix) = @_;
206              
207 0         0 my $result = '';
208 0         0 my $index = 0;
209 0         0 foreach my $item (@{$array}) {
  0         0  
210 0 0       0 $result .= $self->_debugItem($item, (defined $prefix ? $prefix.'_'.$index : undef) );
211 0         0 $index++;
212             }
213 0         0 return $result;
214             }
215              
216             sub _debugHash {
217 0     0   0 my ($self, $hash, $prefix) = @_;
218 0         0 my $result = '';
219 0         0 foreach my $name (keys(%{$hash})) {
  0         0  
220 0 0       0 if($name ne 'parent') {
221 0 0       0 $result .= $self->_debugItem($hash->{$name}, (defined $prefix ? $prefix.'_'.$name : $name) );
222             }
223             }
224 0         0 return $result;
225             }
226              
227             sub _debugItem {
228 0     0   0 my ($self, $item, $prefix) = @_;
229 0 0       0 return '' if not defined $item;
230 0 0       0 if(UNIVERSAL::isa($item, 'ARRAY')) {
    0          
231 0         0 return $self->_debugArray( $item, $prefix );
232             } elsif(UNIVERSAL::isa($item, 'HASH')) {
233 0         0 return $self->_debugHash( $item, $prefix );
234             }
235 0 0       0 return $prefix.": '".$item."'
" if defined $item;
236             }
237              
238              
239             =head2 I<$data>->_getSubStructure( $name, $data )
240              
241             =cut
242             sub _getSubStructure {
243 353     353   541 my ($self, $name, $data) = @_;
244 353         396 my $pdata = $data;
245              
246 353         855 foreach my $part (split(/_/, $name)) {
247 403 50       757 if(not defined($pdata)) {
248 0         0 last;
249             }
250              
251 403 100       1111 if($part =~ /^\-?\d+$/) {
252 6 100       17 if($part < 0) {
253 1         5 my $a = $self->_makeArray($pdata);
254 1         3 $pdata = $a->[@{$a}+$part];
  1         5  
255             } else {
256 5         13 $pdata = $self->_makeArray($pdata)->[$part];
257             }
258             } else {
259 397         740 $pdata = $self->_makeHash($pdata)->{$part};
260             }
261              
262             }
263 353         795 return $pdata;
264             }
265              
266              
267             =head2 I<$data>->_makeArray( $data )
268              
269             Forces the data input to be an array ref:
270              
271             Integer -> Array of indexes [ 0, 1, 2 ... $x ]
272             Code -> Returned from code execution (cont)
273             Array -> Returned Directly
274             Hash -> Returns [ { name => $i, value => $j }, ... ]
275              
276             =cut
277              
278             sub _makeArray
279             {
280 107     107   142 my ($self, $data) = @_;
281 107 100       309 return undef if not defined($data);
282 68 100       147 if(not ref($data)) {
283 6         14 my ($from, $to) = (1, 0);
284 6 50       34 if($data =~ /^\d+$/) {
285 6         8 $to = $data;
286             }
287 6 50       19 if($to >= $from) {
288 6         10 my @result;
289 6         25 for(my $i = $from; $i <= $to; $i++ ) {
290 34         71 push @result, $i;
291             }
292 6         33 return \@result;
293             }
294             }
295 62 50       177 if(UNIVERSAL::isa($data, 'CODE')) {
296 0         0 $data = &$data;
297             }
298             # This is to deal with overloaded variables
299 62 50       146 if(my $sub = overload::Method($data, '@{}')) {
300 0         0 return \@{$data};
  0         0  
301             }
302 62 50       838 if(my $sub = overload::Method($data, '%{}')) {
303 0         0 $data = \%{$data};
  0         0  
304             }
305 62 100       1029 return $data if UNIVERSAL::isa($data, 'ARRAY');
306 5 50       17 if(UNIVERSAL::isa($data, 'HASH')) {
307 5         6 my @tmparray;
308 5         8 foreach my $name (keys(%{$data})) {
  5         21  
309 15         27 my $value = $data->{$name};
310 15         60 push(@tmparray, {'name' => $name, 'value' => $value});
311             }
312 5         30 return \@tmparray;
313             }
314 0         0 return undef;
315             }
316              
317              
318             =head2 I<$data>->_makeHash( $data )
319              
320             Forces the data input to be an hash ref:
321              
322             Code -> Returned from code execution (cont)
323             Hash -> Returned Directly
324             Other -> { value => $data }
325              
326             =cut
327              
328             sub _makeHash
329             {
330 571     571   876 my ($self, $data) = @_;
331 571 50       965 return if not defined($data);
332 571 50       1617 if(UNIVERSAL::isa($data, 'CODE')) {
333 0         0 $data = &$data;
334             }
335 571 50       1374 if(my $sub = overload::Method($data, '%{}')) {
336 0         0 $data = \%{$data};
  0         0  
337             }
338 571 100       11618 return $data if UNIVERSAL::isa($data, 'HASH');
339 89         347 return { value => $data };
340             }
341              
342             =head1 AUTHOR
343              
344             Martin Owens - Copyright 2007, AGPL
345              
346             =cut
347             1;