File Coverage

blib/lib/CPAN/Flatten/Tree.pm
Criterion Covered Total %
statement 15 71 21.1
branch 0 22 0.0
condition 0 8 0.0
subroutine 5 17 29.4
pod 0 12 0.0
total 20 130 15.3


line stmt bran cond sub pod time code
1             package CPAN::Flatten::Tree;
2 1     1   301 use strict;
  1         1  
  1         21  
3 1     1   3 use warnings;
  1         1  
  1         17  
4 1     1   463 use utf8;
  1         8  
  1         4  
5 1     1   25 use Scalar::Util 'weaken';
  1         1  
  1         413  
6              
7             sub new {
8 0     0 0   my $class = shift;
9 0 0         my %args = ref $_[0] ? %{$_[0]} : @_;
  0            
10 0           my $self = bless {
11             _parent => undef,
12             _children => [],
13             %args,
14             }, $class;
15 0           $self;
16             }
17              
18             sub add_child {
19 0     0 0   my ($self, $node) = @_;
20 0 0         if ($node->{_parent}) {
21 0           require Carp;
22 0           Carp::confess("node (@{[$node->uid]}) already has a parent");
  0            
23             }
24 0           push @{ $self->{_children} }, $node;
  0            
25 0           $node->{_parent} = $self;
26 0           weaken $node->{_parent};
27 0           $self;
28             }
29              
30             sub is_child {
31 0     0 0   my ($self, $that) = @_;
32 0           for my $child ($self->children) {
33 0 0         return 1 if $child->equals($that);
34             }
35 0           return;
36             }
37              
38             sub is_sister {
39 0     0 0   my ($self, $that) = @_;
40 0 0         return if $self->is_root;
41 0           for my $sister ($self->parent->children) {
42 0 0         return 1 if $sister->equals($that);
43             }
44 0           return;
45             }
46              
47             sub children {
48 0     0 0   my ($self, $filter) = @_;
49 0           my @children = @{$self->{_children}};
  0            
50 0 0         if ($filter) {
51 0           grep { $filter->($_) } @children;
  0            
52             } else {
53 0           @children;
54             }
55             }
56              
57             sub parent {
58 0     0 0   shift->{_parent};
59             }
60              
61             sub is_root {
62 0 0   0 0   shift->parent ? 0 : 1;
63             }
64              
65             sub root {
66 0     0 0   my $node = shift;
67 0           while (1) {
68 0 0         return $node if $node->is_root;
69 0           $node = $node->parent;
70             }
71             }
72              
73             sub depth {
74 0     0 0   my $node = shift;
75 0           my $depth = 0;
76 0           while (1) {
77 0 0         return $depth if $node->is_root;
78 0           $node = $node->parent;
79 0           $depth++;
80             }
81             }
82              
83 1     1   4 use constant STOP => -1;
  1         1  
  1         172  
84              
85             sub walk_down {
86 0     0 0   my ($self, $callback, $depth) = @_;
87 0   0       $depth ||= 0;
88 0           my $ret = $callback->($self, $depth);
89 0 0 0       return $ret if defined $ret && $ret eq STOP;
90 0           for my $child ($self->children) {
91 0           $ret = $child->walk_down($callback, $depth + 1);
92 0 0 0       return $ret if defined $ret && $ret eq STOP;
93             }
94 0           return 1;
95             }
96              
97             sub uid {
98 0     0 0   my $self = shift;
99 0           my ($uid) = ("$self" =~ /\((.*?)\)$/);
100 0           $uid;
101             }
102              
103             sub equals {
104 0     0 0   my ($self, $that) = @_;
105 0           $self->uid eq $that->uid;
106             }
107              
108             1;