Tree.pm
package Tree;
use Moose;
use Scalar::Util 'reftype';
our $VERSION = '0.01';
our $AUTHORITY = 'cpan:STEVAN';
has 'node' => ( is => 'rw', isa => 'Any' );
has 'uid' => (
is => 'rw',
isa => 'Value',
lazy => 1,
default => sub { ( $_[0] =~ /\((.*?)\)$/ )[0] },
);
has 'parent' => (
reader => 'parent',
writer => '_set_parent',
predicate => 'has_parent',
isa => 'Tree',
is_weak_ref => 1,
handles => {
'add_sibling' => 'add_child',
'get_sibling_at' => 'get_child_at',
'insert_sibling_at' => 'insert_child_at',
},
);
has 'children' => (
is => 'rw',
isa => 'ArrayRef',
default => sub { [] },
);
## informational
sub is_root { !(shift)->has_parent }
sub is_leaf { (shift)->child_count == 0 }
## depth
sub depth { ( (shift)->parent || return -1 )->depth + 1 }
## child management
sub add_child {
my ( $self, $child ) = @_;
( blessed($child) && $child->isa('Tree') )
|| confess "Child parameter must be a Tree not ($child)";
$child->_set_parent($self);
push @{ $self->children } => $child;
$self;
}
sub insert_child_at {
my ( $self, $index, $child ) = @_;
( blessed($child) && $child->isa('Tree') )
|| confess "Child parameter must be a Tree not ($child)";
$child->_set_parent($self);
splice @{ $self->children }, $index, 0, $child;
}
sub get_child_at {
my ( $self, $index ) = @_;
$self->children->[$index];
}
sub child_count { scalar @{ (shift)->children } }
## traversal
sub traverse {
my ( $self, $func ) = @_;
( defined($func) )
|| confess "Cannot traverse without traversal function";
( reftype($func) eq "CODE" )
|| die "Traversal function must be a CODE reference, not : $func";
foreach my $child ( @{ $self->children } ) {
$func->($child);
$child->traverse($func);
}
}
# NOTE:
# we are basically inlining the
# constructor here, and caching
# all our important bits, this
# speeds up building large trees
# considerably.
__PACKAGE__->meta->make_immutable( inline_accessors => 0 );
no Moose; 1;
__END__