File Coverage

blib/lib/Data/RenderAsTree.pm
Criterion Covered Total %
statement 150 181 82.8
branch 64 104 61.5
condition 19 29 65.5
subroutine 17 19 89.4
pod 3 5 60.0
total 253 338 74.8


line stmt bran cond sub pod time code
1             package Data::RenderAsTree;
2              
3 8     8   62140 use strict;
  8         19  
  8         356  
4 8     8   45 use warnings;
  8         17  
  8         529  
5              
6 8     8   5319 use Moo;
  8         92372  
  8         46  
7              
8 8     8   15264 use Scalar::Util qw/blessed reftype/;
  8         30  
  8         741  
9              
10 8     8   5643 use Set::Array;
  8         160881  
  8         390  
11              
12 8     8   4421 use Text::Truncate; # For truncstr().
  8         5055  
  8         616  
13              
14 8     8   7224 use Tree::DAG_Node;
  8         327314  
  8         546  
15              
16 8     8   6280 use Types::Standard qw/Any Bool Int Object Str/;
  8         1207247  
  8         144  
17              
18             has clean_nodes =>
19             (
20             default => sub{return 0},
21             is => 'rw',
22             isa => Bool,
23             required => 0,
24             );
25              
26             has attributes =>
27             (
28             default => sub{return 0},
29             is => 'rw',
30             isa => Bool,
31             required => 0,
32             );
33              
34             has index_stack =>
35             (
36             default => sub{return Set::Array -> new},
37             is => 'rw',
38             isa => Object,
39             required => 0,
40             );
41              
42             has max_key_length =>
43             (
44             default => sub{return 10_000},
45             is => 'rw',
46             isa => Int,
47             required => 0,
48             );
49              
50             has max_value_length =>
51             (
52             default => sub{return 10_000},
53             is => 'rw',
54             isa => Int,
55             required => 0,
56             );
57              
58             has node_stack =>
59             (
60             default => sub{return Set::Array -> new},
61             is => 'rw',
62             isa => Object,
63             required => 0,
64             );
65              
66             has root =>
67             (
68             default => sub{return ''},
69             is => 'rw',
70             isa => Any,
71             required => 0,
72             );
73              
74             has title =>
75             (
76             default => sub{return 'Root'},
77             is => 'rw',
78             isa => Str,
79             required => 0,
80             );
81              
82             has uid =>
83             (
84             default => sub{return 0},
85             is => 'rw',
86             isa => Int,
87             required => 0,
88             );
89              
90             has verbose =>
91             (
92             default => sub{return 0},
93             is => 'rw',
94             isa => Bool,
95             required => 0,
96             );
97              
98             our $VERSION = '1.04';
99              
100             # ------------------------------------------------
101              
102             sub BUILD
103             {
104 8     8 0 399 my($self) = @_;
105 8         270 my($key_length) = $self -> max_key_length;
106 8         251 my($value_length) = $self -> max_value_length;
107              
108 8 50 33     132 $self -> max_key_length(30) if ( ($key_length < 1) || ($key_length > 10_000) );
109 8 50 33     122 $self -> max_value_length(30) if ( ($value_length < 1) || ($value_length > 10_000) );
110              
111             } # End of BUILD.
112              
113             # ------------------------------------------------
114              
115             sub _add_daughter
116             {
117 125     125   259 my($self, $name, $attributes) = @_;
118              
119 125 50       2664 print "Entered _add_daughter($name, $attributes)\n" if ($self -> verbose);
120              
121 125 50       863 $attributes = {} if (! $attributes);
122 125         353 $$attributes{name} = $name;
123 125         2431 $$attributes{uid} = $self -> uid($self -> uid + 1);
124 125         6552 $name = truncstr($name, $self -> max_key_length);
125 125         2698 my($node) = Tree::DAG_Node -> new({name => $name, attributes => $attributes});
126 125         9710 my($tos) = $self -> node_stack -> length - 1;
127              
128 125 50       8394 die "Stack is empty\n" if ($tos < 0);
129              
130 125         205 ${$self -> node_stack}[$tos] -> add_daughter($node);
  125         2794  
131              
132 125         11416 return $node;
133              
134             } # End of _add_daughter.
135              
136             # --------------------------------------------------
137              
138             sub clean_tree
139             {
140 0     0 0 0 my($self) = @_;
141              
142 0         0 my($attributes);
143             my($key);
144 0         0 my($name);
145 0         0 my($value);
146              
147             $self -> root -> walk_down
148             ({
149             callback => sub
150             {
151 0     0   0 my($node, $opt) = @_;
152 0         0 $name = $node -> name;
153 0         0 $attributes = $node -> attributes;
154              
155             # Fix for name is undef.
156              
157 0 0       0 $node -> name('') if (! defined $name);
158              
159             # Fix for attribute name is undef.
160              
161 0 0       0 if (exists $$attributes{undef})
162             {
163 0 0       0 if (! exists $$attributes{''})
164             {
165 0         0 $$attributes{''} = $$attributes{undef};
166             }
167              
168 0         0 delete $$attributes{undef};
169             }
170              
171             # Fix for attribute value is undef.
172              
173 0         0 for $key (keys %$attributes)
174             {
175 0         0 $value = $$attributes{$key};
176 0 0       0 $value = '' if (! defined $value);
177 0         0 $$attributes{$key} = $value;
178             }
179              
180 0         0 $node -> attributes($attributes);
181              
182 0         0 return 1; # Keep walking.
183             },
184 0         0 _depth => 0,
185             });
186              
187             } # End of clean_tree.
188              
189             # ------------------------------------------------
190              
191             sub _process_arrayref
192             {
193 19     19   36 my($self, $value) = @_;
194              
195 19 50       409 print "Entered _process_arrayref($value)\n" if ($self -> verbose);
196              
197 19         370 my($index) = $self -> index_stack -> last;
198 19         1064 my($parent) = $self -> _process_scalar("$index = []", 'ARRAY');
199              
200 19         393 $self -> node_stack -> push($parent);
201              
202 19         1019 $index = -1;
203              
204 19         40 my($bless_type);
205             my($node);
206 19         0 my($ref_type);
207              
208 19         43 for my $item (@$value)
209             {
210 37         45 $index++;
211              
212 37   50     156 $bless_type = blessed($item) || '';
213 37   100     92 $ref_type = reftype($item) || 'VALUE';
214              
215 37 50       71 if ($bless_type)
216             {
217 0         0 $self -> node_stack -> push($self -> _process_scalar("Class = $bless_type", 'BLESS') );
218             }
219              
220 37 100       91 if ($ref_type eq 'ARRAY')
    100          
    50          
221             {
222 7         103 $self -> index_stack -> push($index);
223 7         355 $self -> _process_arrayref($item);
224              
225 7         402 $index = $self -> index_stack -> pop;
226             }
227             elsif ($ref_type eq 'HASH')
228             {
229 4         13 $self -> _process_hashref($item);
230             }
231             elsif ($ref_type eq 'SCALAR')
232             {
233 0         0 $self -> _process_scalar($item);
234             }
235             else
236             {
237 26 50       506 $self -> _process_scalar("$index = " . (defined($item) ? truncstr($item, $self -> max_value_length) : 'undef') );
238             }
239              
240 37 50       742 $node = $self -> node_stack -> pop if ($bless_type);
241             }
242              
243 19         342 $node = $self -> node_stack -> pop;
244              
245             } # End of _process_arrayref;
246              
247             # ------------------------------------------------
248              
249             sub _process_hashref
250             {
251 27     27   58 my($self, $data) = @_;
252 27         54 my($index) = -1;
253              
254 27 50       774 print "Entered _process_hashref($data)\n" if ($self -> verbose);
255              
256 27         230 my($parent) = $self -> _process_scalar('{}', 'HASH');
257              
258 27         725 $self -> node_stack -> push($parent);
259              
260 27         2068 my($bless_type);
261             my($node);
262 27         0 my($ref_type);
263 27         0 my($value);
264              
265 27         147 for my $key (sort keys %$data)
266             {
267 46         310 $index++;
268              
269 46         122 $value = $$data{$key};
270 46   100     264 $bless_type = blessed($value) || '';
271 46   100     163 $ref_type = reftype($value) || 'VALUE';
272 46 100       155 $key = "$key = {}" if ($ref_type eq 'HASH');
273              
274             # Values for use_value:
275             # 0: No, the value of value is undef. Ignore it.
276             # 1: Yes, The value may be undef, but use it.
277              
278 46         291 $node = $self -> _add_daughter
279             (
280             $key,
281             {type => $ref_type, use_value => 1, value => $value}
282             );
283              
284 46 100       176 if ($bless_type)
285             {
286 1         29 $self -> node_stack -> push($node);
287              
288 1         135 $node = $self -> _process_scalar("Class = $bless_type", 'BLESS');
289             }
290              
291 46         1238 $self -> node_stack -> push($node);
292              
293 46 100       3800 if ($ref_type eq 'ARRAY')
    100          
    50          
294             {
295 4         93 $self -> index_stack -> push($index);
296 4         344 $self -> _process_arrayref($value);
297              
298 4         291 $index = $self -> index_stack -> pop;
299             }
300             elsif ($ref_type =~ /CODE|REF|SCALAR|VALUE/)
301             {
302             # Do nothing, except for scalars. sub _process_tree() will combine $key and $value.
303              
304 31 100       116 if ($ref_type eq 'SCALAR')
305             {
306 1         9 $self -> _add_daughter
307             (
308             $value,
309             {type => $ref_type, use_value => 1, value => $$value}
310             );
311             }
312             }
313             elsif ($ref_type eq 'HASH')
314             {
315 11         62 $self -> _process_hashref($value);
316             }
317             else
318             {
319 0         0 die "Sub _process_hashref() cannot handle the ref_type: $ref_type. \n";
320             }
321              
322 46         2181 $node = $self -> node_stack -> pop;
323 46 100       3442 $node = $self -> node_stack -> pop if ($bless_type);
324              
325             # TODO: Why don't we need this in _process_arrayref()?
326             # And ... Do we need to check after each pop above?
327              
328 46 50       236 $self -> node_stack -> push($self -> root) if ($node -> is_root);
329             }
330              
331 27         968 $self -> node_stack -> pop;
332              
333             } # End of _process_hashref.
334              
335             # ------------------------------------------------
336              
337             sub _process_scalar
338             {
339 78     78   528 my($self, $value, $type) = @_;
340 78   100     224 $type ||= 'SCALAR';
341              
342 78 50       1499 print "Entered _process_scalar($value, $type)\n" if ($self -> verbose);
343              
344             # Values for use_value:
345             # 0: No, the value of value is undef. Ignore it.
346             # 1: Yes, The value may be undef, but use it.
347              
348 78         794 return $self -> _add_daughter
349             (
350             $value,
351             {type => $type, use_value => 0, value => undef}
352             );
353              
354             } # End of _process_scalar.
355              
356             # ------------------------------------------------
357              
358             sub process_tree
359             {
360 24     24 1 60 my($self) = @_;
361              
362 24 50       561 if ($self -> verbose)
363             {
364 0         0 print "Entered process_tree(). Printing tree before walk_down ...\n";
365 0         0 print join("\n", @{$self -> root -> tree2string({no_attributes => 0})}), "\n";
  0         0  
366 0         0 print '-' x 50, "\n";
367             }
368              
369 24         172 my($attributes);
370 24         182 my($ignore_value, $id);
371 24         0 my($key);
372 24         0 my($name);
373 24         0 my($ref_type);
374 24         0 my($type);
375 24         0 my($uid, $use_value);
376 24         0 my($value);
377              
378             $self -> root -> walk_down
379             ({
380             callback => sub
381             {
382 149     149   5091 my($node, $opt) = @_;
383              
384             # Ignore the root, and keep walking.
385              
386 149 100       334 return 1 if ($node -> is_root);
387              
388 125         1259 $name = $node -> name;
389 125         810 $attributes = $node -> attributes;
390 125         796 $type = $$attributes{type};
391 125 50       609 $ref_type = ($type =~ /^(\w+)/) ? $1 : $type; # Ignores '(0x12345678)'.
392 125         255 $uid = $$attributes{uid};
393 125         195 $use_value = $$attributes{use_value};
394 125         221 $value = $$attributes{value};
395 125         238 $key = "$ref_type $uid";
396              
397 125 50 66     628 if (defined($value) && $$opt{seen}{$value})
    50          
    50          
    100          
    100          
398             {
399 0 0 0     0 $id = ( ($ref_type eq 'SCALAR') || ($key =~ /^ARRAY|BLESS|HASH/) ) ? $key : "$key -> $$opt{seen}{$value}";
400             }
401             elsif ($ref_type eq 'CODE')
402             {
403 0         0 $id = $key;
404 0 0       0 $name = defined($value) ? "$name = $value" : $name;
405             }
406             elsif ($ref_type eq 'REF')
407             {
408 0 0       0 $id = defined($value) ? $$opt{seen}{$$value} ? "$key -> $$opt{seen}{$$value}" : $key : $key;
    0          
409             }
410             elsif ($ref_type eq 'VALUE')
411             {
412 33         73 $id = $key;
413 33 50       72 $name = defined($name) ? $name : 'undef';
414 33 100       1005 $name .= ' = ' . truncstr(defined($value) ? $value : 'undef', $self -> max_value_length) if ($use_value);
    100          
415             }
416             elsif ($ref_type eq 'SCALAR')
417             {
418 29         39 $id = $key;
419 29 50       64 $name = defined($name) ? $name : 'undef';
420 29 50       115 $name .= ' = ' . truncstr(defined($value) ? $value : 'undef', $self -> max_value_length) if ($use_value);
    100          
421             }
422             else
423             {
424 63         145 $id = $key;
425             }
426              
427 125         1119 $node -> name("$name [$id]");
428              
429 125 100 66     1000 $$opt{seen}{$value} = $id if (defined($value) && ! defined $$opt{seen}{$value});
430              
431             # Keep walking.
432              
433 125         240 return 1;
434             },
435 24         794 _depth => 0,
436             seen => {},
437             });
438              
439             } # End of process_tree.
440              
441             # ------------------------------------------------
442              
443             sub render
444             {
445 24     24 1 27138 my($self, $s) = @_;
446              
447 24         131 $self -> run($s);
448              
449 24         1219 return $self -> root -> tree2string({no_attributes => 1 - $self -> attributes});
450              
451             } # End of render.
452              
453             # ------------------------------------------------
454              
455             sub run
456             {
457 24     24 1 76 my($self, $s) = @_;
458 24 100       91 $s = defined($s) ? $s : 'undef';
459              
460 24         890 $self -> root
461             (
462             Tree::DAG_Node -> new
463             ({
464             attributes => {type => '', uid => $self -> uid, value => ''},
465             name => $self -> title,
466             })
467             );
468 24         4677 $self -> node_stack -> push($self -> root);
469 24         3805 $self -> index_stack -> push(0);
470              
471 24   100     1805 my($bless_type) = blessed($s) || '';
472 24   100     110 my($ref_type) = reftype($s) || 'VALUE';
473              
474 24 100       69 if ($bless_type)
475             {
476 1         24 $self -> node_stack -> push($self -> _process_scalar("Class = $bless_type", 'BLESS') );
477             }
478              
479 24 100       187 if ($ref_type eq 'ARRAY')
    100          
    50          
480             {
481 8         30 $self -> _process_arrayref($s);
482             }
483             elsif ($ref_type eq 'HASH')
484             {
485 12         77 $self -> _process_hashref($s);
486             }
487             elsif ($ref_type =~ /REF|SCALAR|VALUE/)
488             {
489 4         24 $self -> _process_scalar($s, $ref_type);
490             }
491             else
492             {
493 0         0 die "Sub render() cannot handle the ref_type: $ref_type. \n";
494             }
495              
496 24         1376 $self -> process_tree;
497 24 50       1767 $self -> clean_tree if ($self -> clean_nodes);
498              
499             # Clean up in case user reuses this object.
500              
501 24         673 $self -> node_stack -> pop;
502 24         2490 $self -> index_stack -> pop;
503 24 100       1693 $self -> node_stack -> pop if ($bless_type);
504 24         606 $self -> uid(0);
505              
506             } # End of run.
507              
508             # ------------------------------------------------
509              
510             1;
511              
512             =pod
513              
514             =head1 NAME
515              
516             C - Render any data structure as an object of type Tree::DAG_Node
517              
518             =head1 Synopsis
519              
520             This is scripts/synopsis.pl:
521              
522             #!/usr/bin/env perl
523              
524             use strict;
525             use warnings;
526              
527             use Data::RenderAsTree;
528              
529             use Tree::DAG_Node;
530              
531             # ------------------------------------------------
532              
533             print "Code refs are always be different, so we do not use \$expected\n";
534              
535             my($sub) = sub {};
536             my($s) =
537             {
538             A =>
539             {
540             a => {},
541             bbbbbb => $sub,
542             c123 => $sub,
543             d => \$sub,
544             },
545             B => [qw(element_1 element_2 element_3)],
546             C =>
547             {
548             b =>
549             {
550             a =>
551             {
552             a => {},
553             b => sub {},
554             c => '429999999999999999999999999999999999999999999999',
555             }
556             }
557             },
558             DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD => 'd',
559             Object => Tree::DAG_Node -> new({name => 'A tree', attributes => {one => 1} }),
560             Ref2Scalar => \'A shortish string', # Use ' in comment for UltraEdit hiliting.
561             };
562             my($result) = Data::RenderAsTree -> new
563             (
564             attributes => 0,
565             max_key_length => 25,
566             max_value_length => 20,
567             title => 'Synopsis',
568             verbose => 0,
569             ) -> render($s);
570              
571             print join("\n", @$result), "\n";
572              
573             See the L for a discussion as to whether you should call L or L.
574              
575             This is the output of scripts/synopsis.pl:
576              
577             Code refs are always be different, so we do not use $expected
578             Synopsis. Attributes: {}
579             |--- {} [HASH 1]. Attributes: {}
580             |--- A = {} [HASH 2]. Attributes: {}
581             | |--- {} [HASH 3]. Attributes: {}
582             | |--- a = {} [HASH 4]. Attributes: {}
583             | | |--- {} [HASH 5]. Attributes: {}
584             | |--- bbbbbb = CODE(0x55d5168d1b18) [CODE 6]. Attributes: {}
585             | |--- c123 [CODE 7 -> CODE 6]. Attributes: {}
586             | |--- d [REF 8 -> CODE 6]. Attributes: {}
587             |--- B [ARRAY 9]. Attributes: {}
588             | |--- 1 = [] [ARRAY 10]. Attributes: {}
589             | |--- 0 = element_1 [SCALAR 11]. Attributes: {}
590             | |--- 1 = element_2 [SCALAR 12]. Attributes: {}
591             | |--- 2 = element_3 [SCALAR 13]. Attributes: {}
592             |--- C = {} [HASH 14]. Attributes: {}
593             | |--- {} [HASH 15]. Attributes: {}
594             | |--- b = {} [HASH 16]. Attributes: {}
595             | |--- {} [HASH 17]. Attributes: {}
596             | |--- a = {} [HASH 18]. Attributes: {}
597             | |--- {} [HASH 19]. Attributes: {}
598             | |--- a = {} [HASH 20]. Attributes: {}
599             | | |--- {} [HASH 21]. Attributes: {}
600             | |--- b = CODE(0x55d51702db90) [CODE 22]. Attributes: {}
601             | |--- c = 42999999999999999... [VALUE 23]. Attributes: {}
602             |--- DDDDDDDDDDDDDDDDDDDDDD... = d [VALUE 24]. Attributes: {}
603             |--- Object = {} [HASH 25]. Attributes: {}
604             | |--- Class = Tree::DAG_Node [BLESS 26]. Attributes: {}
605             | |--- {} [HASH 27]. Attributes: {}
606             | |--- attributes = {} [HASH 28]. Attributes: {}
607             | | |--- {} [HASH 29]. Attributes: {}
608             | | |--- one = 1 [VALUE 30]. Attributes: {}
609             | |--- daughters [ARRAY 31]. Attributes: {}
610             | | |--- 1 = [] [ARRAY 32]. Attributes: {}
611             | |--- mother = undef [VALUE 33]. Attributes: {}
612             | |--- name = A tree [VALUE 34]. Attributes: {}
613             |--- Ref2Scalar = SCALAR(0x55d51703... [SCALAR 35]. Attributes: {}
614             |--- SCALAR(0x55d51703bc20) = A shortish string [SCALAR 36]. Attributes: {}
615              
616             =head1 Description
617              
618             L provides a mechanism to display a Perl data structure.
619              
620             The data supplied to L is stored in an object of type L.
621              
622             C returns an arrayref by calling C's C method, so you can
623             just print the return value as a string by using code as in synopsis.pl above.
624              
625             It also means you can display as much or as little of the result as you wish, by printing a range
626             of array elements.
627              
628             Hash key lengths can be limited by L, and hash value lengths can be limited
629             by L.
630              
631             For sub-classing, see L.
632              
633             The module serves as a simple replacement for L, but without the huge set of
634             features.
635              
636             For sample code, see these programs in the scripts/ directory of the distro:
637              
638             =over 4
639              
640             =item o array.pl
641              
642             =item o bless.pl
643              
644             =item o empty.pl
645              
646             =item o hash.pl
647              
648             =item o mixup.pl
649              
650             =item o ref.pl
651              
652             =item o synopsis.pl
653              
654             =item o undef.pl
655              
656             =item o zero.pl
657              
658             =back
659              
660             See also the test files t/*.t, which are basically copies of the above. And that means, like the
661             *.pl above, all expected output is given in the source code.
662              
663             Lastly, see the L below for details such as how to process the output tree yourself.
664              
665             =head1 Distributions
666              
667             This module is available as a Unix-style distro (*.tgz).
668              
669             See L
670             for help on unpacking and installing distros.
671              
672             =head1 Installation
673              
674             Install L as you would for any C module:
675              
676             Run:
677              
678             cpanm Data::RenderAsTree
679              
680             or run:
681              
682             sudo cpan Data::RenderAsTree
683              
684             or unpack the distro, and then either:
685              
686             perl Build.PL
687             ./Build
688             ./Build test
689             sudo ./Build install
690              
691             or:
692              
693             perl Makefile.PL
694             make (or dmake or nmake)
695             make test
696             make install
697              
698             =head1 Constructor and Initialization
699              
700             C is called as C<< my($g2m) = Data::RenderAsTree -> new(k1 => v1, k2 => v2, ...) >>.
701              
702             It returns a new object of type C.
703              
704             Key-value pairs accepted in the parameter list (see corresponding methods for details
705             [e.g. L]):
706              
707             =over 4
708              
709             =item o attributes => $Boolean
710              
711             This is a debugging aid. When set to 1, metadata attached to each tree node is included in the
712             output.
713              
714             Default: 0.
715              
716             =item o clean_nodes => $Boolean
717              
718             Clean up nodes before printing, by changing the node's name to '' (the empty string) if it's undef,
719             and by changing to '' any node attribute value which is undef.
720              
721             Set to 1 to activate option.
722              
723             Default: 0.
724              
725             =item o max_key_length => $int
726              
727             Use this to limit the lengths of hash keys.
728              
729             Default: 10_000.
730              
731             =item o max_value_length => $int
732              
733             Use this to limit the lengths of hash values.
734              
735             Default: 10_000.
736              
737             =item o title => $s
738              
739             Use this to set the name of the root node in the tree.
740              
741             Default: 'Root'.
742              
743             =back
744              
745             =head1 Methods
746              
747             =head2 attributes([$Boolean])
748              
749             Here, the [] indicate an optional parameter.
750              
751             Gets or sets the attributes option.
752              
753             Note: The value passed to L's C method is (1 - $Boolean).
754              
755             C is a parameter to L.
756              
757             =head2 clean_nodes([$Boolean])
758              
759             Gets or sets the value of the C option.
760              
761             This stops undef warnings when printing (i.e. when calling the tree's tree2string() method).
762              
763             Values:
764              
765             =over 4
766              
767             =item o 0
768              
769             Do not clean up nodes.
770              
771             =item o 1
772              
773             Clean up nodes by doing both these:
774              
775             =over 4
776              
777             =item o The node's name
778              
779             Change the node's name to '' (the empty string) if it's undef.
780              
781             =item o The node's attribute values
782              
783             Change to '' any node attribute value which is undef.
784              
785             =back
786              
787             =back
788              
789             =head2 max_key_length([$int])
790              
791             Here, the [] indicate an optional parameter.
792              
793             Gets or sets the maximum string length displayed for hash keys.
794              
795             C is a parameter to L.
796              
797             =head2 max_key_length([$int])
798              
799             Here, the [] indicate an optional parameter.
800              
801             Gets or sets the maximum string length displayed for hash values.
802              
803             C is a parameter to L.
804              
805             =head2 new()
806              
807             See L for details on the parameters accepted by L.
808              
809             =head2 process_tree()
810              
811             Just before L returns, it calls C, while walks the tree and adjusts
812             various bits of data attached to each node in the tree.
813              
814             If sub-classing this module, e.g. to change the precise text displayed, I recommend concentrating
815             your efforts on this method.
816              
817             Also, see the answer to the first question in the L.
818              
819             =head2 render($s)
820              
821             Renders $s into an object of type L.
822              
823             Returns an arrayref after calling the C method for L.
824              
825             See L for a typical usage.
826              
827             See also L, which returns the root of the tree.
828              
829             The choice of calling C or C is discussed in the L.
830              
831             =head2 root()
832              
833             Returns the root node in the tree, which is an object of type L.
834              
835             =head2 run($s)
836              
837             Renders $s into an object of type L.
838              
839             Returns the root of the tree.
840              
841             See also L, which returns an arrayref of the tree's data.
842              
843             The choice of calling C or C is discussed in the L.
844              
845             =head2 title([$s])
846              
847             Here, the [] indicate an optional parameter.
848              
849             Gets or sets the title, which is the name of the root node in the tree.
850              
851             C is a parameter to L</new()>. </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"> =head2 verbose([$Boolean]) </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"> Here, the [] indicate an optional parameter. </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"> 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="858">858</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="859">859</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="860">860</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="861">861</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="862">862</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="863">863</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="864">864</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="865">865</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="866">866</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Sure. Just call L</render($s)> and then L</root($s)> to get the root of the tree, and process it </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"> any way you wish. </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"> Otherwise, call L</root($s)>, which returns the root directly. </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"> See the next question for help in choosing between C<render()> and C<root()>. </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"> 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="874">874</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="875">875</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="876">876</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head2 How do I choose between calling C<render()> and C<root()>? </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">   </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"> L</render($s)> automatically calls L<Tree::DAG_Node>'s C<tree2string()> method, which you may not </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"> want. </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"> For instance, the tree might have undef as the name of node, or the value of an attribute, so that </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"> calling C<tree2string()> triggers undefined variable warnings when converting the node's attributes </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"> to a string. </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"> With L</run($s)>, since C<tree2string()> is not called, you have time to process the tree yourself, </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"> cleaning up the nodes, before converting it to an arrayref of strings by calling C<tree2string()> </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"> directly. Indeed, with C<run()> you may never call C<tree2string()> at all. </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">   </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"> Users of L<Marpa::R2> would normally call L</run($s)>. See L<MarpaX::Languages::Lua::Parser> for </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"> sample code, where node names of undef are the reason for this choice. </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"> =head2 What are the attributes of the tree nodes? </td> </tr> <tr> <td class="h" > <a name="893">893</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="894">894</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="895">895</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="896">896</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="897">897</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="898">898</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="899">899</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="900">900</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="901">901</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="902">902</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="903">903</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="904">904</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="905">905</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="906">906</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="907">907</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="908">908</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="909">909</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="910">910</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="911">911</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="912">912</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="913">913</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="914">914</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="915">915</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="916">916</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="917">917</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="918">918</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="919">919</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="920">920</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="921">921</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="922">922</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="923">923</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="924">924</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="925">925</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="926">926</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="927">927</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="928">928</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="929">929</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="930">930</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="931">931</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="932">932</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="933">933</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="934">934</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="935">935</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="936">936</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="937">937</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="938">938</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="939">939</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="940">940</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="941">941</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="942">942</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="943">943</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="944">944</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="945">945</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="946">946</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="947">947</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="948">948</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="949">949</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="950">950</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="951">951</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="952">952</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="953">953</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="954">954</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="955">955</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="956">956</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="957">957</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="958">958</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="959">959</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="960">960</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="961">961</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="962">962</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="963">963</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="964">964</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="965">965</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="966">966</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="967">967</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="968">968</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="969">969</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="970">970</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="971">971</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="972">972</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="973">973</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="974">974</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="975">975</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="976">976</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="977">977</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="978">978</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="979">979</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="980">980</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="981">981</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="982">982</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="983">983</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="984">984</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="985">985</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="986">986</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="987">987</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="988">988</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="989">989</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="990">990</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="991">991</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="992">992</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="993">993</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="994">994</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="995">995</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="996">996</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="997">997</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="998">998</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="999">999</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 </td> </tr> <tr> <td class="h" > <a name="1000">1000</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> a 2, if they pointed to arrayrefs. </td> </tr> <tr> <td class="h" > <a name="1001">1001</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="1002">1002</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="1003">1003</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="1004">1004</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="1005">1005</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="1006">1006</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="1007">1007</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="1008">1008</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="1009">1009</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="1010">1010</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="1011">1011</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="1012">1012</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="1013">1013</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="1014">1014</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="1015">1015</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="1016">1016</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="1017">1017</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="1018">1018</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="1019">1019</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="1020">1020</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="1021">1021</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="1022">1022</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="1023">1023</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="1024">1024</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="1025">1025</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="1026">1026</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="1027">1027</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="1028">1028</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="1029">1029</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="1030">1030</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="1031">1031</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="1032">1032</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="1033">1033</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="1034">1034</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="1035">1035</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="1036">1036</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="1037">1037</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="1038">1038</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="1039">1039</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="1040">1040</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="1041">1041</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="1042">1042</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="1043">1043</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="1044">1044</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="1045">1045</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="1046">1046</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="1047">1047</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="1048">1048</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="1049">1049</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="1050">1050</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =cut </td> </tr> </table> </body> </html>