File Coverage

blib/lib/Data/RenderAsTree.pm
Criterion Covered Total %
statement 141 181 77.9
branch 64 104 61.5
condition 19 29 65.5
subroutine 17 19 89.4
pod 3 5 60.0
total 244 338 72.1


line stmt bran cond sub pod time code
1             package Data::RenderAsTree;
2              
3 7     7   4234 use strict;
  7         10  
  7         149  
4 7     7   26 use warnings;
  7         11  
  7         254  
5              
6 7     7   5617 use Moo;
  7         112095  
  7         41  
7              
8 7     7   10819 use Scalar::Util qw/blessed reftype/;
  7         12  
  7         679  
9              
10 7     7   6535 use Set::Array;
  7         116701  
  7         240  
11              
12 7     7   5333 use Text::Truncate; # For truncstr().
  7         3061  
  7         324  
13              
14 7     7   8104 use Tree::DAG_Node;
  7         193167  
  7         304  
15              
16 7     7   6676 use Types::Standard qw/Any Bool Int Object Str/;
  7         464827  
  7         95  
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.03';
99              
100             # ------------------------------------------------
101              
102             sub BUILD
103             {
104 7     7 0 258 my($self) = @_;
105 7         39 my($key_length) = $self -> max_key_length;
106 7         4114 my($value_length) = $self -> max_value_length;
107              
108 7 50 33     4180 $self -> max_key_length(30) if ( ($key_length < 1) || ($key_length > 10_000) );
109 7 50 33     197 $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 124     124   209 my($self, $name, $attributes) = @_;
118              
119 124 50       2279 print "Entered _add_daughter($name, $attributes)\n" if ($self -> verbose);
120              
121 124 50       741 $attributes = {} if (! $attributes);
122 124         236 $$attributes{name} = $name;
123 124         2286 $$attributes{uid} = $self -> uid($self -> uid + 1);
124 124         5657 $name = truncstr($name, $self -> max_key_length);
125 124         1808 my($node) = Tree::DAG_Node -> new({name => $name, attributes => $attributes});
126 124         6328 my($tos) = $self -> node_stack -> length - 1;
127              
128 124 50       5989 die "Stack is empty\n" if ($tos < 0);
129              
130 124         137 ${$self -> node_stack}[$tos] -> add_daughter($node);
  124         2385  
131              
132 124         7369 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   56 my($self, $value) = @_;
194              
195 19 50       368 print "Entered _process_arrayref($value)\n" if ($self -> verbose);
196              
197 19         1517 my($index) = $self -> index_stack -> last;
198 19         913 my($parent) = $self -> _process_scalar("$index = []", 'ARRAY');
199              
200 19         392 $self -> node_stack -> push($parent);
201              
202 19         910 $index = -1;
203              
204 19         25 my($bless_type);
205             my($node);
206 0         0 my($ref_type);
207              
208 19         72 for my $item (@$value)
209             {
210 37         45 $index++;
211              
212 37   50     154 $bless_type = blessed($item) || '';
213 37   100     179 $ref_type = reftype($item) || 'VALUE';
214              
215 37 50       66 if ($bless_type)
216             {
217 0         0 $self -> node_stack -> push($self -> _process_scalar("Class = $bless_type", 'BLESS') );
218             }
219              
220 37 100       110 if ($ref_type eq 'ARRAY')
    100          
    50          
221             {
222 7         134 $self -> index_stack -> push($index);
223 7         364 $self -> _process_arrayref($item);
224              
225 7         440 $index = $self -> index_stack -> pop;
226             }
227             elsif ($ref_type eq 'HASH')
228             {
229 4         11 $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       555 $self -> _process_scalar("$index = " . (defined($item) ? truncstr($item, $self -> max_value_length) : 'undef') );
238             }
239              
240 37 50       676 $node = $self -> node_stack -> pop if ($bless_type);
241             }
242              
243 19         373 $node = $self -> node_stack -> pop;
244              
245             } # End of _process_arrayref;
246              
247             # ------------------------------------------------
248              
249             sub _process_hashref
250             {
251 27     27   59 my($self, $data) = @_;
252 27         34 my($index) = -1;
253              
254 27 50       518 print "Entered _process_hashref($data)\n" if ($self -> verbose);
255              
256 27         768 my($parent) = $self -> _process_scalar('{}', 'HASH');
257              
258 27         529 $self -> node_stack -> push($parent);
259              
260 27         1312 my($bless_type);
261             my($node);
262 0         0 my($ref_type);
263 0         0 my($value);
264              
265 27         113 for my $key (sort keys %$data)
266             {
267 46         177 $index++;
268              
269 46         76 $value = $$data{$key};
270 46   100     196 $bless_type = blessed($value) || '';
271 46   100     160 $ref_type = reftype($value) || 'VALUE';
272 46 100       111 $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         201 $node = $self -> _add_daughter
279             (
280             $key,
281             {type => $ref_type, use_value => 1, value => $value}
282             );
283              
284 46 100       102 if ($bless_type)
285             {
286 1         25 $self -> node_stack -> push($node);
287              
288 1         66 $node = $self -> _process_scalar("Class = $bless_type", 'BLESS');
289             }
290              
291 46         904 $self -> node_stack -> push($node);
292              
293 46 100       2648 if ($ref_type eq 'ARRAY')
    100          
    50          
294             {
295 4         81 $self -> index_stack -> push($index);
296 4         213 $self -> _process_arrayref($value);
297              
298 4         252 $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       74 if ($ref_type eq 'SCALAR')
305             {
306 1         6 $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         54 $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         1682 $node = $self -> node_stack -> pop;
323 46 100       2547 $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       184 $self -> node_stack -> push($self -> root) if ($node -> is_root);
329             }
330              
331 27         756 $self -> node_stack -> pop;
332              
333             } # End of _process_hashref.
334              
335             # ------------------------------------------------
336              
337             sub _process_scalar
338             {
339 77     77   444 my($self, $value, $type) = @_;
340 77   100     225 $type ||= 'SCALAR';
341              
342 77 50       1369 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 77         2825 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 23     23 1 38 my($self) = @_;
361              
362 23 50       438 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 23         141 my($attributes);
370 23         33 my($ignore_value, $id);
371 0         0 my($key);
372 0         0 my($name);
373 0         0 my($ref_type);
374 0         0 my($type);
375 0         0 my($uid, $use_value);
376 0         0 my($value);
377              
378             $self -> root -> walk_down
379             ({
380             callback => sub
381             {
382 147     147   3443 my($node, $opt) = @_;
383              
384             # Ignore the root, and keep walking.
385              
386 147 100       465 return 1 if ($node -> is_root);
387              
388 124         1200 $name = $node -> name;
389 124         701 $attributes = $node -> attributes;
390 124         568 $type = $$attributes{type};
391 124 50       447 $ref_type = ($type =~ /^(\w+)/) ? $1 : $type; # Ignores '(0x12345678)'.
392 124         172 $uid = $$attributes{uid};
393 124         154 $use_value = $$attributes{use_value};
394 124         159 $value = $$attributes{value};
395 124         211 $key = "$ref_type $uid";
396              
397 124 50 66     657 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 32         45 $id = $key;
413 32 50       60 $name = defined($name) ? $name : 'undef';
414 32 100       679 $name .= ' = ' . truncstr(defined($value) ? $value : 'undef', $self -> max_value_length) if ($use_value);
    100          
415             }
416             elsif ($ref_type eq 'SCALAR')
417             {
418 29         37 $id = $key;
419 29 50       50 $name = defined($name) ? $name : 'undef';
420 29 50       103 $name .= ' = ' . truncstr(defined($value) ? $value : 'undef', $self -> max_value_length) if ($use_value);
    100          
421             }
422             else
423             {
424 63         87 $id = $key;
425             }
426              
427 124         801 $node -> name("$name [$id]");
428              
429 124 100 66     926 $$opt{seen}{$value} = $id if (defined($value) && ! defined $$opt{seen}{$value});
430              
431             # Keep walking.
432              
433 124         258 return 1;
434             },
435 23         463 _depth => 0,
436             seen => {},
437             });
438              
439             } # End of process_tree.
440              
441             # ------------------------------------------------
442              
443             sub render
444             {
445 23     23 1 22204 my($self, $s) = @_;
446              
447 23         73 $self -> run($s);
448              
449 23         867 return $self -> root -> tree2string({no_attributes => 1 - $self -> attributes});
450              
451             } # End of render.
452              
453             # ------------------------------------------------
454              
455             sub run
456             {
457 23     23 1 39 my($self, $s) = @_;
458 23 100       88 $s = defined($s) ? $s : 'undef';
459              
460 23         431 $self -> root
461             (
462             Tree::DAG_Node -> new
463             ({
464             attributes => {type => '', uid => $self -> uid, value => ''},
465             name => $self -> title,
466             })
467             );
468 23         14190 $self -> node_stack -> push($self -> root);
469 23         6452 $self -> index_stack -> push(0);
470              
471 23   100     4998 my($bless_type) = blessed($s) || '';
472 23   100     107 my($ref_type) = reftype($s) || 'VALUE';
473              
474 23 100       57 if ($bless_type)
475             {
476 1         22 $self -> node_stack -> push($self -> _process_scalar("Class = $bless_type", 'BLESS') );
477             }
478              
479 23 100       196 if ($ref_type eq 'ARRAY')
    100          
    50          
480             {
481 8         25 $self -> _process_arrayref($s);
482             }
483             elsif ($ref_type eq 'HASH')
484             {
485 12         42 $self -> _process_hashref($s);
486             }
487             elsif ($ref_type =~ /REF|SCALAR|VALUE/)
488             {
489 3         16 $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 23         1035 $self -> process_tree;
497 23 50       1175 $self -> clean_tree if ($self -> clean_nodes);
498              
499             # Clean up in case user reuses this object.
500              
501 23         4698 $self -> node_stack -> pop;
502 23         1663 $self -> index_stack -> pop;
503 23 100       1092 $self -> node_stack -> pop if ($bless_type);
504 23         523 $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             my($sub) = sub {};
534             my($s) =
535             {
536             A =>
537             {
538             a => {},
539             bbbbbb => $sub,
540             c123 => $sub,
541             d => \$sub,
542             },
543             B => [qw(element_1 element_2 element_3)],
544             C =>
545             {
546             b =>
547             {
548             a =>
549             {
550             a => {},
551             b => sub {},
552             c => '429999999999999999999999999999999999999999999999',
553             }
554             }
555             },
556             DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD => 'd',
557             Object => Tree::DAG_Node -> new({name => 'A tree', attributes => {one => 1} }),
558             Ref2Scalar => \'A shortish string', # Use ' in comment for UltraEdit hiliting.
559             };
560             my($result) = Data::RenderAsTree -> new
561             (
562             attributes => 0,
563             max_key_length => 25,
564             max_value_length => 20,
565             title => 'Synopsis',
566             verbose => 0,
567             ) -> render($s);
568              
569             print join("\n", @$result), "\n";
570              
571             See the L for a discussion as to whether you should call L or L.
572              
573             This is the output of scripts/synopsis.pl:
574              
575             Synopsis
576             |--- {} [HASH 1]
577             |--- A = {} [HASH 2]
578             | |--- {} [HASH 3]
579             | |--- a = {} [HASH 4]
580             | | |--- {} [HASH 5]
581             | |--- bbbbbb = CODE(0x1c93e30) [CODE 6]
582             | |--- c123 [CODE 7 -> CODE 6]
583             | |--- d [REF 8 -> CODE 6]
584             |--- B [ARRAY 9]
585             | |--- 1 = [] [ARRAY 10]
586             | |--- 0 = element_1 [SCALAR 11]
587             | |--- 1 = element_2 [SCALAR 12]
588             | |--- 2 = element_3 [SCALAR 13]
589             |--- C = {} [HASH 14]
590             | |--- {} [HASH 15]
591             | |--- b = {} [HASH 16]
592             | |--- {} [HASH 17]
593             | |--- a = {} [HASH 18]
594             | |--- {} [HASH 19]
595             | |--- a = {} [HASH 20]
596             | | |--- {} [HASH 21]
597             | |--- b = CODE(0x2475c68) [CODE 22]
598             | |--- c = 42999999999999999... [VALUE 23]
599             |--- DDDDDDDDDDDDDDDDDDDDDD... = d [VALUE 24]
600             |--- Object = {} [HASH 25]
601             | |--- Class = Tree::DAG_Node [BLESS 26]
602             | |--- {} [HASH 27]
603             | |--- attributes = {} [HASH 28]
604             | | |--- {} [HASH 29]
605             | | |--- one = 1 [VALUE 30]
606             | |--- daughters [ARRAY 31]
607             | | |--- 1 = [] [ARRAY 32]
608             | |--- mother = undef [VALUE 33]
609             | |--- name = A tree [VALUE 34]
610             |--- Ref2Scalar = SCALAR(0x230a230) [SCALAR 35]
611             |--- SCALAR(0x230a230) = A shortish string [SCALAR 36]
612              
613             =head1 Description
614              
615             L provides a mechanism to display a Perl data structure.
616              
617             The data supplied to L is stored in an object of type L.
618              
619             C returns an arrayref by calling C's C method, so you can
620             just print the return value as a string by using code as in synopsis.pl above.
621              
622             It also means you can display as much or as little of the result as you wish, by printing a range
623             of array elements.
624              
625             Hash key lengths can be limited by L, and hash value lengths can be limited
626             by L.
627              
628             For sub-classing, see L.
629              
630             The module serves as a simple replacement for L, but without the huge set of
631             features.
632              
633             For sample code, see these programs in the scripts/ directory of the distro:
634              
635             =over 4
636              
637             =item o array.pl
638              
639             =item o bless.pl
640              
641             =item o hash.pl
642              
643             =item o mixup.pl
644              
645             =item o ref.pl
646              
647             =item o synopsis.pl
648              
649             =back
650              
651             See also the test files t/*.t, which are basically copies of the above. And that means, like the
652             *.pl above, all expected output is given in the source code.
653              
654             Lastly, see the L for details such as how to process the output tree yourself.
655              
656             =head1 Distributions
657              
658             This module is available as a Unix-style distro (*.tgz).
659              
660             See L
661             for help on unpacking and installing distros.
662              
663             =head1 Installation
664              
665             Install L as you would for any C module:
666              
667             Run:
668              
669             cpanm Data::RenderAsTree
670              
671             or run:
672              
673             sudo cpan Data::RenderAsTree
674              
675             or unpack the distro, and then either:
676              
677             perl Build.PL
678             ./Build
679             ./Build test
680             sudo ./Build install
681              
682             or:
683              
684             perl Makefile.PL
685             make (or dmake or nmake)
686             make test
687             make install
688              
689             =head1 Constructor and Initialization
690              
691             C is called as C<< my($g2m) = Data::RenderAsTree -> new(k1 => v1, k2 => v2, ...) >>.
692              
693             It returns a new object of type C.
694              
695             Key-value pairs accepted in the parameter list (see corresponding methods for details
696             [e.g. L]):
697              
698             =over 4
699              
700             =item o attributes => $Boolean
701              
702             This is a debugging aid. When set to 1, metadata attached to each tree node is included in the
703             output.
704              
705             Default: 0.
706              
707             =item o clean_nodes => $Boolean
708              
709             Clean up nodes before printing, by changing the node's name to '' (the empty string) if it's undef,
710             and by changing to '' any node attribute value which is undef.
711              
712             Set to 1 to activate option.
713              
714             Default: 0.
715              
716             =item o max_key_length => $int
717              
718             Use this to limit the lengths of hash keys.
719              
720             Default: 10_000.
721              
722             =item o max_value_length => $int
723              
724             Use this to limit the lengths of hash values.
725              
726             Default: 10_000.
727              
728             =item o title => $s
729              
730             Use this to set the name of the root node in the tree.
731              
732             Default: 'Root'.
733              
734             =back
735              
736             =head1 Methods
737              
738             =head2 attributes([$Boolean])
739              
740             Here, the [] indicate an optional parameter.
741              
742             Gets or sets the attributes option.
743              
744             Note: The value passed to L's C method is (1 - $Boolean).
745              
746             C is a parameter to L.
747              
748             =head2 clean_nodes([$Boolean])
749              
750             Gets or sets the value of the C option.
751              
752             This stops undef warnings when printing (i.e. when calling the tree's tree2string() method).
753              
754             Values:
755              
756             =over 4
757              
758             =item o 0
759              
760             Do not clean up nodes.
761              
762             =item o 1
763              
764             Clean up nodes by doing both these:
765              
766             =over 4
767              
768             =item o The node's name
769              
770             Change the node's name to '' (the empty string) if it's undef.
771              
772             =item o The node's attribute values
773              
774             Change to '' any node attribute value which is undef.
775              
776             =back
777              
778             =back
779              
780             =head2 max_key_length([$int])
781              
782             Here, the [] indicate an optional parameter.
783              
784             Gets or sets the maximum string length displayed for hash keys.
785              
786             C is a parameter to L.
787              
788             =head2 max_key_length([$int])
789              
790             Here, the [] indicate an optional parameter.
791              
792             Gets or sets the maximum string length displayed for hash values.
793              
794             C is a parameter to L.
795              
796             =head2 new()
797              
798             See L for details on the parameters accepted by L.
799              
800             =head2 process_tree()
801              
802             Just before L returns, it calls C, while walks the tree and adjusts
803             various bits of data attached to each node in the tree.
804              
805             If sub-classing this module, e.g. to change the precise text displayed, I recommend concentrating
806             your efforts on this method.
807              
808             Also, see the answer to the first question in the L.
809              
810             =head2 render($s)
811              
812             Renders $s into an object of type L.
813              
814             Returns an arrayref after calling the C method for L.
815              
816             See L for a typical usage.
817              
818             See also L, which returns the root of the tree.
819              
820             The choice of calling C or C is discussed in the L.
821              
822             =head2 root()
823              
824             Returns the root node in the tree, which is an object of type L.
825              
826             =head2 run($s)
827              
828             Renders $s into an object of type L.
829              
830             Returns the root of the tree.
831              
832             See also L, which returns an arrayref of the tree's data.
833              
834             The choice of calling C or C is discussed in the L.
835              
836             =head2 title([$s])
837              
838             Here, the [] indicate an optional parameter.
839              
840             Gets or sets the title, which is the name of the root node in the tree.
841              
842             C is a parameter to L</new()>. </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 verbose([$Boolean]) </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"> Here, the [] indicate an optional parameter. </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"> 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="849">849</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="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"> C<verbose> 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"> =head1 FAQ </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"> =head2 Can I process the tree myself? </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"> 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="858">858</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="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"> Otherwise, call L</root($s)>, which returns the root directly. </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"> See the next question for help in choosing between C<render()> and C<root()>. </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"> 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="865">865</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="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"> =head2 How do I choose between calling C<render()> and C<root()>? </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</render($s)> automatically calls L<Tree::DAG_Node>'s C<tree2string()> method, which you may not </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"> want. </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">   </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"> 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="873">873</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="874">874</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="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"> 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="877">877</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="878">878</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="879">879</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="880">880</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="881">881</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="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"> =head2 What are the attributes of the tree nodes? </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"> 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="886">886</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="887">887</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="888">888</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="889">889</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="890">890</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="891">891</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="892">892</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="893">893</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="894">894</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="895">895</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="896">896</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="897">897</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="898">898</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="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"> 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="901">901</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="902">902</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="903">903</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="904">904</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="905">905</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="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"> The value is an arrayref. </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"> =item o BLESS </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">   </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"> The value is blessed into a class, who name is in the value. </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">   </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"> =item o CODE </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">   </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"> The value is a coderef. </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">   </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"> =item o HASH </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">   </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"> The value is a hashref. </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">   </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"> =item o REF </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">   </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"> 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="924">924</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="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 SCALAR </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 scalarref. </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 VALUE </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 just a literal value. </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">   </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"> 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="935">935</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="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"> =back </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"> Other values returned by C<reftype()> are not used by this module. </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"> =item o uid => $integer </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"> Each node in the tree has a unique integer identifier, counting from 1 up. </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">   </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"> =item o use_value => $Boolean </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">   </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"> Node values (see next point) can be undef, and this flag serves the following purpose: </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">   </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"> =over </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">   </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"> =item o Zero </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">   </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"> 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="954">954</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="955">955</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="956">956</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="957">957</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="958">958</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="959">959</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="960">960</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="961">961</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="962">962</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="963">963</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="964">964</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="965">965</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="966">966</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="967">967</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="968">968</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="969">969</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="970">970</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="971">971</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="972">972</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="973">973</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="974">974</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="975">975</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="976">976</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="977">977</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="978">978</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="979">979</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="980">980</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="981">981</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="982">982</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="983">983</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="984">984</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="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"> Why is there a '1 = []' in there? </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"> Firstly, note that C<hash> keys are returned in sorted order. </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"> 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="991">991</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="992">992</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="993">993</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="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"> The major alternatives are L<String::Truncate> and L<Text::Elide>, or re-inventing the wheel. </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"> 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="998">998</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="999">999</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="1000">1000</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="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"> This matter is discussed in the notes for method L</process_tree()>. </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"> =head1 See Also </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"> L<Data::TreeDumper>. </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">   </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"> =head1 Machine-Readable Change Log </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">   </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"> The file Changes was converted into Changelog.ini by L<Module::Metadata::Changes>. </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">   </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"> =head1 Version Numbers </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">   </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"> Version numbers < 1.00 represent development versions. From 1.00 up, they are production versions. </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">   </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"> =head1 Repository </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">   </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"> L<https://github.com/ronsavage/Data-RenderAsTree> </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">   </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"> =head1 Support </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">   </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"> Email the author, or log a bug on RT: </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">   </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"> L<https://rt.cpan.org/Public/Dist/Display.html?Name=Data::RenderAsTree>. </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">   </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"> =head1 Author </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">   </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"> 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="1029">1029</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="1030">1030</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="1031">1031</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="1032">1032</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="1033">1033</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="1034">1034</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="1035">1035</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="1036">1036</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="1037">1037</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="1038">1038</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="1039">1039</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="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"> =cut </td> </tr> </table> </body> </html>