The node tree

Classes

class  senf::console::GenericNode
 Config/console node tree base-class. More...
 
class  senf::console::DirectoryNode
 Config/console tree directory node. More...
 
class  senf::console::CommandNode
 Config/console tree command node. More...
 
class  senf::console::ScopedDirectory< Owner >
 DirectoryNode member proxy. More...
 

Detailed Description

The console/config node tree is the central data-structure of the library. Into this tree, all commands and parameters are entered. The tree is then exposed using a file-system like interface.

The tree

We will start by giving a more complete example. This example contains most of the stuff needed
for using the console/config library.
// Define callback function.
void mycommand(std::ostream & os, senf::console::ParseCommandInfo const & command)
{
// ...
os << "!! Important message ...\n";
}
class SomeClass
{
public:
// Declare a directory node (proxy) for use by this class. This must be public so we can add
// it to the node tree later.
SomeClass() : dir(this)
{
namespace fty = senf::console::factory;
// You may document the directory here or later when adding it to the tree
dir.doc("Manager for something");
// Add a member function (the pointer-to-member is automatically bound to this instance)
dir.add("member", fty::Command(&SomeClass::member, this)
.doc("Do the member operation"));
}
void member(std::ostream & os, senf::console::ParseCommandInfo const & command)
{
// ...
}
};
int main(int, char**)
{
namespace fty = senf::console::factory;
// Provide global documentation
.doc("This is someServer server");
// Add a new directory to the root and document it. All the mutators return the node object
// itself so operations can be chained.
.add("myserver", fty::Directory()
.doc("My server specific directory")));
// Add a command to that directory
mydir.add("mycommand", fty::Command(&mycommand)
.doc("mycommand <foo> [<bar>]\n\n"
"If <bar> is given, flurgle the <foo>, otherwise burgle it"));
// Create a SomeClass instance and add it's directory.
SomeClass someClass;
mydir.add("someClass", someClass.dir);
// Start the interactive console server
.name("someServer");
}

Node types

The console/config library tree consists of two basic node types:

\li senf::console::DirectoryNode provides internal nodes with an arbitrary number of children
\li senf::console::CommandNode describes a command entry in the tree
\li senf::console::LinkNode is a link to another node. It works much like a symlink on POSIX
    systems.

senf::console::CommandNode is the base-class of all command nodes of which there are several,
depending on the type of command.

There is a single root node, the senf::console::DirectoryNode called senf::console::root(). From
this node, the tree is traversed.

All nodes are allocated on the heap and are managed using a smart pointer.

Manipulating the node tree

There are several ways to add nodes to the tree:

\li A senf::console::DirectoryNode can be added using senf::console::DirectoryNode::mkdir().
\li An arbitrary node can be created and then (possibly later) added to the tree using the
    corresponding senf::console::DirectoryNode::add() overload.
\li A senf::console::CommandNode is normally added to the tree by directly adding a callback
    using one of the overloaded senf::console::DirectoryNode::add() members. See \ref
    console_commands.
\li A senf::console::LinkNode is created by senf::console::DirectoryNode::link()

When directly adding a node callback, the type of node added depends on the type of
callback. The callback types which can be added are listed at \ref console_callbacks.
void callback(std::ostream & os, senf::console::ParseCommandInfo const & command) { ... }
// ...
myDirectory.add("foo",fty::Command(&callback));
Every node is identified among it's siblings by it's name. The name of the node is set when
adding the node to the tree. If the name is empty or non-unique, a unique name will be
automatically provided.

To remove a node from the tree, just use the nodes senf::console::GenericNode::unlink() or the
parents senf::console::DirectoryNode::remove() member. This call removes the node from it's
parent and returns a (smart) node pointer.

\li If you ignore the return value, the node (and it's children) will be deleted.
\li Alternatively, you may store away the node and re-attach it later.
\li An node (or subtree) can be moved to a different place by unlinking the node at it's old
    place and re-adding it at it's new location.
\li To rename a node, unlink and re-add it with a different name.
myDirectory.add("bar", myDirectory.remove("foo"));

Assigning additional node parameters

Depending on the node type added, additional node parameters may be set. For example, every node
has a documentation parameter which is used by the online-help system. To assign these
parameters, the node exposes corresponding member functions. Since
senf::console::DirectoryNode::add() returns the newly added node by reference. Additional
parameters may be added after the factory call:
myDirectory.add("foo", fty::Command(&fooCallback).doc("The foo method") );

Since the parameter setters all return the node reference, additional parameters may just be added to the end of the command.

Traversing the tree

The simplest way to access tree elements is to save the return value of the
senf::console::DirectoryNode::add() members. However, saving the reference will not ensure, that
the node is not removed. If the node might be removed from the tree, you should use a smart
pointer (either <tt>ptr</tt> or <tt>weak_ptr</tt>) to hold the node.

Another possibility is to traverse the tree explicitly. For this purpose, the operators '[]' and
'()' have been overloaded in senf::console::DirectoryNode.
\\ or more concise but otherwise completely identical
senf::console::root()["myDirectory"]("foo")
getDirectory and the '[]' operator will return a senf::console::DirectoryNode whereas getCommand
and the '()' operator will return a senf::console::CommandNode. If the node is not found or is
not of the correct type, an exception will be raised.

Assigning a directory to an object instance

Most objects will register several commands. So it makes sense for these objects to manage their
own directory. Since directories are however allocated on the heap, they cannot be directly
added to a class. To facilitate this usage, the senf::console::ScopedDirectory is used. This
class provides a senf::console::DirectoryNode facade. Internally, it automatically creates a
senf::console::DirectoryNode to which all calls are forwarded.

The senf::console::ScopedDirectory member should be declared public. This allows the user of the
class to add the node to the tree.