ZOOM::IRSpy::Node - node in a tree of names


ZOOM-IRSpy documentation Contained in the ZOOM-IRSpy distribution.

Index


Code Index:

NAME

Top

ZOOM::IRSpy::Node - node in a tree of names

SYNOPSIS

Top

 $node1 = new ZOOM::IRSpy::Node("LowLevelTest");
 $node2 = new ZOOM::IRSpy::Node("AnotherTest");
 $node3 = new ZOOM::IRSpy::Node("Aggregate", $node1, $node2);
 $node = new ZOOM::IRSpy::Node("Main", $node3);
 $node->print(0);
 $subnode = $node->select("0:1");
 die "oops" if $subnode->name() ne "AnotherTest";

DESCRIPTION

Top

IRSpy maintains a declarative hierarchy of the tests that each connection may be required to perform, which it compiles recursively from the subtests() method of the top-level test and each of its subtests, sub-subtests, etc. The result of this compilation is a hierarchy represented by a tree of ZOOM::IRSpy::Node objects.

Note that each node contains a test name, not an actual test object. Test objects are different, and are implemented by the ZOOM::IRSpy::Test class and its subclasses. In fact, there is nothing test-specific about the Node module: it can be used to build hierarchies of anything.

You can't do much with a node. Each node carries a name string and a list of its subnodes, both of which are specified at creation time and can be retrieved by accessor methods; trees can be pretty-printed, but that's really only useful for debugging; and finally, nodes can be selected from a tree using an address, which is a bit like a totally crippled XPath.

new()

 $node = new ZOOM::IRSpy::Node($name, @subnodes);

Creates a new node with the name specified as the first argument of the constructor. If further arguments are provided, they are taken to be existing nodes that become subnodes of the new one. Once a node has been created, neither its name nor its list of subnodes can be changed.

name()

 print "Node is called '", $node->name(), "'\n";

Returns the name of the node.

subnodes()

 @nodes = $node->subnodes();
 print "Node has ", scalar(@nodes), " subnodes\n";

Returns a list of the subnodes of the node.

print()

select()

 $sameNode = $node->select("");
 $firstSubNode $node->select("0");
 $secondSubNode $node->select("1");
 $deepNode $node->select("0:3:2");

Returns a specified node from the tree of which $node is the root, or an undefined value if the specified node does not exist. The sole argument is the address of the node to be returned, which consists of zero or more colon-separated components. Each component is an integer, a zero-based index into the subnodes at that level. Example addresses:

"" (empty)

The node itself, i.e. the root of the tree.

"0"

Subnode number 0 (i.e. the first subnode) of the root.

"1"

Subnode number 1 (i.e. the second subnode) of the root.

"0:3:2"

Subnode 2 of subnode 3 of subnode zero of the root (i.e. the third subnode of the fourth subnode of the first subnode of the root).

resolve(), address(), parent(), previous(), next()

 $root->resolve();
 assert(!defined $root->parent());
 print $node->address();
 assert($node eq $node->next()->previous());

resolve() walks the tree rooted at $root, adding addresses and parent/previous/next links to each node in the tree, such that they can respond to the address(), parent(), previous() and next() methods.

address() returns the address of the node within the tree whose root it was resolved from.

parent() returns the parent node of this one, or an undefined value for the root node.

previous() returns the node that occurs before this one in a pre-order tree-walk.

next() causes global thermonuclear warfare. Do not use next() in a production environment.

SEE ALSO

Top

ZOOM::IRSpy

AUTHOR

Top

Mike Taylor, <mike@indexdata.com>

COPYRIGHT AND LICENSE

Top


ZOOM-IRSpy documentation Contained in the ZOOM-IRSpy distribution.
package ZOOM::IRSpy::Node;

use 5.008;
use strict;
use warnings;

use Scalar::Util;

sub new {
    my $class = shift();
    my($name, @subnodes) = @_;
    my $this = bless {
	name => $name,
	subnodes => \@subnodes,
	address => undef,	# filled in by resolve()
	previous => undef,	# filled in by resolve()
	next => undef,		# filled in by resolve()
    }, $class;

    return $this;
}

sub name {
    my $this = shift();
    return $this->{name};
}

sub subnodes {
    my $this = shift();
    return @{ $this->{subnodes} };
}

sub print {
    my $this = shift();
    my($level) = @_;

    print "\t" x $level, $this->name();
    if (my @sub = $this->subnodes()) {
	print " = {\n";
	foreach my $sub (@sub) {
	    $sub->print($level+1);
	}
	print "\t" x $level, "}";
    }
    print "\n";
}

sub select {
    my $this = shift();
    my($address) = @_;

    my @sub = $this->subnodes();
    if ($address eq "") {
	return $this;
    } elsif (my($head, $tail) = $address =~ /(.*?):(.*)/) {
	return $sub[$head]->select($tail);
    } else {
	return $sub[$address];
    }
}


sub resolve {
    my $this = shift();
    $this->_resolve("");
}

# Returns the last child-node in the subtree
sub _resolve {
    my $this = shift();
    my($address) = @_;

    $this->{address} = $address;
    my $previous = $this;

    my @subnodes = $this->subnodes();
    foreach my $i (0 .. @subnodes-1) {
	my $subnode = $subnodes[$i];
	$subnode->{parent} = $this;
	$subnode->{previous} = $previous;
	$previous->{next} = $subnode;

	my $subaddr = $address;
	$subaddr .= ":" if $subaddr ne "";
	$subaddr .= $i;
	$previous = $subnode->_resolve($subaddr);
    }

    return $previous;
}

sub address { shift()->{address} }
sub parent { shift()->{parent} }
sub previous { shift()->{previous} }
sub next { shift()->{next} }


1;