Class::MOP - fleshing out the attributes a bit more
[gitmo/Class-MOP.git] / t / lib / BinaryTree.pm
CommitLineData
c50c603e 1
2package BinaryTree;
3
4use strict;
5use warnings;
6
7our $VERSION = '0.01';
8
9use Class::MOP ':universal';
10
11__PACKAGE__->meta->add_attribute(
12 Class::MOP::Attribute->new('_uid' => (
13 reader => 'getUID',
14 writer => 'setUID',
15 default => sub {
16 my $instance = shift;
17 ("$instance" =~ /\((.*?)\)$/);
18 }
19 ))
20);
21
22__PACKAGE__->meta->add_attribute(
23 Class::MOP::Attribute->new('_node' => (
24 reader => 'getNodeValue',
25 writer => 'setNodeValue',
26 init_arg => ':node'
27 ))
28);
29
30__PACKAGE__->meta->add_attribute(
31 Class::MOP::Attribute->new('_parent' => (
32 reader => 'getParent',
33 writer => 'setParent',
34 predicate => {
35 'isRoot' => sub {
36 my ($self) = @_;
37 return not defined $self->{_parent};
38 }
39 }
40 ))
41);
42
43__PACKAGE__->meta->add_attribute(
44 Class::MOP::Attribute->new('_left' => (
45 predicate => 'hasLeft',
46 reader => 'getLeft',
47 writer => {
48 'setLeft' => sub {
49 my ($self, $tree) = @_;
50 $tree->setParent($self);
51 $self->{_left} = $tree;
52 $tree->setDepth($self->getDepth() + 1);
53 $self;
54 }
55 },
56 ))
57);
58
59__PACKAGE__->meta->add_attribute(
60 Class::MOP::Attribute->new('_right' => (
61 predicate => 'hasRight',
62 reader => 'getRight',
63 writer => {
64 'setRight' => sub {
65 my ($self, $tree) = @_;
66 $tree->setParent($self);
67 $self->{_right} = $tree;
68 $tree->setDepth($self->getDepth() + 1);
69 $self;
70 }
71 }
72 ))
73);
74
75__PACKAGE__->meta->add_attribute(
76 Class::MOP::Attribute->new('_depth' => (
77 default => 0,
78 reader => 'getDepth',
79 writer => {
80 'setDepth' => sub {
81 my ($self, $depth) = @_;
82 unless ($self->isLeaf()) {
83 $self->fixDepth();
84 }
85 else {
86 $self->{_depth} = $depth;
87 }
88 }
89 }
90 ))
91);
92
93sub new {
94 my $class = shift;
95 bless $class->meta->construct_instance(':node' => shift) => $class;
96}
97
98sub removeLeft {
99 my ($self) = @_;
100 my $left = $self->{_left};
101 $left->setParent(undef);
102 $left->setDepth(0);
103 $self->{_left} = undef;
104 return $left;
105}
106
107sub removeRight {
108 my ($self) = @_;
109 my $right = $self->{_right};
110 $right->setParent(undef);
111 $right->setDepth(0);
112 $self->{_right} = undef;
113 return $right;
114}
115
116sub isLeaf {
117 my ($self) = @_;
118 return (!$self->hasLeft && !$self->hasRight);
119}
120
121sub fixDepth {
122 my ($self) = @_;
123 # make sure the tree's depth
124 # is up to date all the way down
125 $self->traverse(sub {
126 my ($tree) = @_;
127 unless ($tree->isRoot()) {
128 $tree->{_depth} = $tree->getParent()->getDepth() + 1;
129 }
130 else {
131 $tree->{_depth} = 0;
132 }
133 }
134 );
135}
136
137sub traverse {
138 my ($self, $func) = @_;
139 $func->($self);
140 $self->{_left}->traverse($func) if defined $self->{_left};
141 $self->{_right}->traverse($func) if defined $self->{_right};
142}
143
144sub mirror {
145 my ($self) = @_;
146 # swap left for right
147 my $temp = $self->{_left};
148 $self->{_left} = $self->{_right};
149 $self->{_right} = $temp;
150 # and recurse
151 $self->{_left}->mirror() if $self->hasLeft();
152 $self->{_right}->mirror() if $self->hasRight();
153 $self;
154}
155
156sub size {
157 my ($self) = @_;
158 my $size = 1;
159 $size += $self->{_left}->size() if $self->hasLeft();
160 $size += $self->{_right}->size() if $self->hasRight();
161 return $size;
162}
163
164sub height {
165 my ($self) = @_;
166 my ($left_height, $right_height) = (0, 0);
167 $left_height = $self->{_left}->height() if $self->hasLeft();
168 $right_height = $self->{_right}->height() if $self->hasRight();
169 return 1 + (($left_height > $right_height) ? $left_height : $right_height);
170}
171