File Coverage

blib/lib/Tree/Compat/Tree/Simple.pm
Criterion Covered Total %
statement 187 193 96.8
branch 81 86 94.1
condition 22 24 91.6
subroutine 37 41 90.2
pod 0 30 0.0
total 327 374 87.4


line stmt bran cond sub pod time code
1             package Tree::Compat::Tree::Simple;
2              
3 6     6   25213 use strict;
  6         11  
  6         203  
4 6     6   31 use warnings;
  6         12  
  6         347  
5              
6             our $VERSION = '1.00';
7              
8             package Tree::Simple;
9              
10             # Set %INC so that require() thinks Tree::Simple has already been loaded
11             $INC{'Tree/Simple.pm'} = $INC{'Tree::Compat::Tree::Simple'};
12              
13 6     6   27 use strict;
  6         43  
  6         167  
14 6     6   28 use warnings;
  6         11  
  6         252  
15              
16 6     6   47 use Scalar::Util qw( blessed weaken );
  6         17  
  6         932  
17 6     6   5533 use Tree;
  6         52486  
  6         98  
18              
19 6     6   194 use constant ROOT => 'root';
  6         12  
  6         16081  
20              
21             sub new {
22 84     84 0 17948 my $class = shift;
23 84         127 my ($value, $parent) = @_;
24              
25 84         289 my $tree = Tree->new( $value );
26 84         3438 $tree->error_handler( $tree->DIE );
27              
28 84         1022 my $self = bless \$tree, $class;
29              
30 84         271 $tree->meta->{compat}{object} = $self;
31 84         593 weaken( $self );
32              
33 84         237 $self->_init( $value, $parent, [] );
34              
35 81         238 return $self;
36             }
37              
38 1     1 0 676 sub REAL_TREE { ${+shift} }
  1         3  
39              
40             sub _init {
41 84     84   99 my $self = shift;
42 84         89 my $tree = ${$self};
  84         142  
43 84         218 my ($value, $parent, $children) = @_;
44              
45 84         522 ($tree->meta->{compat}{uid}) = "$self" =~ /\((.*?)\)$/;
46              
47 84 100 100     951 if ( blessed $parent && $parent->isa( __PACKAGE__ ) ) {
    100 100        
48 3         9 $parent->addChild( $self );
49             }
50             elsif ( defined $parent && $parent ne $self->ROOT ) {
51 3         41 die "Insufficient Arguments : parent argument must be a Tree::Simple object";
52             }
53              
54             # Untested code
55 81 50       877 if ( @$children ) {
56 0         0 $self->addChild( @$children );
57             }
58              
59 81         127 return $self;
60             }
61              
62 0     0   0 sub _setParent {}
63              
64 99     99 0 41202 sub isRoot { ${+shift}->is_root }
  99         353  
65 42     42 0 19506 sub isLeaf { ${+shift}->is_leaf }
  42         152  
66              
67             sub setNodeValue {
68 21     21 0 140 my $tree = ${+shift};
  21         26  
69 21         25 my ($value) = @_;
70 21 100       50 (defined($value)) || die "Insufficient Arguments : must supply a value for node";
71 20         43 $tree->set_value( $value );
72             }
73 224     224 0 4922 sub getNodeValue { ${+shift}->value }
  224         626  
74              
75             sub getIndex {
76 6     6 0 1798 my $tree = ${+shift};
  6         11  
77              
78 6 100       19 return -1 if $tree->is_root;
79 5         46 my ($index) = $tree->parent->get_index_for( $tree );
80 5         183 return $index;
81             }
82              
83 60     60 0 24103 sub getDepth { ${+shift}->depth - 1 }
  60         216  
84 0     0 0 0 sub fixDepth {}
85             sub getParent {
86 76     76 0 12935 my $self = shift;
87 76         105 my $parent = ${$self}->parent;
  76         6284  
88 76 100       382 if ( $parent ) {
89 75         220 return $parent->meta->{compat}{object};
90             }
91             else {
92 1         27 return $self->ROOT;
93             }
94             }
95              
96 1     1 0 709 sub size { ${+shift}->size }
  1         5  
97 1     1 0 532 sub height { ${+shift}->height }
  1         4  
98              
99 45     45 0 6957 sub getChildCount { scalar ${+shift}->children }
  45         204  
