File Coverage

blib/lib/Data/RenderAsTree.pm
Criterion Covered Total %
statement 138 159 86.7
branch 63 94 67.0
condition 19 29 65.5
subroutine 16 16 100.0
pod 2 3 66.6
total 238 301 79.0


line stmt bran cond sub pod time code
1             package Data::RenderAsTree;
2              
3 7     7   3595 use strict;
  7         8  
  7         216  
4 7     7   27 use warnings;
  7         41  
  7         148  
5              
6 7     7   4023 use Moo;
  7         87128  
  7         64  
7              
8 7     7   9866 use Scalar::Util qw/blessed reftype/;
  7         10  
  7         630  
9              
10 7     7   4509 use Set::Array;
  7         106917  
  7         293  
11              
12 7     7   4236 use Text::Truncate; # For truncstr().
  7         3057  
  7         419  
13              
14 7     7   5824 use Tree::DAG_Node;
  7         151821  
  7         314  
15              
16 7     7   5130 use Types::Standard qw/Any Bool Int Object Str/;
  7         424681  
  7         118  
17              
18             has attributes =>
19             (
20             default => sub{return 0},
21             is => 'rw',
22             isa => Bool,
23             required => 0,
24             );
25              
26             has index_stack =>
27             (
28             default => sub{return Set::Array -> new},
29             is => 'rw',
30             isa => Object,
31             required => 0,
32             );
33              
34             has max_key_length =>
35             (
36             default => sub{return 10_000},
37             is => 'rw',
38             isa => Int,
39             required => 0,
40             );
41              
42             has max_value_length =>
43             (
44             default => sub{return 10_000},
45             is => 'rw',
46             isa => Int,
47             required => 0,
48             );
49              
50             has node_stack =>
51             (
52             default => sub{return Set::Array -> new},
53             is => 'rw',
54             isa => Object,
55             required => 0,
56             );
57              
58             has root =>
59             (
60             default => sub{return ''},
61             is => 'rw',
62             isa => Any,
63             required => 0,
64             );
65              
66             has title =>
67             (
68             default => sub{return 'Root'},
69             is => 'rw',
70             isa => Str,
71             required => 0,
72             );
73              
74             has uid =>
75             (
76             default => sub{return 0},
77             is => 'rw',
78             isa => Int,
79             required => 0,
80             );
81              
82             has verbose =>
83             (
84             default => sub{return 0},
85             is => 'rw',
86             isa => Bool,
87             required => 0,
88             );
89              
90             our $VERSION = '1.01';
91              
92             # ------------------------------------------------
93              
94             sub BUILD
95             {
96 7     7 0 218 my($self) = @_;
97 7         32 my($key_length) = $self -> max_key_length;
98 7         3985 my($value_length) = $self -> max_value_length;
99              
100 7 50 33     4207 $self -> max_key_length(30) if ( ($key_length < 1) || ($key_length > 10_000) );
101 7 50 33     186 $self -> max_value_length(30) if ( ($value_length < 1) || ($value_length > 10_000) );
102              
103             } # End of BUILD.
104              
105             # ------------------------------------------------
106              
107             sub _add_daughter
108             {
109 124     124   227 my($self, $name, $attributes) = @_;
110              
111 124 50       2393 print "Entered _add_daughter($name, $attributes)\n" if ($self -> verbose);
112              
113 124 50       686 $attributes = {} if (! $attributes);
114 124         206 $$attributes{name} = $name;
115 124         2128 $$attributes{uid} = $self -> uid($self -> uid + 1);
116 124         5162 $name = truncstr($name, $self -> max_key_length);
117 124         1871 my($node) = Tree::DAG_Node -> new({name => $name, attributes => $attributes});
118 124         6533 my($tos) = $self -> node_stack -> length - 1;
119              
120 124 50       6043 die "Stack is empty\n" if ($tos < 0);
121              
122 124         121 ${$self -> node_stack}[$tos] -> add_daughter($node);
  124         2367  
123              
124 124         7266 return $node;
125              
126             } # End of _add_daughter.
127              
128             # ------------------------------------------------
129              
130             sub _process_arrayref
131             {
132 19     19   26 my($self, $value) = @_;
133              
134 19 50       319 print "Entered _process_arrayref($value)\n" if ($self -> verbose);
135              
136 19         1286 my($index) = $self -> index_stack -> last;
137 19         752 my($parent) = $self -> _process_scalar("$index = []", 'ARRAY');
138              
139 19         324 $self -> node_stack -> push($parent);
140              
141 19         763 $index = -1;
142              
143 19         23 my($bless_type);
144             my($node);
145 0         0 my($ref_type);
146              
147 19         59 for my $item (@$value)
148             {
149 37         31 $index++;
150              
151 37   50     151 $bless_type = blessed($item) || '';
152 37   100     105 $ref_type = reftype($item) || 'VALUE';
153              
154 37 50       55 if ($bless_type)
155             {
156 0         0 $self -> node_stack -> push($self -> _process_scalar("Class = $bless_type", 'BLESS') );
157             }
158              
159 37 100       100 if ($ref_type eq 'ARRAY')
    100          
    50          
160             {
161 7         137 $self -> index_stack -> push($index);
162 7         324 $self -> _process_arrayref($item);
163              
164 7         422 $index = $self -> index_stack -> pop;
165             }
166             elsif ($ref_type eq 'HASH')
167             {
168 4         12 $self -> _process_hashref($item);
169             }
170             elsif ($ref_type eq 'SCALAR')
171             {
172 0         0 $self -> _process_scalar($item);
173             }
174             else
175             {
176 26 50       499 $self -> _process_scalar("$index = " . (defined($item) ? truncstr($item, $self -> max_value_length) : 'undef') );
177             }
178              
179 37 50       612 $node = $self -> node_stack -> pop if ($bless_type);
180             }
181              
182 19         357 $node = $self -> node_stack -> pop;
183              
184             } # End of _process_arrayref;
185              
186             # ------------------------------------------------
187              
188             sub _process_hashref
189             {
190 27     27   38 my($self, $data) = @_;
191 27         40 my($index) = -1;
192              
193 27 50       576 print "Entered _process_hashref($data)\n" if ($self -> verbose);
194              
195 27         1009 my($parent) = $self -> _process_scalar('{}', 'HASH');
196              
197 27         701 $self -> node_stack -> push($parent);
198              
199 27         1396 my($bless_type);
200             my($node);
201 0         0 my($ref_type);
202 0         0 my($value);
203              
204 27         156 for my $key (sort keys %$data)
205             {
206 46         175 $index++;
207              
208 46         80 $value = $$data{$key};
209 46   100     223 $bless_type = blessed($value) || '';
210 46   100     171 $ref_type = reftype($value) || 'VALUE';
211 46 100       146 $key = "$key = {}" if ($ref_type eq 'HASH');
212              
213             # Values for use_value:
214             # 0: No, the value of value is undef. Ignore it.
215             # 1: Yes, The value may be undef, but use it.
216              
217 46         249 $node = $self -> _add_daughter
218             (
219             $key,
220             {type => $ref_type, use_value => 1, value => $value}
221             );
222              
223 46 100       147 if ($bless_type)
224             {
225 1         17 $self -> node_stack -> push($node);
226              
227 1         44 $node = $self -> _process_scalar("Class = $bless_type", 'BLESS');
228             }
229              
230 46         1016 $self -> node_stack -> push($node);
231              
232 46 100       3002 if ($ref_type eq 'ARRAY')
    100          
    50          
233             {
234 4         69 $self -> index_stack -> push($index);
235 4         162 $self -> _process_arrayref($value);
236              
237 4         254 $index = $self -> index_stack -> pop;
238             }
239             elsif ($ref_type =~ /CODE|REF|SCALAR|VALUE/)
240             {
241             # Do nothing, except for scalars. sub _process_tree() will combine $key and $value.
242              
243 31 100       96 if ($ref_type eq 'SCALAR')
244             {
245 1         9 $self -> _add_daughter
246             (
247             $value,
248             {type => $ref_type, use_value => 1, value => $$value}
249             );
250             }
251             }
252             elsif ($ref_type eq 'HASH')
253             {
254 11         53 $self -> _process_hashref($value);
255             }
256             else
257             {
258 0         0 die "Sub _process_hashref() cannot handle the ref_type: $ref_type. \n";
259             }
260              
261 46         2058 $node = $self -> node_stack -> pop;
262 46 100       2604 $node = $self -> node_stack -> pop if ($bless_type);
263              
264             # TODO: Why don't we need this in _process_arrayref()?
265             # And ... Do we need to check after each pop above?
266              
267 46 50       188 $self -> node_stack -> push($self -> root) if ($node -> is_root);
268             }
269              
270 27         886 $self -> node_stack -> pop;
271              
272             } # End of _process_hashref.
273              
274             # ------------------------------------------------
275              
276             sub _process_scalar
277             {
278 77     77   420 my($self, $value, $type) = @_;
279 77   100     169 $type ||= 'SCALAR';
280              
281 77 50       1196 print "Entered _process_scalar($value, $type)\n" if ($self -> verbose);
282              
283             # Values for use_value:
284             # 0: No, the value of value is undef. Ignore it.
285             # 1: Yes, The value may be undef, but use it.
286              
287 77         2662 return $self -> _add_daughter
288             (
289             $value,
290             {type => $type, use_value => 0, value => undef}
291             );
292              
293             } # End of _process_scalar.
294              
295             # ------------------------------------------------
296              
297             sub process_tree
298             {
299 23     23 1 34 my($self) = @_;
300              
301 23 50       607 if ($self -> verbose)
302             {
303 0         0 print "Entered process_tree(). Printing tree before walk_down ...\n";
304 0         0 print join("\n", @{$self -> root -> tree2string({no_attributes => 0})}), "\n";
  0         0  
305 0         0 print '-' x 50, "\n";
306             }
307              
308 23         133 my($attributes);
309 23         32 my($ignore_value, $id);
310 0         0 my($key);
311 0         0 my($name);
312 0         0 my($ref_type);
313 0         0 my($type);
314 0         0 my($uid, $use_value);
315 0         0 my($value);
316              
317             $self -> root -> walk_down
318             ({
319             callback => sub
320             {
321 147     147   3393 my($node, $opt) = @_;
322              
323             # Ignore the root, and keep walking.
324              
325 147 100       258 return 1 if ($node -> is_root);
326              
327 124         873 $name = $node -> name;
328 124         540 $attributes = $node -> attributes;
329 124         436 $type = $$attributes{type};
330 124 50       476 $ref_type = ($type =~ /^(\w+)/) ? $1 : $type; # Ignores '(0x12345678)'.
331 124         184 $uid = $$attributes{uid};
332 124         125 $use_value = $$attributes{use_value};
333 124         133 $value = $$attributes{value};
334 124         159 $key = "$ref_type $uid";
335              
336 124 50 66     652 if (defined($value) && $$opt{seen}{$value})
    50          
    50          
    100          
    100          
337             {
338 0 0 0     0 $id = ( ($ref_type eq 'SCALAR') || ($key =~ /^ARRAY|BLESS|HASH/) ) ? $key : "$key -> $$opt{seen}{$value}";
339             }
340             elsif ($ref_type eq 'CODE')
341             {
342 0         0 $id = $key;
343 0 0       0 $name = defined($value) ? "$name = $value" : $name;
344             }
345             elsif ($ref_type eq 'REF')
346             {
347 0 0       0 $id = defined($value) ? $$opt{seen}{$$value} ? "$key -> $$opt{seen}{$$value}" : $key : $key;
    0          
348             }
349             elsif ($ref_type eq 'VALUE')
350             {
351 32         36 $id = $key;
352 32 50       88 $name = defined($name) ? $name : 'undef';
353 32 100       828 $name .= ' = ' . truncstr(defined($value) ? $value : 'undef', $self -> max_value_length) if ($use_value);
    100          
354             }
355             elsif ($ref_type eq 'SCALAR')
356             {
357 29         23 $id = $key;
358 29 50       40 $name = defined($name) ? $name : 'undef';
359 29 50       81 $name .= ' = ' . truncstr(defined($value) ? $value : 'undef', $self -> max_value_length) if ($use_value);
    100          
360             }
361             else
362             {
363 63         77 $id = $key;
364             }
365              
366 124         737 $node -> name("$name [$id]");
367              
368 124 100 66     773 $$opt{seen}{$value} = $id if (defined($value) && ! defined $$opt{seen}{$value});
369              
370             # Keep walking.
371              
372 124         230 return 1;
373             },
374 23         409 _depth => 0,
375             seen => {},
376             });
377              
378             } # End of process_tree.
379              
380             # ------------------------------------------------
381              
382             sub render
383             {
384 23     23 1 21392 my($self, $s) = @_;
385 23 100       74 $s = defined($s) ? $s : 'undef';
386              
387 23         501 $self -> root
388             (
389             Tree::DAG_Node -> new
390             ({
391             attributes => {type => '', uid => $self -> uid, value => ''},
392             name => $self -> title,
393             })
394             );
395 23         14133 $self -> node_stack -> push($self -> root);
396 23         6427 $self -> index_stack -> push(0);
397              
398 23   100     4860 my($bless_type) = blessed($s) || '';
399 23   100     123 my($ref_type) = reftype($s) || 'VALUE';
400              
401 23 100       57 if ($bless_type)
402             {
403 1         22 $self -> node_stack -> push($self -> _process_scalar("Class = $bless_type", 'BLESS') );
404             }
405              
406 23 100       151 if ($ref_type eq 'ARRAY')
    100          
    50          
407             {
408 8         29 $self -> _process_arrayref($s);
409             }
410             elsif ($ref_type eq 'HASH')
411             {
412 12         45 $self -> _process_hashref($s);
413             }
414             elsif ($ref_type =~ /REF|SCALAR|VALUE/)
415             {
416 3         15 $self -> _process_scalar($s, $ref_type);
417             }
418             else
419             {
420 0         0 die "Sub render() cannot handle the ref_type: $ref_type. \n";
421             }
422              
423 23         1046 $self -> process_tree;
424              
425             # Clean up in case user reuses this object.
426              
427 23         1183 $self -> node_stack -> pop;
428 23         1555 $self -> index_stack -> pop;
429 23 100       972 $self -> node_stack -> pop if ($bless_type);
430 23         513 $self -> uid(0);
431              
432 23         821 return $self -> root -> tree2string({no_attributes => 1 - $self -> attributes});
433              
434             } # End of render.
435              
436             # ------------------------------------------------
437              
438             1;
439              
440             =pod
441              
442             =head1 NAME
443              
444             C - Render any data structure as an object of type Tree::DAG_Node
445              
446             =head1 Synopsis
447              
448             This is scripts/synopsis.pl:
449              
450             #!/usr/bin/env perl
451              
452             use strict;
453             use warnings;
454              
455             use Data::RenderAsTree;
456              
457             use Tree::DAG_Node;
458              
459             # ------------------------------------------------
460              
461             my($sub) = sub {};
462             my($s) =
463             {
464             A =>
465             {
466             a => {},
467             bbbbbb => $sub,
468             c123 => $sub,
469             d => \$sub,
470             },
471             B => [qw(element_1 element_2 element_3)],
472             C =>
473             {
474             b =>
475             {
476             a =>
477             {
478             a => {},
479             b => sub {},
480             c => '429999999999999999999999999999999999999999999999',
481             }
482             }
483             },
484             DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD => 'd',
485             Object => Tree::DAG_Node -> new({name => 'A tree', attributes => {one => 1} }),
486             Ref2Scalar => \'A shortish string', # Use ' in comment for UltraEdit hiliting.
487             };
488             my($result) = Data::RenderAsTree -> new
489             (
490             attributes => 0,
491             max_key_length => 25,
492             max_value_length => 20,
493             title => 'Synopsis',
494             verbose => 0,
495             ) -> render($s);
496              
497             print join("\n", @$result), "\n";
498              
499             This is the output of scripts/synopsis.pl:
500              
501             Synopsis
502             |--- {} [HASH 1]
503             |--- A = {} [HASH 2]
504             | |--- {} [HASH 3]
505             | |--- a = {} [HASH 4]
506             | | |--- {} [HASH 5]
507             | |--- bbbbbb = CODE(0x1c93e30) [CODE 6]
508             | |--- c123 [CODE 7 -> CODE 6]
509             | |--- d [REF 8 -> CODE 6]
510             |--- B [ARRAY 9]
511             | |--- 1 = [] [ARRAY 10]
512             | |--- 0 = element_1 [SCALAR 11]
513             | |--- 1 = element_2 [SCALAR 12]
514             | |--- 2 = element_3 [SCALAR 13]
515             |--- C = {} [HASH 14]
516             | |--- {} [HASH 15]
517             | |--- b = {} [HASH 16]
518             | |--- {} [HASH 17]
519             | |--- a = {} [HASH 18]
520             | |--- {} [HASH 19]
521             | |--- a = {} [HASH 20]
522             | | |--- {} [HASH 21]
523             | |--- b = CODE(0x2475c68) [CODE 22]
524             | |--- c = 42999999999999999... [VALUE 23]
525             |--- DDDDDDDDDDDDDDDDDDDDDD... = d [VALUE 24]
526             |--- Object = {} [HASH 25]
527             | |--- Class = Tree::DAG_Node [BLESS 26]
528             | |--- {} [HASH 27]
529             | |--- attributes = {} [HASH 28]
530             | | |--- {} [HASH 29]
531             | | |--- one = 1 [VALUE 30]
532             | |--- daughters [ARRAY 31]
533             | | |--- 1 = [] [ARRAY 32]
534             | |--- mother = undef [VALUE 33]
535             | |--- name = A tree [VALUE 34]
536             |--- Ref2Scalar = SCALAR(0x230a230) [SCALAR 35]
537             |--- SCALAR(0x230a230) = A shortish string [SCALAR 36]
538              
539             =head1 Description
540              
541             L provides a mechanism to display a Perl data structure.
542              
543             The data supplied to L is stored in an object of type L.
544              
545             C returns an arrayref by calling C's C method, so you can
546             just print the return value as a string by using code as in synopsis.pl above.
547              
548             It also means you can display as much or as little of the result as you wish, by printing a range
549             of array elements.
550              
551             Hash key lengths can be limited by L, and hash value lengths can be limited
552             by L.
553              
554             For sub-classing, see L.
555              
556             The module serves as a simple replacement for L, but without the huge set of
557             features.
558              
559             For sample code, see these programs in the scripts/ directory of the distro:
560              
561             =over 4
562              
563             =item o array.pl
564              
565             =item o bless.pl
566              
567             =item o hash.pl
568              
569             =item o mixup.pl
570              
571             =item o ref.pl
572              
573             =item o synopsis.pl
574              
575             =back
576              
577             See also the test files t/*.t, which are basically copies of the above. And that means, like the
578             *.pl above, all expected output is given in the source code.
579              
580             Lastly, see the L for details such as how to process the output tree yourself.
581              
582             =head1 Distributions
583              
584             This module is available as a Unix-style distro (*.tgz).
585              
586             See L
587             for help on unpacking and installing distros.
588              
589             =head1 Installation
590              
591             Install L as you would for any C module:
592              
593             Run:
594              
595             cpanm Data::RenderAsTree
596              
597             or run:
598              
599             sudo cpan Data::RenderAsTree
600              
601             or unpack the distro, and then either:
602              
603             perl Build.PL
604             ./Build
605             ./Build test
606             sudo ./Build install
607              
608             or:
609              
610             perl Makefile.PL
611             make (or dmake or nmake)
612             make test
613             make install
614              
615             =head1 Constructor and Initialization
616              
617             C is called as C<< my($g2m) = Data::RenderAsTree -> new(k1 => v1, k2 => v2, ...) >>.
618              
619             It returns a new object of type C.
620              
621             Key-value pairs accepted in the parameter list (see corresponding methods for details
622             [e.g. L]):
623              
624             =over 4
625              
626             =item o attributes => $Boolean
627              
628             This is a debugging aid. When set to 1, metadata attached to each tree node is included in the
629             output.
630              
631             Default: 0.
632              
633             =item o max_key_length => $int
634              
635             Use this to limit the lengths of hash keys.
636              
637             Default: 10_000.
638              
639             =item o max_value_length => $int
640              
641             Use this to limit the lengths of hash values.
642              
643             Default: 10_000.
644              
645             =item o title => $s
646              
647             Use this to set the name of the root node in the tree.
648              
649             Default: 'Root'.
650              
651             =back
652              
653             =head1 Methods
654              
655             =head2 attributes([$Boolean])
656              
657             Here, the [] indicate an optional parameter.
658              
659             Gets or sets the attributes option.
660              
661             Note: The value passed to L's C method is (1 - $Boolean).
662              
663             C is a parameter to L.
664              
665             =head2 max_key_length([$int])
666              
667             Here, the [] indicate an optional parameter.
668              
669             Gets or sets the maximum string length displayed for hash keys.
670              
671             C is a parameter to L.
672              
673             =head2 max_key_length([$int])
674              
675             Here, the [] indicate an optional parameter.
676              
677             Gets or sets the maximum string length displayed for hash values.
678              
679             C is a parameter to L.
680              
681             =head2 new()
682              
683             See L for details on the parameters accepted by L.
684              
685             =head2 process_tree()
686              
687             Just before L returns, it calls C, while walks the tree and adjusts
688             various bits of data attached to each node in the tree.
689              
690             If sub-classing this module, e.g. to change the precise text displayed, I recommend concentrating
691             your efforts on this method.
692              
693             Alternately, see the answer to the first question in the L.
694              
695             =head2 root()
696              
697             Returns the root node in the tree, which is an object of type L.
698              
699             =head2 render($s)
700              
701             Renders $s into an object of type L.
702              
703             Returns an arrayref after calling the C method for L.
704              
705             See L for a typical usage.
706              
707             =head2 title([$s])
708              
709             Here, the [] indicate an optional parameter.
710              
711             Gets or sets the title, which is the name of the root node in the tree.
712              
713             C is a parameter to L</new()>. </td> </tr> <tr> <td class="h" > <a name="714">714</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="715">715</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head2 verbose([$Boolean]) </td> </tr> <tr> <td class="h" > <a name="716">716</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="717">717</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Here, the [] indicate an optional parameter. </td> </tr> <tr> <td class="h" > <a name="718">718</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="719">719</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Gets or sets the verbose option, which prints a message upon entry to each method, with parameters, </td> </tr> <tr> <td class="h" > <a name="720">720</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> and prints the tree at the start of L</process_tree()>. </td> </tr> <tr> <td class="h" > <a name="721">721</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="722">722</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> C<verbose> is a parameter to L</new()>. </td> </tr> <tr> <td class="h" > <a name="723">723</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="724">724</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head1 FAQ </td> </tr> <tr> <td class="h" > <a name="725">725</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="726">726</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head2 Can I process the tree myself? </td> </tr> <tr> <td class="h" > <a name="727">727</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="728">728</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Sure. Just call L</root()> - after L</render()> - to get the root of the tree, and process it any </td> </tr> <tr> <td class="h" > <a name="729">729</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> way you wish. </td> </tr> <tr> <td class="h" > <a name="730">730</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="731">731</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> See L</process_tree()> for sample code. More information is in the docs for L<Tree::DAG_Node> </td> </tr> <tr> <td class="h" > <a name="732">732</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> especially under the discussion of C<walk_down()>. </td> </tr> <tr> <td class="h" > <a name="733">733</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="734">734</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head2 What are the attributes of the tree nodes? </td> </tr> <tr> <td class="h" > <a name="735">735</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="736">736</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Firslty, each node has a name, which you can set or get with the C<name([$new_name])> method. Here, </td> </tr> <tr> <td class="h" > <a name="737">737</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> [] refer to an optional parameter. </td> </tr> <tr> <td class="h" > <a name="738">738</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="739">739</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Secondly, the attributes of each node are held in a hashref, getable and setable with the </td> </tr> <tr> <td class="h" > <a name="740">740</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> C<attributes([$hashref])> method. The returned hashref has these (key => value) pairs: </td> </tr> <tr> <td class="h" > <a name="741">741</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="742">742</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =over 4 </td> </tr> <tr> <td class="h" > <a name="743">743</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="744">744</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item o name => $string </td> </tr> <tr> <td class="h" > <a name="745">745</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="746">746</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> This is a copy of the name of the node. It's here because L</process_tree()> changes the name of </td> </tr> <tr> <td class="h" > <a name="747">747</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> some nodes as it walks the tree. </td> </tr> <tr> <td class="h" > <a name="748">748</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="749">749</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item o type => $string </td> </tr> <tr> <td class="h" > <a name="750">750</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="751">751</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> This is the C<reftype()> (from the module L</Scalar::Util>) of the value (see the C<value> key, </td> </tr> <tr> <td class="h" > <a name="752">752</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> below), or one of various strings I use, and hence has values like: </td> </tr> <tr> <td class="h" > <a name="753">753</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="754">754</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =over 4 </td> </tr> <tr> <td class="h" > <a name="755">755</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="756">756</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item o ARRAY </td> </tr> <tr> <td class="h" > <a name="757">757</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="758">758</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> The value is an arrayref. </td> </tr> <tr> <td class="h" > <a name="759">759</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="760">760</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item o BLESS </td> </tr> <tr> <td class="h" > <a name="761">761</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="762">762</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> The value is blessed into a class, who name is in the value. </td> </tr> <tr> <td class="h" > <a name="763">763</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="764">764</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item o CODE </td> </tr> <tr> <td class="h" > <a name="765">765</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="766">766</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> The value is a coderef. </td> </tr> <tr> <td class="h" > <a name="767">767</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="768">768</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item o HASH </td> </tr> <tr> <td class="h" > <a name="769">769</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="770">770</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> The value is a hashref. </td> </tr> <tr> <td class="h" > <a name="771">771</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="772">772</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item o REF </td> </tr> <tr> <td class="h" > <a name="773">773</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="774">774</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> The value is presumably a generic reference. I could not see an explanation which I skimmed the </td> </tr> <tr> <td class="h" > <a name="775">775</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> output of 'perldoc perlref'. </td> </tr> <tr> <td class="h" > <a name="776">776</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="777">777</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item o SCALAR </td> </tr> <tr> <td class="h" > <a name="778">778</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="779">779</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> The value is a scalarref. </td> </tr> <tr> <td class="h" > <a name="780">780</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="781">781</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item o VALUE </td> </tr> <tr> <td class="h" > <a name="782">782</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="783">783</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> The value is just a literal value. </td> </tr> <tr> <td class="h" > <a name="784">784</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="785">785</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> I did not use LITERAL because the 1-letter abbreviation 'L' clashes with the 1-letter abbreviation </td> </tr> <tr> <td class="h" > <a name="786">786</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> of 'LVALUE', which C<reftype()> can return. </td> </tr> <tr> <td class="h" > <a name="787">787</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="788">788</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =back </td> </tr> <tr> <td class="h" > <a name="789">789</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="790">790</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Other values returned by C<reftype()> are not used by this module. </td> </tr> <tr> <td class="h" > <a name="791">791</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="792">792</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item o uid => $integer </td> </tr> <tr> <td class="h" > <a name="793">793</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="794">794</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Each node in the tree has a unique integer identifier, counting from 1 up. </td> </tr> <tr> <td class="h" > <a name="795">795</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="796">796</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item o use_value => $Boolean </td> </tr> <tr> <td class="h" > <a name="797">797</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="798">798</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Node values (see next point) can be undef, and this flag serves the following purpose: </td> </tr> <tr> <td class="h" > <a name="799">799</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="800">800</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =over </td> </tr> <tr> <td class="h" > <a name="801">801</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="802">802</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item o Zero </td> </tr> <tr> <td class="h" > <a name="803">803</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="804">804</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Do not use the value. It's undef, and set by the code, and thus not a real node's value. </td> </tr> <tr> <td class="h" > <a name="805">805</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="806">806</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item o One </td> </tr> <tr> <td class="h" > <a name="807">807</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="808">808</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> The node's value really is undef, or any other value. Use it in the output. </td> </tr> <tr> <td class="h" > <a name="809">809</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="810">810</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =back </td> </tr> <tr> <td class="h" > <a name="811">811</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="812">812</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item o value => $string </td> </tr> <tr> <td class="h" > <a name="813">813</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="814">814</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Finally, the actual value of the node. </td> </tr> <tr> <td class="h" > <a name="815">815</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="816">816</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =back </td> </tr> <tr> <td class="h" > <a name="817">817</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="818">818</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head2 Why are there so many levels in the output? </td> </tr> <tr> <td class="h" > <a name="819">819</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="820">820</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Or: Couldn't you cut some cases showing '{}' and '[]'? </td> </tr> <tr> <td class="h" > <a name="821">821</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="822">822</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Cutting them introduces other problems, especially when the input is a set of nested arrayrefs. </td> </tr> <tr> <td class="h" > <a name="823">823</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="824">824</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> See scripts/array.pl, example 4 (hash key 4), for such a case. </td> </tr> <tr> <td class="h" > <a name="825">825</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="826">826</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head2 Why do you decorate the output with e.g. [HASH 1] and not [H1]? </td> </tr> <tr> <td class="h" > <a name="827">827</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="828">828</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> I feel the style [H1] used by L<Data::TreeDumper> is unnecessarily cryptic. </td> </tr> <tr> <td class="h" > <a name="829">829</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="830">830</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head2 I found a problem with the output of synopsis.pl! </td> </tr> <tr> <td class="h" > <a name="831">831</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="832">832</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> It says: </td> </tr> <tr> <td class="h" > <a name="833">833</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="834">834</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> |--- B [ARRAY 9] </td> </tr> <tr> <td class="h" > <a name="835">835</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> | |--- 1 = [] [ARRAY 10] </td> </tr> <tr> <td class="h" > <a name="836">836</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="837">837</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Why is there a '1 = []' in there? </td> </tr> <tr> <td class="h" > <a name="838">838</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="839">839</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Firstly, note that C<hash> keys are returned in sorted order. </td> </tr> <tr> <td class="h" > <a name="840">840</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="841">841</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> And, for C<hash> keys, that integer counts them, so C<A> would have gotten a 0, and C<C> would get a </td> </tr> <tr> <td class="h" > <a name="842">842</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> 2, if they pointed to arrayrefs. </td> </tr> <tr> <td class="h" > <a name="843">843</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="844">844</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head2 Why did you use Text::Truncate? </td> </tr> <tr> <td class="h" > <a name="845">845</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="846">846</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> The major alternatives are L<String::Truncate> and L<Text::Elide>, or re-inventing the wheel. </td> </tr> <tr> <td class="h" > <a name="847">847</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="848">848</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> The first module seems too complex, and the second truncates to whole words, which makes sense in </td> </tr> <tr> <td class="h" > <a name="849">849</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> some applications, but not for dumping raw data. </td> </tr> <tr> <td class="h" > <a name="850">850</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="851">851</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head2 How would I go about sub-classing this module? </td> </tr> <tr> <td class="h" > <a name="852">852</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="853">853</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> This matter is discussed in the notes for method L</process_tree()>. </td> </tr> <tr> <td class="h" > <a name="854">854</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="855">855</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head1 See Also </td> </tr> <tr> <td class="h" > <a name="856">856</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="857">857</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> L<Data::TreeDumper>. </td> </tr> <tr> <td class="h" > <a name="858">858</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="859">859</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head1 Machine-Readable Change Log </td> </tr> <tr> <td class="h" > <a name="860">860</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="861">861</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> The file Changes was converted into Changelog.ini by L<Module::Metadata::Changes>. </td> </tr> <tr> <td class="h" > <a name="862">862</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="863">863</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head1 Version Numbers </td> </tr> <tr> <td class="h" > <a name="864">864</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="865">865</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Version numbers < 1.00 represent development versions. From 1.00 up, they are production versions. </td> </tr> <tr> <td class="h" > <a name="866">866</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="867">867</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head1 Repository </td> </tr> <tr> <td class="h" > <a name="868">868</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="869">869</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> L<https://github.com/ronsavage/Data-RenderAsTree> </td> </tr> <tr> <td class="h" > <a name="870">870</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="871">871</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head1 Support </td> </tr> <tr> <td class="h" > <a name="872">872</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="873">873</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Email the author, or log a bug on RT: </td> </tr> <tr> <td class="h" > <a name="874">874</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="875">875</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data::RenderAsTree>. </td> </tr> <tr> <td class="h" > <a name="876">876</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="877">877</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head1 Author </td> </tr> <tr> <td class="h" > <a name="878">878</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="879">879</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> L<Data::RenderAsTree> was written by Ron Savage I<E<lt>ron@savage.net.auE<gt>> in 2015. </td> </tr> <tr> <td class="h" > <a name="880">880</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="881">881</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> My homepage: L<http://savage.net.au/>. </td> </tr> <tr> <td class="h" > <a name="882">882</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="883">883</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head1 Copyright </td> </tr> <tr> <td class="h" > <a name="884">884</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="885">885</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Australian copyright (c) 2015, Ron Savage. </td> </tr> <tr> <td class="h" > <a name="886">886</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="887">887</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> All Programs of mine are 'OSI Certified Open Source Software'; </td> </tr> <tr> <td class="h" > <a name="888">888</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> you can redistribute them and/or modify them under the terms of </td> </tr> <tr> <td class="h" > <a name="889">889</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> The Artistic License 2.0, a copy of which is available at: </td> </tr> <tr> <td class="h" > <a name="890">890</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> http://opensource.org/licenses/alphabetical. </td> </tr> <tr> <td class="h" > <a name="891">891</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="892">892</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =cut </td> </tr> </table> </body> </html>