line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Tree::Easy; |
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
71216
|
use warnings; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
64
|
|
4
|
2
|
|
|
2
|
|
10
|
use strict; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
74
|
|
5
|
|
|
|
|
|
|
|
6
|
2
|
|
|
2
|
|
11
|
use Scalar::Util qw(refaddr); |
|
2
|
|
|
|
|
9
|
|
|
2
|
|
|
|
|
268
|
|
7
|
2
|
|
|
2
|
|
11
|
use List::Util qw(max); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
230
|
|
8
|
2
|
|
|
2
|
|
11
|
use Carp qw(croak carp); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
5998
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our $VERSION = '0.01'; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
my $_DUMPER_IS_LOADED = 0; # for dump method |
13
|
|
|
|
|
|
|
my %_NODE_DATA; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub new |
16
|
|
|
|
|
|
|
{ |
17
|
6
|
|
|
6
|
1
|
21
|
my $class = shift; |
18
|
6
|
|
|
|
|
16
|
my $self = bless [ ], $class; |
19
|
|
|
|
|
|
|
|
20
|
6
|
|
|
|
|
9
|
my $data = shift; |
21
|
6
|
50
|
|
|
|
16
|
if ( defined $data ) { |
22
|
6
|
|
|
|
|
23
|
$_NODE_DATA{ refaddr($self) } = $data; |
23
|
|
|
|
|
|
|
} |
24
|
6
|
|
|
|
|
20
|
return $self; |
25
|
|
|
|
|
|
|
} |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
sub clone |
28
|
|
|
|
|
|
|
{ |
29
|
4
|
|
|
4
|
1
|
6
|
my $self = shift; |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# Make a shallow copy of any data references... |
32
|
4
|
|
|
|
|
11
|
my $data = $self->data; |
33
|
4
|
50
|
|
|
|
19
|
my $new_data = ( ! ref $data ? $data : |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
34
|
|
|
|
|
|
|
ref $data eq 'ARRAY' ? [ @$data ] : |
35
|
|
|
|
|
|
|
ref $data eq 'HASH' ? { %$data } : |
36
|
|
|
|
|
|
|
die sprintf qq{Internal error, don't know how to clone data reference\n}. |
37
|
|
|
|
|
|
|
q{of type "%s"}, ref $data ); |
38
|
|
|
|
|
|
|
|
39
|
4
|
|
|
|
|
10
|
my $new_root = __PACKAGE__->new($new_data); |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
# Recursively clone any descendants... |
42
|
4
|
|
|
|
|
8
|
for my $child ( @$self ) { |
43
|
2
|
|
|
|
|
7
|
$new_root->push_node($child->clone); |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
|
46
|
4
|
|
|
|
|
24
|
return $new_root; |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
sub DESTROY { |
50
|
6
|
|
|
6
|
|
228
|
my $self = shift; |
51
|
6
|
|
|
|
|
9
|
my $key = refaddr($self); |
52
|
6
|
|
|
|
|
121
|
delete $_NODE_DATA{$key}; |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
sub data |
56
|
|
|
|
|
|
|
{ |
57
|
18
|
|
|
18
|
1
|
45
|
my ($self, $data) = @_; |
58
|
|
|
|
|
|
|
|
59
|
18
|
|
|
|
|
37
|
my $key = refaddr($self); |
60
|
18
|
100
|
|
|
|
30
|
if ( defined $data ) { |
61
|
1
|
|
|
|
|
3
|
$_NODE_DATA{$key} = $data; |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
18
|
|
|
|
|
89
|
return $_NODE_DATA{$key}; |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
sub insert_node |
68
|
|
|
|
|
|
|
{ |
69
|
3
|
50
|
|
3
|
1
|
10
|
croak 'Invalid use of invoke_child method, not enough arguments' |
70
|
|
|
|
|
|
|
if ( @_ < 2 ); |
71
|
3
|
|
|
|
|
5
|
my ($self, $child, $where) = @_; |
72
|
|
|
|
|
|
|
|
73
|
3
|
50
|
|
|
|
20
|
croak 'Child parameter must be a Tree::Easy object' |
74
|
|
|
|
|
|
|
unless ( $child->isa('Tree::Easy') ); |
75
|
|
|
|
|
|
|
|
76
|
3
|
50
|
33
|
|
|
10
|
croak '$where parameter must be numeric' |
77
|
|
|
|
|
|
|
if ( defined $where && $where !~ /^-?\d$/ ); |
78
|
|
|
|
|
|
|
|
79
|
3
|
50
|
33
|
|
|
11
|
if ( ! defined $where || $where > $#$self ) { |
80
|
3
|
50
|
33
|
|
|
10
|
carp '$where parameter is past end of children' |
81
|
|
|
|
|
|
|
if ( defined $where && $where > $#$self ); |
82
|
3
|
|
|
|
|
5
|
push @{$self}, $child; |
|
3
|
|
|
|
|
7
|
|
83
|
3
|
|
|
|
|
13
|
return $child; |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
0
|
0
|
|
|
|
0
|
if ( $where < 0 ) { |
87
|
0
|
|
|
|
|
0
|
carp '$where parameter should not negative!'; |
88
|
0
|
|
|
|
|
0
|
$where = 0; |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
0
|
|
|
|
|
0
|
splice @{$self}, $where, 0, $child; |
|
0
|
|
|
|
|
0
|
|
92
|
0
|
|
|
|
|
0
|
return $child; |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
sub push_node |
96
|
|
|
|
|
|
|
{ |
97
|
3
|
|
|
3
|
1
|
10
|
return $_[0]->insert_node( $_[1] ); |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
sub unshift_node |
101
|
|
|
|
|
|
|
{ |
102
|
0
|
|
|
0
|
1
|
0
|
return $_[0]->insert_node( $_[1], 0 ); |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
sub push_new |
106
|
|
|
|
|
|
|
{ |
107
|
1
|
|
|
1
|
1
|
2
|
my $self = shift; |
108
|
1
|
|
|
|
|
5
|
return $self->push_node( __PACKAGE__->new(@_) ); |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
sub unshift_new |
112
|
|
|
|
|
|
|
{ |
113
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
114
|
0
|
|
|
|
|
0
|
return $self->unshift_node( __PACKAGE__->new(@_) ); |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
sub npush |
118
|
|
|
|
|
|
|
{ |
119
|
1
|
|
|
1
|
1
|
2
|
my $self = shift; |
120
|
1
|
|
|
|
|
3
|
my @new_nodes; |
121
|
|
|
|
|
|
|
|
122
|
1
|
|
|
|
|
3
|
for my $arg ( @_ ) { |
123
|
1
|
50
|
|
|
|
2
|
push @new_nodes, ( eval { $arg->isa(__PACKAGE__) } |
|
1
|
|
|
|
|
15
|
|
124
|
|
|
|
|
|
|
? $self->push_node($arg) |
125
|
|
|
|
|
|
|
: $self->push_new($arg) ); |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
1
|
|
|
|
|
14
|
return @new_nodes; |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
sub nunshift |
132
|
|
|
|
|
|
|
{ |
133
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
134
|
0
|
|
|
|
|
0
|
my @new_nodes; |
135
|
|
|
|
|
|
|
|
136
|
0
|
|
|
|
|
0
|
for my $arg ( @_ ) { |
137
|
0
|
0
|
|
|
|
0
|
push @new_nodes, ( eval { $arg->isa(__PACKAGE__) } |
|
0
|
|
|
|
|
0
|
|
138
|
|
|
|
|
|
|
? $self->unshift_node($arg) |
139
|
|
|
|
|
|
|
: $self->unshift_new($arg) ); |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
0
|
|
|
|
|
0
|
return @new_nodes; |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
sub remove_node |
146
|
|
|
|
|
|
|
{ |
147
|
0
|
0
|
|
0
|
1
|
0
|
croak 'Invalid use of remove_node method, not enough parameters' |
148
|
|
|
|
|
|
|
if ( @_ < 2 ); |
149
|
0
|
|
|
|
|
0
|
my ($self, $where) = @_; |
150
|
|
|
|
|
|
|
|
151
|
0
|
0
|
|
|
|
0
|
croak qq{Invalid \$where parameter ($where)...\nmust be a numeric index} |
152
|
|
|
|
|
|
|
unless ( $where =~ /\A \d+ \z/xms ); |
153
|
|
|
|
|
|
|
|
154
|
0
|
0
|
0
|
|
|
0
|
croak qq{Invalid \$where parameter ($where)...\noutside of range} |
|
|
|
0
|
|
|
|
|
155
|
|
|
|
|
|
|
if ( ( $where < 0 && $where*-1 > $#$self ) || $where > $#$self ); |
156
|
|
|
|
|
|
|
|
157
|
0
|
|
|
|
|
0
|
return splice @$self, $where, 1; |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
sub pop_node |
161
|
|
|
|
|
|
|
{ |
162
|
0
|
|
|
0
|
1
|
0
|
return $_[0]->remove_node( -1 ); |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub shift_node |
166
|
|
|
|
|
|
|
{ |
167
|
0
|
|
|
0
|
1
|
0
|
return $_[0]->remove_node( 0 ); |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
sub traverse |
171
|
|
|
|
|
|
|
{ |
172
|
1
|
50
|
|
1
|
1
|
5
|
croak 'Invalid use of traverse method, not enough arguments' |
173
|
|
|
|
|
|
|
if ( @_ < 2 ); |
174
|
1
|
|
|
|
|
2
|
my ($self, $code_ref, $how) = @_; |
175
|
|
|
|
|
|
|
|
176
|
1
|
50
|
|
|
|
4
|
$how = 0 unless ( defined $how ); |
177
|
|
|
|
|
|
|
|
178
|
1
|
50
|
33
|
|
|
544
|
croak "\$how parameter is invalid ($how) |
|
|
|
33
|
|
|
|
|
179
|
|
|
|
|
|
|
must be -1, 0, or 1 for prefix, infix (default)), or postfix" |
180
|
|
|
|
|
|
|
unless ( $how eq '-1' || $how eq '0' || $how eq '1' ); |
181
|
|
|
|
|
|
|
|
182
|
1
|
|
|
|
|
1
|
my $traverser_ref; |
183
|
|
|
|
|
|
|
$traverser_ref = |
184
|
|
|
|
|
|
|
( $how == 0 ? sub { # infix |
185
|
2
|
|
|
2
|
|
2
|
my $node = shift; |
186
|
|
|
|
|
|
|
|
187
|
2
|
100
|
|
|
|
6
|
if ( @$node == 0 ) { |
188
|
1
|
|
|
|
|
3
|
$code_ref->($node); |
189
|
1
|
|
|
|
|
2
|
return; |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
|
192
|
1
|
50
|
|
|
|
3
|
if ( @$node == 1 ) { |
193
|
|
|
|
|
|
|
# Treat one node like it's on the left... |
194
|
1
|
|
|
|
|
4
|
$traverser_ref->($node->[0]); |
195
|
1
|
|
|
|
|
2
|
$code_ref->($node); |
196
|
1
|
|
|
|
|
2
|
return; |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
|
199
|
0
|
|
|
|
|
0
|
my $mid = int( $#$node / 2 ); |
200
|
0
|
|
|
|
|
0
|
my $odd_kids = @$node % 2; |
201
|
|
|
|
|
|
|
|
202
|
0
|
0
|
|
|
|
0
|
if ( $odd_kids ) { --$mid; } |
|
0
|
|
|
|
|
0
|
|
203
|
|
|
|
|
|
|
|
204
|
0
|
|
|
|
|
0
|
for my $i ( 0 .. $mid ) { |
205
|
0
|
|
|
|
|
0
|
$traverser_ref->($node->[$i]); |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# if ( $odd_kids ) { |
209
|
|
|
|
|
|
|
# $traverser_ref->($node->[++$mid]); |
210
|
|
|
|
|
|
|
# } |
211
|
|
|
|
|
|
|
|
212
|
0
|
|
|
|
|
0
|
$code_ref->($node); |
213
|
|
|
|
|
|
|
|
214
|
0
|
|
|
|
|
0
|
for my $i ( ++$mid .. $#$node ) { |
215
|
0
|
|
|
|
|
0
|
$traverser_ref->($node->[$i]); |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
} : |
218
|
|
|
|
|
|
|
$how == -1 ? sub { # preorder |
219
|
0
|
|
|
0
|
|
0
|
my $node = shift; |
220
|
|
|
|
|
|
|
|
221
|
0
|
|
|
|
|
0
|
$code_ref->($node); |
222
|
|
|
|
|
|
|
|
223
|
0
|
|
|
|
|
0
|
for my $i ( 0 .. $#$node ) { |
224
|
0
|
|
|
|
|
0
|
$traverser_ref->($node->[$i]); |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
} : |
227
|
|
|
|
|
|
|
$how == 1 ? sub { # postorder |
228
|
0
|
|
|
0
|
|
0
|
my $node = shift; |
229
|
|
|
|
|
|
|
|
230
|
0
|
|
|
|
|
0
|
for my $i ( 0 .. $#$node ) { |
231
|
0
|
|
|
|
|
0
|
$traverser_ref->($node->[$i]); |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
|
234
|
0
|
|
|
|
|
0
|
$code_ref->($node); |
235
|
|
|
|
|
|
|
} : |
236
|
1
|
0
|
|
|
|
8
|
die 'Internal error' |
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
237
|
|
|
|
|
|
|
); |
238
|
|
|
|
|
|
|
|
239
|
1
|
|
|
|
|
3
|
$traverser_ref->($self); |
240
|
1
|
|
|
|
|
2
|
return; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
sub search |
244
|
|
|
|
|
|
|
{ |
245
|
4
|
50
|
|
4
|
1
|
10
|
croak 'Invalid use of search method, not enough arguments' |
246
|
|
|
|
|
|
|
if ( @_ < 2 ); |
247
|
4
|
|
|
|
|
9
|
my ($self, $match, $how) = @_; |
248
|
|
|
|
|
|
|
|
249
|
4
|
50
|
|
|
|
10
|
$how = 'dfs' unless ( defined $how ); |
250
|
4
|
|
|
|
|
7
|
$how = lc $how; |
251
|
|
|
|
|
|
|
|
252
|
4
|
50
|
33
|
|
|
10
|
croak qq{\$how parameter is invalid ($how) |
253
|
|
|
|
|
|
|
must be 'dfs' or 'bfs' for depth-first or breadth-first search} |
254
|
|
|
|
|
|
|
if ( $how ne 'dfs' && $how ne 'bfs' ); |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
my $matcher_ref = |
257
|
|
|
|
|
|
|
( ref $match eq 'CODE' ? $match |
258
|
|
|
|
|
|
|
: sub { |
259
|
2
|
|
|
2
|
|
2
|
my $node = shift; |
260
|
2
|
|
|
|
|
3
|
return $node->data eq $match; |
261
|
4
|
100
|
|
|
|
12
|
} ); |
262
|
|
|
|
|
|
|
|
263
|
4
|
|
|
|
|
4
|
my $searcher_ref; |
264
|
|
|
|
|
|
|
$searcher_ref = |
265
|
|
|
|
|
|
|
( $how eq 'dfs' ? |
266
|
|
|
|
|
|
|
sub { |
267
|
8
|
|
|
8
|
|
7
|
my $node = shift; |
268
|
8
|
100
|
|
|
|
49
|
return $node if ( $matcher_ref->($node) ); |
269
|
5
|
|
|
|
|
9
|
for my $child ( @$node ) { |
270
|
4
|
|
|
|
|
13
|
return $searcher_ref->($child); |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
return undef |
273
|
1
|
|
|
|
|
6
|
} |
274
|
|
|
|
|
|
|
: |
275
|
|
|
|
|
|
|
$how eq 'bfs' ? |
276
|
|
|
|
|
|
|
sub { |
277
|
0
|
|
|
0
|
|
0
|
my $node = shift; |
278
|
0
|
0
|
|
|
|
0
|
return $node if ( $matcher_ref->($node) ); |
279
|
0
|
|
|
|
|
0
|
for my $child ( @$node ) { |
280
|
0
|
0
|
|
|
|
0
|
return $child if ( $matcher_ref->($child) ); |
281
|
|
|
|
|
|
|
} |
282
|
0
|
|
|
|
|
0
|
for my $child ( @$node ) { |
283
|
0
|
|
|
|
|
0
|
return $searcher_ref->($child); |
284
|
|
|
|
|
|
|
} |
285
|
0
|
|
|
|
|
0
|
return undef; |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
: |
288
|
4
|
0
|
|
|
|
16
|
die 'Internal error' |
|
|
50
|
|
|
|
|
|
289
|
|
|
|
|
|
|
); |
290
|
|
|
|
|
|
|
|
291
|
4
|
|
|
|
|
9
|
return $searcher_ref->($self); |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
sub get_height |
295
|
|
|
|
|
|
|
{ |
296
|
2
|
|
|
2
|
1
|
2
|
my $self = shift; |
297
|
|
|
|
|
|
|
|
298
|
1
|
|
|
|
|
4
|
return 1 + ( @$self == 0 ? 0 : |
299
|
2
|
100
|
|
|
|
15
|
max map { $_->get_height } @$self ); |
300
|
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
sub dump_node_data |
303
|
|
|
|
|
|
|
{ |
304
|
0
|
|
|
0
|
1
|
|
my $node = shift; |
305
|
|
|
|
|
|
|
|
306
|
0
|
|
|
|
|
|
my $data = $node->data; |
307
|
0
|
0
|
|
|
|
|
return 'undef' unless ( defined $data ); |
308
|
|
|
|
|
|
|
|
309
|
0
|
|
|
|
|
|
my $reftype = ref $data; |
310
|
|
|
|
|
|
|
return ( ! $reftype ? $data : |
311
|
0
|
0
|
|
|
|
|
do { |
312
|
0
|
0
|
|
|
|
|
unless ( $_DUMPER_IS_LOADED ) { |
313
|
0
|
|
|
|
|
|
require Data::Dumper; |
314
|
0
|
|
|
|
|
|
$Data::Dumper::Indent = 0; |
315
|
0
|
|
|
|
|
|
$Data::Dumper::Terse = 1; |
316
|
0
|
|
|
|
|
|
$_DUMPER_IS_LOADED = 1; |
317
|
|
|
|
|
|
|
} |
318
|
0
|
|
|
|
|
|
Data::Dumper::Dumper($data); |
319
|
|
|
|
|
|
|
} ); |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
sub dumper |
323
|
|
|
|
|
|
|
{ |
324
|
0
|
|
|
0
|
1
|
|
my ($self, $file_handle, $col_limit) = @_; |
325
|
|
|
|
|
|
|
|
326
|
0
|
0
|
|
|
|
|
$file_handle = \*STDOUT unless ( defined $file_handle ); |
327
|
0
|
0
|
|
|
|
|
$col_limit = 78 unless ( defined $col_limit ); |
328
|
|
|
|
|
|
|
|
329
|
0
|
0
|
|
|
|
|
croak "\$col_limit parameter ($col_limit) is invalid, must be numeric and positive" |
330
|
|
|
|
|
|
|
if ( $col_limit !~ /\A \d+ \z/xms ); |
331
|
|
|
|
|
|
|
|
332
|
0
|
|
|
|
|
|
require Text::Wrap; |
333
|
|
|
|
|
|
|
|
334
|
0
|
|
|
|
|
|
my $dumper_ref; |
335
|
|
|
|
|
|
|
$dumper_ref = sub { |
336
|
0
|
|
|
0
|
|
|
my ($node, $depth_counts) = @_; |
337
|
|
|
|
|
|
|
|
338
|
0
|
|
|
|
|
|
my $node_text = $node->dump_node_data; |
339
|
0
|
|
|
|
|
|
my $prefix = ''; |
340
|
|
|
|
|
|
|
|
341
|
0
|
0
|
|
|
|
|
if ( @$depth_counts ) { |
342
|
|
|
|
|
|
|
# If there are no more items in a depth above us, they |
343
|
|
|
|
|
|
|
# won't need a line to represent their branch. |
344
|
0
|
|
|
|
|
|
for my $i ( 0 .. $#$depth_counts-1 ) { |
345
|
0
|
|
|
|
|
|
my $nodes_on_depth = $depth_counts->[$i]; |
346
|
0
|
0
|
|
|
|
|
$prefix .= ( $nodes_on_depth > 0 ? '| ' : ' ' ); |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
# If this is the last item, make a curved "twig". |
350
|
0
|
|
|
|
|
|
my $more_siblings = --$depth_counts->[-1]; |
351
|
0
|
0
|
|
|
|
|
$prefix .= ( $more_siblings ? '|-- ' : '`-- ' ); |
352
|
|
|
|
|
|
|
} |
353
|
|
|
|
|
|
|
|
354
|
0
|
|
|
|
|
|
print $file_handle Text::Wrap::wrap( $prefix, ' ' x length($prefix), "$node_text\n" ); |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
# Recurse through the the children nodes... |
357
|
0
|
|
|
|
|
|
my $child_count = @$node; |
358
|
0
|
|
|
|
|
|
for my $child ( @$node ) { |
359
|
0
|
|
|
|
|
|
$dumper_ref->( $child, |
360
|
|
|
|
|
|
|
[ @$depth_counts, |
361
|
|
|
|
|
|
|
$child_count-- ] ); |
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
|
364
|
0
|
|
|
|
|
|
return; |
365
|
0
|
|
|
|
|
|
}; |
366
|
|
|
|
|
|
|
|
367
|
0
|
|
|
|
|
|
$dumper_ref->( $self, [ ] ); |
368
|
0
|
|
|
|
|
|
return; |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
1; |