100              
101             sub addChild {
102 28     28 0 3645 my $tree = ${+shift};
  28         52  
103 28 100       80 (@_)
104             || die "Insufficient Arguments : no tree(s) to insert";
105 27 100 100     2479 (blessed $_[0] && $_[0]->isa( __PACKAGE__ ))
106             || die "Insufficient Arguments : Child must be a Tree::Simple object";
107 24 50       62 return $tree->add_child(map { ${$_} } @_)
  61         60  
  61         171  
108             ? $tree->meta->{compat}{object}
109             : ();
110             }
111             *addChildren = \&addChild;
112              
113             sub insertChild {
114 22     22 0 8623 my $self = shift;
115 22         33 my $index = shift;
116 22 100       86 (defined($index))
117             || die "Insufficient Arguments : Cannot insert child without index";
118             # check the bounds of our children
119             # against the index given
120 20         52 my $child_count = $self->getChildCount();
121 20 100       1197 ($index <= $child_count)
122             || die "Index Out of Bounds : got ($index) expected no more than ($child_count).";
123 18 100       66 (@_)
124             || die "Insufficient Arguments : no tree(s) to insert";
125              
126 16         37 foreach (@_) {
127 19 100 100     164 next if blessed $_ && $_->isa( __PACKAGE__ );
128              
129 8         96 die "Insufficient Arguments : Child must be a Tree::Simple object";
130             }
131              
132 8         15 my $tree = ${$self};
  8         15  
133 8 50       31 return $tree->add_child({ at => $index }, map { ${$_} } @_ )
  11         13  
  11         14591  
134             ? $tree->meta->{compat}{object}
135             : ();
136             }
137             *insertChildren = \&insertChild;
138              
139             sub removeChild {
140 11     11 0 108 my $self = shift;
141 11         20 my ($child_to_remove) = @_;
142              
143 11 100       43 (defined($child_to_remove))
144             || die "Insufficient Arguments : you must specify a child to remove";
145 10 100       34 if (ref($child_to_remove)) {
146 5 100 100     83 (blessed($child_to_remove) && $child_to_remove->isa(__PACKAGE__))
147             || die "Insufficient Arguments : Only valid child type is a Tree::Simple object";
148 3         6 my $found = 0;
149 3         15 foreach my $child ( $self->getAllChildren() ) {
150 3 100       18 "$child" eq "$child_to_remove" or next;
151 2         4 $found = 1;
152 2         4 last;
153             }
154 3 100       15 if ( !$found ) {
155 1         11 die "Child Not Found : cannot find object ($child_to_remove) in self";
156             }
157             }
158              
159 7         2214 my @return = map {
160 7         19 $_->meta->{compat}{object}
161 2         11 } ${$self}->remove_child( map {
162 7 100       13 ref $_ ? ${$_} : $_
  7         36  
163             } @_ );
164 7 50       82 wantarray ? @return : $return[0];
165             }
166              
167             sub removeChildAt {
168 7     7 0 1998 my $self = shift;
169              
170 7         13 my ($index) = @_;
171 7 100       31 (defined $index)
172             || die "Insufficient Arguments : Cannot remove child without index.";
173 6 100       19 ((my $child_count = $self->getChildCount()) != 0)
174             || die "Illegal Operation : There are no children to remove";
175 5 100       218 ($index < $child_count)
176             || die "Index Out of Bounds : got ($index) expected no more than ($child_count)";
177 4         13 $self->removeChild( @_ );
178             }
179              
180             sub getAllChildren {
181 178     178 0 23448 my $tree = ${+shift};
  178         277  
182 178         819 my @children = map { $_->meta->{compat}{object} } $tree->children( @_ );
  359         3771  
183 178 100       2005 return wantarray ? @children : \@children;
184             }
185              
186             sub getChild {
187 88     88 0 23860 my $self = shift;
188 88         114 my ($index) = @_;
189 88 100       208 (defined($index))
190             || die "Insufficient Arguments : Cannot get child without index";
191              
192 87         175 my @children = $self->getAllChildren( @_ );
193 87         318 return $children[0];
194             }
195              
196             sub addSibling {
197 2     2 0 376 my $self = shift;
198 2 100       8 (!$self->isRoot())
199             || die "Insufficient Arguments : cannot add a sibling to a ROOT tree";
200 1         13 $self->getParent->addChild( @_ );
201             }
202             sub addSiblings {
203 2     2 0 382 my $self = shift;
204 2 100       8 (!$self->isRoot())
205             || die "Insufficient Arguments : cannot add siblings to a ROOT tree";
206 1         14 $self->getParent->addChild( @_ );
207             }
208              
209             sub insertSibling {
210 4     4 0 718 my $self = shift;
211 4 100       14 (!$self->isRoot())
212             || die "Insufficient Arguments : cannot insert sibling(s) to a ROOT tree";
213 2         28 $self->getParent->insertChild( @_ );
214             }
215             *insertSiblings = \&insertSibling;
216              
217             sub getSibling {
218 10     10 0 37 my $self = shift;
219 10 100       27 (!$self->isRoot())
220             || die "Insufficient Arguments : cannot get siblings from a ROOT tree";
221 9         91 $self->getParent->getChild( @_ );
222             }
223             sub getAllSiblings {
224 28     28 0 27433 my $self = shift;
225 28 100       89 (!$self->isRoot())
226             || die "Insufficient Arguments : cannot get siblings from a ROOT tree";
227 27         294 return $self->getParent->getAllChildren;
228             }
229              
230             sub traverse {
231 8     8 0 2033 my $tree = ${+shift};
  8         16  
232 8         14 my ($func) = @_;
233              
234 8 100       36 (defined($func)) || die "Insufficient Arguments : Cannot traverse without traversal function";
235 7 100       38 (ref($func) eq "CODE") || die "Incorrect Object Type : traversal function is not a function";
236              
237 5         22 my $traversal = $tree->traverse;
238              
239             # Tree::Simple's traverse doesn't include $self
240 5         81 $traversal->();
241              
242 5         72 while ( my $node = $traversal->() ) {
243 100         2464 $func->( $node->meta->{compat}{object} );
244             }
245             }
246              
247             sub accept {
248 5     5 0 135 my ($self, $visitor) = @_;
249             # it must be a blessed reference and ...
250 5 100 66     105 (blessed($visitor) &&
      66        
251             # either a Tree::Simple::Visitor object, or ...
252             ($visitor->isa("Tree::Simple::Visitor") ||
253             # it must be an object which has a 'visit' method avaiable
254             $visitor->can('visit')))
255             || die "Insufficient Arguments : You must supply a valid Visitor object";
256 1         5 $visitor->visit($self);
257             }
258              
259             sub clone {
260 32     32 0 409 my $self = shift;
261 32         87 my $clone = blessed($self)->new( _clone_value( $self->getNodeValue, {} ) );
262 32 100       82 if ( my @children = $self->getAllChildren ) {
263 7         10 $clone->addChild( map { $_->clone( $_->getNodeValue ) } @children );
  29         84  
264             }
265 32         2486 return $clone;
266             }
267              
268             sub _clone_value {
269 41     41   170 my ($node, $seen) = @_;
270              
271 41 100       127 return $node unless ref $node;
272 9 50       22 return $seen->{$node} if exists $seen->{$node};
273              
274 9         9 my $clone;
275 9 100       21 if ( blessed( $node ) ) {
276 3 100       33 if ( $node->can( 'clone' ) ) {
277 1         5 $clone = $node->clone;
278             }
279             else {
280 2         3 $clone = $node;
281             }
282             }
283             else {
284 6 100 100     37 if ( ref($node) eq 'SCALAR' or ref($node) eq 'REF' ) {
    100          
    100          
285 3         5 $clone = \my $var;
286 3         4 ${$clone} = _clone_value( ${$node}, $seen );
  3         5  
  3         16  
287             }
288             elsif( ref($node) eq 'ARRAY' ) {
289 4         6 $clone = [
290 1         2 map { _clone_value( $_, $seen ) } @{$node}
  1         2  
291             ];
292             }
293             elsif( ref($node) eq 'HASH' ) {
294 1         2 $clone = {};
295 1         10 while ( my ($k, $v) = each %$node ) {
296 2         5 $clone->{$k} = _clone_value( $v, $seen );
297             }
298             }
299             else {
300 1         2 $clone = $node;
301             }
302             }
303              
304 9         27 $seen->{$node} = $clone;
305 9         26 return $clone;
306             }
307              
308             sub cloneShallow {
309 0     0 0 0 my $self = shift;
310 0         0 die <<'END_DIE';
311             This method is unimplemented. You don't want to do this. The problem is that
312             $self->getChildAt(0)->getParent is not guaranteed to equal $self, and that is
313             a problem.
314             END_DIE
315             }
316              
317 0     0   0 sub DESTROY {}
318              
319 5     5 0 980 sub getUID { ${+shift}->meta->{compat}{uid} }
  5         21  
320             sub setUID {
321 2 100   2 0 2279 ($_[1]) || die "Insufficient Arguments : Custom Unique ID's must be a true value";
322 1         2 ${+shift}->meta->{compat}{uid} = $_[1];
  1         5  
323             }
324              
325             1;
326             __END__