[ Home | Main Table Of Contents | Table Of Contents | Keyword Index ]

cmdr-spec-dsl(n) 1.2 doc "Cmdr, a framework for command line parsing and dispatch"

Name

cmdr-spec-dsl - Cmdr - Introduction to the Specification Language

Table Of Contents

Description

Welcome to the Cmdr project, written by Andreas Kupries.

For availability please read Cmdr - How To Get The Sources.

This document is for users of the cmdr framework. It introduces the domain-specific language for the specification of command hierarchies with commands and their parameters by way of examples and then provides links to the detailed reference documents.

Related Specification Documents

  1. Cmdr - Introduction to the Specification Language

  2. Cmdr - Officer Specification Language

  3. Cmdr - Private Specification Language

  4. Cmdr - Parameter Specification Language

  5. Cmdr - Runtime Processing Flow

Introductory examples

Instead of immediately diving into the full syntax of the specification language first a few examples to demonstrate the general look and feel, plus basic features.

Basic private commands with inputs

This example specifies a command line providing 3 commands for the management of command aliases. This is actually a slice of stackato's interface, reduced and modified to fit here. While it does not have the necessary backend procedures required to actually run the commands, it is enough to demonstrate basic features, namely the declaration of "privates" with "input" parameters.

"privates" are the actual commands, the leaves at the bottom of the hierarchy. Their "inputs" are positional parameters, i.e. the association of argument words on a command line to parameter is done in order of occurence (on command line, and in the specification).

# -*- tcl -*
package require Tcl 8.5
package require cmdr
package require foo-backend
cmdr create ::foo foo {
    private alias+ {
	description {
	    Create a shortcut for a command (prefix).
	}
	input name {
	    The name of the new shortcut.
	} {
	    validate ::foo::backend::vt::notacommand
	}
	input command {
	    The command (prefix) the name will map to.
	} {
	    list
	}
    } ::foo::backend::alias::add
    private alias- {
	description {
	    Remove a shortcut by name.
	}
	input name {
	    The name of the shortcut to remove.
	} {
	    validate ::foo::backend::vt::aliasname
	}
    } ::foo::backend::alias::remove
    private alias? {
	description {
	    List the known aliases (shortcuts).
	}
    } ::foo::backend::alias::list
}
foo do {*}$argv
exit

At the bottom of the example, just above we can also see the very simple Tcl command which invokes the command line processing for a list of words, here coming from $argv, i.e. the application's command line.

Simple command nesting

The decoupling of command names from their implementations seen in the previous example makes it easy to re-arrange and re-label the user visible commands without having to touch any other part of the code.

This is demonstrated in the example below, moving the 3 "privates" into an "officer" and renaming them, without changing the actions. Note that the parameter specifications were removed for clarity, as they were not changed compared to the original example.

"officers" are named inner nodes in the command hierarchy. They aggregate related commands, which may not only be "privates" as seen here, but sub-officers as well.

...
cmdr create ::foo foo {
    officer alias {
	description {
	    A collection of commands to manage
	    user-specific shortcuts for command
	    entry
	}
	private add {
	    ...
	} ::foo::backend::alias::add
	private remove {
	    ...
	} ::foo::backend::alias::remove
	private list {
	    ...
	} ::foo::backend::alias::list
    }
}
...

Simple backend

This example shows a possible implementation of the backend for the command hierarchies shown in the previous two sections. It is important to note, I believe, that this backend works for both command hierarchies, despite the changes to the command names (flat versus nesting) they do.

Note further that while this example uses a namespace ensemble to organize the backend other methods are possible too, i.e. all the various object systems for Tcl would be suitable as well.

Lastly, for the sake of brevity this code is incomplete, not showing any utility commands we may have importet from somewhere else, nor the low-level workhorse procedures operating on the actual alias database or whatnot.

# -*- tcl -*-
# # ## ### ##### ######## ############# #####################
namespace eval ::foo::backend::alias {
    namespace export list add remove
    namespace ensemble create
}
# # ## ### ##### ######## ############# #####################
## Command implementations.
proc ::foo::backend::alias::list {config} {
    set aliases [manager known]
    if {[$config @json]} {
	puts [jmap aliases $aliases]
	return
    }
    [table::do t {Alias Command} {
	foreach {name command} $aliases {
	    $t add $name $command
	}
    } show display]
    return
}
proc ::foo::backend::alias::add {config} {
    set name    [$config @name]
    set command [$config @command]
    manager add $name $command
    say [color green "Successfully aliased '$name' to '$command'"]
    return
}
proc ::foo::backend::alias::remove {config} {
    set name [$config @name]
    if {![manager has $name]} {
	err [color red "Unknown alias '$name'"]
    } else {
	manager remove $name
	say [color green "Successfully unaliased '$name'"]
    }
    return
}
# # ## ### ##### ######## ############# #####################
package provide  foo::backend::alias 0
# 2 lines, hidden from kettle scanner.

Language Reference

With the examples behind us we can now go and specify the entire specification language. If you have skipped here on first reading, ignoring the examples, please go back and read them first.

The conceptual model underneath the command hierarchy is that of a tree.

The inner nodes of the tree represent command ensembles, here called officers. Each officer knows one or more commands to perform, and delegates actual execution to their respective specification, which may be another officer, or a private.

The leaf nodes of the tree represent the individual commands, here called privates. Each private is responsible for a single action and knows how to perform it, and the set of parameters used to configure that action at runtime.

The same model is graphically presented in the Entity-Relationship-Diagram below.

erd

The actor in that diagram is the common base class for the ensembles and commands and not directly relevant to users.

The config on the other hand is the second interface seen by the user, as the sole argument to the action command prefix of private. See Cmdr - Officer Specification Language for the details. This container, an instance of cmdr::config, holds all the declared parameters of the command the action is invoked for, and provides easy access to them through its methods at the time of execution.

Please continue reading with Cmdr - Officer Specification Language.

Related Documents

  1. Cmdr - Introduction to the project

  2. Cmdr - License

  3. Cmdr - Log of Changes

  4. Cmdr - How To Get The Sources

  5. Cmdr - The Installer's Guide

  6. Cmdr - The Developer's Guide

Bugs, Ideas, Feedback

Both the package(s) and this documentation will undoubtedly contain bugs and other problems. Please report such at Cmdr Tickets.

Please also report any ideas you may have for enhancements of either package(s) and/or documentation.

Keywords

arguments, command hierarchy, command line completion, command line handling, command tree, editing command line, help for command line, hierarchy of commands, interactive command shell, optional arguments, options, parameters, processing command line, tree of commands