# CommandSpec
<span class="source-link">[[Source]](src/cli/_value_type.md#L-0-9)</span>

CommandSpec describes the specification of a parent or leaf command. Each
command has the following attributes:

- a name: a simple string token that identifies the command.
- a description: used in the syntax message.
- a map of options: the valid options for this command.
- an optional help option+command name for help parsing
- one of:
   - a Map of child commands.
   - an Array of arguments.


```pony
class ref CommandSpec
```

## Constructors

### parent
<span class="source-link">[[Source]](src/cli/_value_type.md#L-0-32)</span>


Creates a command spec that can accept options and child commands, but not
arguments.


```pony
new ref parent(
  name': String val,
  descr': String val = "",
  options': Array[OptionSpec val] box = Array[OptionSpec](),
    commands': Array[CommandSpec] box = Array[CommandSpec]()) ?
  =>
    """
    Creates a command spec that can accept options and child commands, but not
    arguments.
    """
    _type = _CommandSpecParent
    _name = _assert_name(name')?
    _descr = descr'
    for o in options'.values() do
      _options.update(o.name(), o)
    end
    for c in commands'.values() do
      _commands.update(c.name(), c)
    end

  new leaf(
    name': String,
    descr': String = "",
    options': Array[OptionSpec] box = Array[OptionSpec](),
    args': Array[ArgSpec] box = Array[ArgSpec]()) ?
  =>
    """
    Creates a command spec that can accept options and arguments, but not child
    commands.
    """
    _type = _CommandSpecLeaf
    _name = _assert_name(name')?
    _descr = descr'
    for o in options'.values() do
      _options.update(o.name(), o)
    end
    for a in args'.values() do
      _args.push(a)
    end

  fun tag _assert_name(nm: String): String ? =>
    for b in nm.values() do
      if (b != '-') and (b != '_') and
        not ((b >= '0') and (b <= '9')) and
        not ((b >= 'A') and (b <= 'Z')) and
        not ((b >= 'a') and (b <= 'z')) then
        error
      end
    end
    nm

  fun ref add_command(cmd: CommandSpec box) ? =>
    """
    Adds an additional child command to this parent command.
    """
    if is_leaf() then error end
    _commands.update(cmd.name(), cmd)

  fun ref add_help(hname: String = "help", descr': String = "") ? =>
    """
    Adds a standard help option and, optionally command, to a root command.
    """
    _help_name = hname
    _help_info = descr'
    let help_option = OptionSpec.bool(_help_name, _help_info, 'h', false)
    _options.update(_help_name, help_option)
    if is_parent() then
      let help_cmd =
        CommandSpec.leaf(
          _help_name,
          "",
          Array[OptionSpec](),
          [
            ArgSpec.string("command" where default' = "")
          ])?
      _commands.update(_help_name, help_cmd)
    end

  fun name(): String =>
    """
    Returns the name of this command.
    """
    _name

  fun descr(): String =>
    """
    Returns the description for this command.
    """
    _descr

  fun options(): Map[String, OptionSpec] box =>
    """
    Returns a map by name of the named options of this command.
    """
    _options

  fun commands(): Map[String, CommandSpec box] box =>
    """
    Returns a map by name of the child commands of this command.
    """
    _commands

  fun args(): Array[ArgSpec] box =>
    """
    Returns an array of the positional arguments of this command.
    """
    _args

  fun is_leaf(): Bool => _type is _CommandSpecLeaf

  fun is_parent(): Bool => _type is _CommandSpecParent

  fun help_name(): String =>
    """
    Returns the name of the help command, which defaults to "help".
    """
    _help_name

  fun help_string(): String =>
    """
    Returns a formatted help string for this command and all of its arguments.
    """
    let s = _name.clone()
    s.append(" ")
    let args_iter = _args.values()
    for a in args_iter do
      s.append(a.help_string())
      if args_iter.has_next() then s.append(" ") end
    end
    s

class,
  commands': Array[CommandSpec ref] box = class CommandSpec
  """
  CommandSpec describes the specification of a parent or leaf command. Each
  command has the following attributes:

  - a name: a simple string token that identifies the command.
  - a description: used in the syntax message.
  - a map of options: the valid options for this command.
  - an optional help option+command name for help parsing
  - one of:
     - a Map of child commands.
     - an Array of arguments.
  """
  let _type: _CommandSpecType
  let _name: String
  let _descr: String
  let _options: Map[String, OptionSpec] = _options.create()
  var _help_name: String = ""
  var _help_info: String = ""
  // A parent commands can have sub-commands; leaf commands can have args.
  let _commands: Map[String, CommandSpec box] = _commands.create()
  let _args: Array[ArgSpec] = _args.create()

  new parent(
    name': String,
    descr': String = "",
    options': Array[OptionSpec] box = Array[OptionSpec](),
    commands': Array[CommandSpec] box = Array[CommandSpec]())
: CommandSpec ref^ ?
```
#### Parameters

*   name': [String](builtin-String.md) val
*   descr': [String](builtin-String.md) val = ""
*   options': [Array](builtin-Array.md)\[[OptionSpec](cli-OptionSpec.md) val\] box = Array[OptionSpec](),
    commands': Array[CommandSpec] box = Array[CommandSpec]()) ?
  =>
    """
    Creates a command spec that can accept options and child commands, but not
    arguments.
    """
    _type = _CommandSpecParent
    _name = _assert_name(name')?
    _descr = descr'
    for o in options'.values() do
      _options.update(o.name(), o)
    end
    for c in commands'.values() do
      _commands.update(c.name(), c)
    end

  new leaf(
    name': String,
    descr': String = "",
    options': Array[OptionSpec] box = Array[OptionSpec](),
    args': Array[ArgSpec] box = Array[ArgSpec]()) ?
  =>
    """
    Creates a command spec that can accept options and arguments, but not child
    commands.
    """
    _type = _CommandSpecLeaf
    _name = _assert_name(name')?
    _descr = descr'
    for o in options'.values() do
      _options.update(o.name(), o)
    end
    for a in args'.values() do
      _args.push(a)
    end

  fun tag _assert_name(nm: String): String ? =>
    for b in nm.values() do
      if (b != '-') and (b != '_') and
        not ((b >= '0') and (b <= '9')) and
        not ((b >= 'A') and (b <= 'Z')) and
        not ((b >= 'a') and (b <= 'z')) then
        error
      end
    end
    nm

  fun ref add_command(cmd: CommandSpec box) ? =>
    """
    Adds an additional child command to this parent command.
    """
    if is_leaf() then error end
    _commands.update(cmd.name(), cmd)

  fun ref add_help(hname: String = "help", descr': String = "") ? =>
    """
    Adds a standard help option and, optionally command, to a root command.
    """
    _help_name = hname
    _help_info = descr'
    let help_option = OptionSpec.bool(_help_name, _help_info, 'h', false)
    _options.update(_help_name, help_option)
    if is_parent() then
      let help_cmd =
        CommandSpec.leaf(
          _help_name,
          "",
          Array[OptionSpec](),
          [
            ArgSpec.string("command" where default' = "")
          ])?
      _commands.update(_help_name, help_cmd)
    end

  fun name(): String =>
    """
    Returns the name of this command.
    """
    _name

  fun descr(): String =>
    """
    Returns the description for this command.
    """
    _descr

  fun options(): Map[String, OptionSpec] box =>
    """
    Returns a map by name of the named options of this command.
    """
    _options

  fun commands(): Map[String, CommandSpec box] box =>
    """
    Returns a map by name of the child commands of this command.
    """
    _commands

  fun args(): Array[ArgSpec] box =>
    """
    Returns an array of the positional arguments of this command.
    """
    _args

  fun is_leaf(): Bool => _type is _CommandSpecLeaf

  fun is_parent(): Bool => _type is _CommandSpecParent

  fun help_name(): String =>
    """
    Returns the name of the help command, which defaults to "help".
    """
    _help_name

  fun help_string(): String =>
    """
    Returns a formatted help string for this command and all of its arguments.
    """
    let s = _name.clone()
    s.append(" ")
    let args_iter = _args.values()
    for a in args_iter do
      s.append(a.help_string())
      if args_iter.has_next() then s.append(" ") end
    end
    s

class
*   commands': [Array](builtin-Array.md)\[[CommandSpec](cli-CommandSpec.md) ref\] box = class CommandSpec
  """
  CommandSpec describes the specification of a parent or leaf command. Each
  command has the following attributes:

  - a name: a simple string token that identifies the command.
  - a description: used in the syntax message.
  - a map of options: the valid options for this command.
  - an optional help option+command name for help parsing
  - one of:
     - a Map of child commands.
     - an Array of arguments.
  """
  let _type: _CommandSpecType
  let _name: String
  let _descr: String
  let _options: Map[String, OptionSpec] = _options.create()
  var _help_name: String = ""
  var _help_info: String = ""
  // A parent commands can have sub-commands; leaf commands can have args.
  let _commands: Map[String, CommandSpec box] = _commands.create()
  let _args: Array[ArgSpec] = _args.create()

  new parent(
    name': String,
    descr': String = "",
    options': Array[OptionSpec] box = Array[OptionSpec](),
    commands': Array[CommandSpec] box = Array[CommandSpec]()

#### Returns

* [CommandSpec](cli-CommandSpec.md) ref^ ?

---

### leaf
<span class="source-link">[[Source]](src/cli/_value_type.md#L-0-52)</span>


Creates a command spec that can accept options and arguments, but not child
commands.


```pony
new ref leaf(
  name': String val,
  descr': String val = "",
  options': Array[OptionSpec val] box = Array[OptionSpec](),
    args': Array[ArgSpec] box = Array[ArgSpec]()) ?
  =>
    """
    Creates a command spec that can accept options and arguments, but not child
    commands.
    """
    _type = _CommandSpecLeaf
    _name = _assert_name(name')?
    _descr = descr'
    for o in options'.values() do
      _options.update(o.name(), o)
    end
    for a in args'.values() do
      _args.push(a)
    end

  fun tag _assert_name(nm: String): String ? =>
    for b in nm.values() do
      if (b != '-') and (b != '_') and
        not ((b >= '0') and (b <= '9')) and
        not ((b >= 'A') and (b <= 'Z')) and
        not ((b >= 'a') and (b <= 'z')) then
        error
      end
    end
    nm

  fun ref add_command(cmd: CommandSpec box) ? =>
    """
    Adds an additional child command to this parent command.
    """
    if is_leaf() then error end
    _commands.update(cmd.name(), cmd)

  fun ref add_help(hname: String = "help", descr': String = "") ? =>
    """
    Adds a standard help option and, optionally command, to a root command.
    """
    _help_name = hname
    _help_info = descr'
    let help_option = OptionSpec.bool(_help_name, _help_info, 'h', false)
    _options.update(_help_name, help_option)
    if is_parent() then
      let help_cmd =
        CommandSpec.leaf(
          _help_name,
          "",
          Array[OptionSpec](),
          [
            ArgSpec.string("command" where default' = "")
          ])?
      _commands.update(_help_name, help_cmd)
    end

  fun name(): String =>
    """
    Returns the name of this command.
    """
    _name

  fun descr(): String =>
    """
    Returns the description for this command.
    """
    _descr

  fun options(): Map[String, OptionSpec] box =>
    """
    Returns a map by name of the named options of this command.
    """
    _options

  fun commands(): Map[String, CommandSpec box] box =>
    """
    Returns a map by name of the child commands of this command.
    """
    _commands

  fun args(): Array[ArgSpec] box =>
    """
    Returns an array of the positional arguments of this command.
    """
    _args

  fun is_leaf(): Bool => _type is _CommandSpecLeaf

  fun is_parent(): Bool => _type is _CommandSpecParent

  fun help_name(): String =>
    """
    Returns the name of the help command, which defaults to "help".
    """
    _help_name

  fun help_string(): String =>
    """
    Returns a formatted help string for this command and all of its arguments.
    """
    let s = _name.clone()
    s.append(" ")
    let args_iter = _args.values()
    for a in args_iter do
      s.append(a.help_string())
      if args_iter.has_next() then s.append(" ") end
    end
    s

class,
  args': Array[ArgSpec val] box = Array[ArgSpec]()) ?
  =>
    """
    Creates a command spec that can accept options and arguments, but not child
    commands.
    """
    _type = _CommandSpecLeaf
    _name = _assert_name(name')?
    _descr = descr'
    for o in options'.values() do
      _options.update(o.name(), o)
    end
    for a in args'.values() do
      _args.push(a)
    end

  fun tag _assert_name(nm: String): String ? =>
    for b in nm.values() do
      if (b != '-') and (b != '_') and
        not ((b >= '0') and (b <= '9')) and
        not ((b >= 'A') and (b <= 'Z')) and
        not ((b >= 'a') and (b <= 'z')) then
        error
      end
    end
    nm

  fun ref add_command(cmd: CommandSpec box) ? =>
    """
    Adds an additional child command to this parent command.
    """
    if is_leaf() then error end
    _commands.update(cmd.name(), cmd)

  fun ref add_help(hname: String = "help", descr': String = "") ? =>
    """
    Adds a standard help option and, optionally command, to a root command.
    """
    _help_name = hname
    _help_info = descr'
    let help_option = OptionSpec.bool(_help_name, _help_info, 'h', false)
    _options.update(_help_name, help_option)
    if is_parent() then
      let help_cmd =
        CommandSpec.leaf(
          _help_name,
          "",
          Array[OptionSpec](),
          [
            ArgSpec.string("command" where default' = "")
          ])?
      _commands.update(_help_name, help_cmd)
    end

  fun name(): String =>
    """
    Returns the name of this command.
    """
    _name

  fun descr(): String =>
    """
    Returns the description for this command.
    """
    _descr

  fun options(): Map[String, OptionSpec] box =>
    """
    Returns a map by name of the named options of this command.
    """
    _options

  fun commands(): Map[String, CommandSpec box] box =>
    """
    Returns a map by name of the child commands of this command.
    """
    _commands

  fun args(): Array[ArgSpec] box =>
    """
    Returns an array of the positional arguments of this command.
    """
    _args

  fun is_leaf(): Bool => _type is _CommandSpecLeaf

  fun is_parent(): Bool => _type is _CommandSpecParent

  fun help_name(): String =>
    """
    Returns the name of the help command, which defaults to "help".
    """
    _help_name

  fun help_string(): String =>
    """
    Returns a formatted help string for this command and all of its arguments.
    """
    let s = _name.clone()
    s.append(" ")
    let args_iter = _args.values()
    for a in args_iter do
      s.append(a.help_string())
      if args_iter.has_next() then s.append(" ") end
    end
    s

class val OptionSpec
  """
  OptionSpec describes the specification of a named Option. They have a name,
  descr(iption), a short-name, a typ(e), and a default value when they are not
  required.

  Options can be placed anywhere before or after commands, and can be thought
  of as named arguments.
  """
  let _name: String
  let _descr: String
  let _short: (U8 | None)
  let _typ: _ValueType
  let _default: _Value
  let _required: Bool

  fun tag _init(typ': _ValueType, default': (_Value | None))
    : (_ValueType, _Value, Bool)
  =>
    match \exhaustive\ default'
    | None => (typ', false, true)
    | let d: _Value => (typ', d, false)
    end

  new val bool(
    name': String,
    descr': String = "",
    short': (U8 | None) = None,
    default': (Bool | None) = None)
  =>
    """
    Creates an Option with a Bool typed value that can be used like
      `--opt` or `-O` or `--opt=true` or `-O=true`
    to yield an option value like
      `cmd.option("opt").bool() == true`.
    """
    _name = name'
    _descr = descr'
    _short = short'
    (_typ, _default, _required) = _init(_BoolType, default')

  new val string(
    name': String,
    descr': String = "",
    short': (U8 | None) = None,
    default': (String | None) = None)
  =>
    """
    Creates an Option with a String typed value that can be used like
      `--file=dir/filename` or `-F=dir/filename` or `-Fdir/filename`
    to yield an option value like
      `cmd.option("file").string() == "dir/filename"`.
    """
    _name = name'
    _descr = descr'
    _short = short'
    (_typ, _default, _required) = _init(_StringType, default')

  new val i64(name': String,
    descr': String = "",
    short': (U8 | None) = None,
    default': (I64 | None) = None)
  =>
    """
    Creates an Option with an I64 typed value that can be used like
      `--count=42 -C=42`
    to yield an option value like
      `cmd.option("count").i64() == I64(42)`.
    """
    _name = name'
    _descr = descr'
    _short = short'
    (_typ, _default, _required) = _init(_I64Type, default')

  new val u64(name': String,
    descr': String = "",
    short': (U8 | None) = None,
    default': (U64 | None) = None)
  =>
    """
    Creates an Option with an U64 typed value that can be used like
      `--count=47 -C=47`
    to yield an option value like
      `cmd.option("count").u64() == U64(47)`.
    """
    _name = name'
    _descr = descr'
    _short = short'
    (_typ, _default, _required) = _init(_U64Type, default')

  new val f64(name': String,
    descr': String = "",
    short': (U8 | None) = None,
    default': (F64 | None) = None)
  =>
    """
    Creates an Option with a F64 typed value that can be used like
      `--ratio=1.039` or `-R=1.039`
    to yield an option value like
      `cmd.option("ratio").f64() == F64(1.039)`.
    """
    _name = name'
    _descr = descr'
    _short = short'
    (_typ, _default, _required) = _init(_F64Type, default')

  new val string_seq(
    name': String,
    descr': String = "",
    short': (U8 | None) = None)
  =>
    """
    Creates an Option with a ReadSeq[String] typed value that can be used like
      `--files=file1 --files=files2 --files=files2`
    to yield a sequence of three strings equivalent to
      `cmd.option("ratio").string_seq() (equiv) ["file1"; "file2"; "file3"]`.
    """
    _name = name'
    _descr = descr'
    _short = short'
    (_typ, _default, _required) = _init(_StringSeqType, _StringSeq.empty())

  fun name(): String =>
    """
    Returns the name of this option.
    """
    _name

  fun descr(): String =>
    """
    Returns the description for this option.
    """
    _descr

  fun _typ_p(): _ValueType => _typ

  fun _default_p(): _Value => _default

  fun required(): Bool =>
    """
    Returns true iff this option is required to be present in the command line.
    """
    _required

  // Other than bools, all options require args.
  fun _requires_arg(): Bool =>
    match _typ
    | let _: _BoolType => false
    else
      true
    end

  // Used for bool options to get the true arg when option is present w/o arg
  fun _default_arg(): _Value =>
    match _typ
    | let _: _BoolType => true
    else
      false
    end

  fun _has_short(sh: U8): Bool =>
    match _short
    | let ss: U8 => sh == ss
    else
      false
    end

  fun help_string(): String =>
    """
    Returns a formatted help string for this option.
    """
    let s =
      match _short
      | let ss: U8 => "-" + String.from_utf32(ss.u32()) + ", "
      else
        "    "
      end
    s + "--" + _name +
      if not _required then "=" + _default.string() else "" end

  fun deb_string(): String =>
    "--" + _name + "[" + _typ.string() + "]" +
      if not _required then "(=" + _default.string() + ")" else "" end

class val ArgSpec
  """
  ArgSpec describes the specification of a positional Arg(ument). They have a
  name, descr(iption), a typ(e), and a default value when they are not
  required.

  Args always come after a leaf command, and are assigned in their positional
  order.
  """
  let _name: String
  let _descr: String
  let _typ: _ValueType
  let _default: _Value
  let _required: Bool

  fun tag _init(typ': _ValueType, default': (_Value | None))
    : (_ValueType, _Value, Bool)
  =>
    match \exhaustive\ default'
    | None => (typ', false, true)
    | let d: _Value => (typ', d, false)
    end)
: CommandSpec ref^ ?
```
#### Parameters

*   name': [String](builtin-String.md) val
*   descr': [String](builtin-String.md) val = ""
*   options': [Array](builtin-Array.md)\[[OptionSpec](cli-OptionSpec.md) val\] box = Array[OptionSpec](),
    args': Array[ArgSpec] box = Array[ArgSpec]()) ?
  =>
    """
    Creates a command spec that can accept options and arguments, but not child
    commands.
    """
    _type = _CommandSpecLeaf
    _name = _assert_name(name')?
    _descr = descr'
    for o in options'.values() do
      _options.update(o.name(), o)
    end
    for a in args'.values() do
      _args.push(a)
    end

  fun tag _assert_name(nm: String): String ? =>
    for b in nm.values() do
      if (b != '-') and (b != '_') and
        not ((b >= '0') and (b <= '9')) and
        not ((b >= 'A') and (b <= 'Z')) and
        not ((b >= 'a') and (b <= 'z')) then
        error
      end
    end
    nm

  fun ref add_command(cmd: CommandSpec box) ? =>
    """
    Adds an additional child command to this parent command.
    """
    if is_leaf() then error end
    _commands.update(cmd.name(), cmd)

  fun ref add_help(hname: String = "help", descr': String = "") ? =>
    """
    Adds a standard help option and, optionally command, to a root command.
    """
    _help_name = hname
    _help_info = descr'
    let help_option = OptionSpec.bool(_help_name, _help_info, 'h', false)
    _options.update(_help_name, help_option)
    if is_parent() then
      let help_cmd =
        CommandSpec.leaf(
          _help_name,
          "",
          Array[OptionSpec](),
          [
            ArgSpec.string("command" where default' = "")
          ])?
      _commands.update(_help_name, help_cmd)
    end

  fun name(): String =>
    """
    Returns the name of this command.
    """
    _name

  fun descr(): String =>
    """
    Returns the description for this command.
    """
    _descr

  fun options(): Map[String, OptionSpec] box =>
    """
    Returns a map by name of the named options of this command.
    """
    _options

  fun commands(): Map[String, CommandSpec box] box =>
    """
    Returns a map by name of the child commands of this command.
    """
    _commands

  fun args(): Array[ArgSpec] box =>
    """
    Returns an array of the positional arguments of this command.
    """
    _args

  fun is_leaf(): Bool => _type is _CommandSpecLeaf

  fun is_parent(): Bool => _type is _CommandSpecParent

  fun help_name(): String =>
    """
    Returns the name of the help command, which defaults to "help".
    """
    _help_name

  fun help_string(): String =>
    """
    Returns a formatted help string for this command and all of its arguments.
    """
    let s = _name.clone()
    s.append(" ")
    let args_iter = _args.values()
    for a in args_iter do
      s.append(a.help_string())
      if args_iter.has_next() then s.append(" ") end
    end
    s

class
*   args': [Array](builtin-Array.md)\[[ArgSpec](cli-ArgSpec.md) val\] box = Array[ArgSpec]()) ?
  =>
    """
    Creates a command spec that can accept options and arguments, but not child
    commands.
    """
    _type = _CommandSpecLeaf
    _name = _assert_name(name')?
    _descr = descr'
    for o in options'.values() do
      _options.update(o.name(), o)
    end
    for a in args'.values() do
      _args.push(a)
    end

  fun tag _assert_name(nm: String): String ? =>
    for b in nm.values() do
      if (b != '-') and (b != '_') and
        not ((b >= '0') and (b <= '9')) and
        not ((b >= 'A') and (b <= 'Z')) and
        not ((b >= 'a') and (b <= 'z')) then
        error
      end
    end
    nm

  fun ref add_command(cmd: CommandSpec box) ? =>
    """
    Adds an additional child command to this parent command.
    """
    if is_leaf() then error end
    _commands.update(cmd.name(), cmd)

  fun ref add_help(hname: String = "help", descr': String = "") ? =>
    """
    Adds a standard help option and, optionally command, to a root command.
    """
    _help_name = hname
    _help_info = descr'
    let help_option = OptionSpec.bool(_help_name, _help_info, 'h', false)
    _options.update(_help_name, help_option)
    if is_parent() then
      let help_cmd =
        CommandSpec.leaf(
          _help_name,
          "",
          Array[OptionSpec](),
          [
            ArgSpec.string("command" where default' = "")
          ])?
      _commands.update(_help_name, help_cmd)
    end

  fun name(): String =>
    """
    Returns the name of this command.
    """
    _name

  fun descr(): String =>
    """
    Returns the description for this command.
    """
    _descr

  fun options(): Map[String, OptionSpec] box =>
    """
    Returns a map by name of the named options of this command.
    """
    _options

  fun commands(): Map[String, CommandSpec box] box =>
    """
    Returns a map by name of the child commands of this command.
    """
    _commands

  fun args(): Array[ArgSpec] box =>
    """
    Returns an array of the positional arguments of this command.
    """
    _args

  fun is_leaf(): Bool => _type is _CommandSpecLeaf

  fun is_parent(): Bool => _type is _CommandSpecParent

  fun help_name(): String =>
    """
    Returns the name of the help command, which defaults to "help".
    """
    _help_name

  fun help_string(): String =>
    """
    Returns a formatted help string for this command and all of its arguments.
    """
    let s = _name.clone()
    s.append(" ")
    let args_iter = _args.values()
    for a in args_iter do
      s.append(a.help_string())
      if args_iter.has_next() then s.append(" ") end
    end
    s

class val OptionSpec
  """
  OptionSpec describes the specification of a named Option. They have a name,
  descr(iption), a short-name, a typ(e), and a default value when they are not
  required.

  Options can be placed anywhere before or after commands, and can be thought
  of as named arguments.
  """
  let _name: String
  let _descr: String
  let _short: (U8 | None)
  let _typ: _ValueType
  let _default: _Value
  let _required: Bool

  fun tag _init(typ': _ValueType, default': (_Value | None))
    : (_ValueType, _Value, Bool)
  =>
    match \exhaustive\ default'
    | None => (typ', false, true)
    | let d: _Value => (typ', d, false)
    end

  new val bool(
    name': String,
    descr': String = "",
    short': (U8 | None) = None,
    default': (Bool | None) = None)
  =>
    """
    Creates an Option with a Bool typed value that can be used like
      `--opt` or `-O` or `--opt=true` or `-O=true`
    to yield an option value like
      `cmd.option("opt").bool() == true`.
    """
    _name = name'
    _descr = descr'
    _short = short'
    (_typ, _default, _required) = _init(_BoolType, default')

  new val string(
    name': String,
    descr': String = "",
    short': (U8 | None) = None,
    default': (String | None) = None)
  =>
    """
    Creates an Option with a String typed value that can be used like
      `--file=dir/filename` or `-F=dir/filename` or `-Fdir/filename`
    to yield an option value like
      `cmd.option("file").string() == "dir/filename"`.
    """
    _name = name'
    _descr = descr'
    _short = short'
    (_typ, _default, _required) = _init(_StringType, default')

  new val i64(name': String,
    descr': String = "",
    short': (U8 | None) = None,
    default': (I64 | None) = None)
  =>
    """
    Creates an Option with an I64 typed value that can be used like
      `--count=42 -C=42`
    to yield an option value like
      `cmd.option("count").i64() == I64(42)`.
    """
    _name = name'
    _descr = descr'
    _short = short'
    (_typ, _default, _required) = _init(_I64Type, default')

  new val u64(name': String,
    descr': String = "",
    short': (U8 | None) = None,
    default': (U64 | None) = None)
  =>
    """
    Creates an Option with an U64 typed value that can be used like
      `--count=47 -C=47`
    to yield an option value like
      `cmd.option("count").u64() == U64(47)`.
    """
    _name = name'
    _descr = descr'
    _short = short'
    (_typ, _default, _required) = _init(_U64Type, default')

  new val f64(name': String,
    descr': String = "",
    short': (U8 | None) = None,
    default': (F64 | None) = None)
  =>
    """
    Creates an Option with a F64 typed value that can be used like
      `--ratio=1.039` or `-R=1.039`
    to yield an option value like
      `cmd.option("ratio").f64() == F64(1.039)`.
    """
    _name = name'
    _descr = descr'
    _short = short'
    (_typ, _default, _required) = _init(_F64Type, default')

  new val string_seq(
    name': String,
    descr': String = "",
    short': (U8 | None) = None)
  =>
    """
    Creates an Option with a ReadSeq[String] typed value that can be used like
      `--files=file1 --files=files2 --files=files2`
    to yield a sequence of three strings equivalent to
      `cmd.option("ratio").string_seq() (equiv) ["file1"; "file2"; "file3"]`.
    """
    _name = name'
    _descr = descr'
    _short = short'
    (_typ, _default, _required) = _init(_StringSeqType, _StringSeq.empty())

  fun name(): String =>
    """
    Returns the name of this option.
    """
    _name

  fun descr(): String =>
    """
    Returns the description for this option.
    """
    _descr

  fun _typ_p(): _ValueType => _typ

  fun _default_p(): _Value => _default

  fun required(): Bool =>
    """
    Returns true iff this option is required to be present in the command line.
    """
    _required

  // Other than bools, all options require args.
  fun _requires_arg(): Bool =>
    match _typ
    | let _: _BoolType => false
    else
      true
    end

  // Used for bool options to get the true arg when option is present w/o arg
  fun _default_arg(): _Value =>
    match _typ
    | let _: _BoolType => true
    else
      false
    end

  fun _has_short(sh: U8): Bool =>
    match _short
    | let ss: U8 => sh == ss
    else
      false
    end

  fun help_string(): String =>
    """
    Returns a formatted help string for this option.
    """
    let s =
      match _short
      | let ss: U8 => "-" + String.from_utf32(ss.u32()) + ", "
      else
        "    "
      end
    s + "--" + _name +
      if not _required then "=" + _default.string() else "" end

  fun deb_string(): String =>
    "--" + _name + "[" + _typ.string() + "]" +
      if not _required then "(=" + _default.string() + ")" else "" end

class val ArgSpec
  """
  ArgSpec describes the specification of a positional Arg(ument). They have a
  name, descr(iption), a typ(e), and a default value when they are not
  required.

  Args always come after a leaf command, and are assigned in their positional
  order.
  """
  let _name: String
  let _descr: String
  let _typ: _ValueType
  let _default: _Value
  let _required: Bool

  fun tag _init(typ': _ValueType, default': (_Value | None))
    : (_ValueType, _Value, Bool)
  =>
    match \exhaustive\ default'
    | None => (typ', false, true)
    | let d: _Value => (typ', d, false)
    end

#### Returns

* [CommandSpec](cli-CommandSpec.md) ref^ ?

---

## Public Functions

### add_command
<span class="source-link">[[Source]](src/cli/_value_type.md#L-0-83)</span>


Adds an additional child command to this parent command.


```pony
fun ref add_command(
  cmd: CommandSpec box)
: None val ?
```
#### Parameters

*   cmd: [CommandSpec](cli-CommandSpec.md) box

#### Returns

* [None](builtin-None.md) val ?

---

### add_help
<span class="source-link">[[Source]](src/cli/_value_type.md#L-0-90)</span>


Adds a standard help option and, optionally command, to a root command.


```pony
fun ref add_help(
  hname: String val = "help",
  descr': String val = "")
: None val ?
```
#### Parameters

*   hname: [String](builtin-String.md) val = "help"
*   descr': [String](builtin-String.md) val = ""

#### Returns

* [None](builtin-None.md) val ?

---

### name
<span class="source-link">[[Source]](src/cli/_value_type.md#L-0-110)</span>


Returns the name of this command.


```pony
fun box name()
: String val
```

#### Returns

* [String](builtin-String.md) val

---

### descr
<span class="source-link">[[Source]](src/cli/_value_type.md#L-0-116)</span>


Returns the description for this command.


```pony
fun box descr()
: String val
```

#### Returns

* [String](builtin-String.md) val

---

### options
<span class="source-link">[[Source]](src/cli/_value_type.md#L-0-122)</span>


Returns a map by name of the named options of this command.


```pony
fun box options()
: Map[String val, OptionSpec val] box
```

#### Returns

* [Map](collections-Map.md)\[[String](builtin-String.md) val, [OptionSpec](cli-OptionSpec.md) val\] box

---

### commands
<span class="source-link">[[Source]](src/cli/_value_type.md#L-0-128)</span>


Returns a map by name of the child commands of this command.


```pony
fun box commands()
: Map[String val, CommandSpec box] box
```

#### Returns

* [Map](collections-Map.md)\[[String](builtin-String.md) val, [CommandSpec](cli-CommandSpec.md) box\] box

---

### args
<span class="source-link">[[Source]](src/cli/_value_type.md#L-0-134)</span>


Returns an array of the positional arguments of this command.


```pony
fun box args()
: Array[ArgSpec val] box
```

#### Returns

* [Array](builtin-Array.md)\[[ArgSpec](cli-ArgSpec.md) val\] box

---

### is_leaf
<span class="source-link">[[Source]](src/cli/_value_type.md#L-0-140)</span>


```pony
fun box is_leaf()
: Bool val
```

#### Returns

* [Bool](builtin-Bool.md) val

---

### is_parent
<span class="source-link">[[Source]](src/cli/_value_type.md#L-0-142)</span>


```pony
fun box is_parent()
: Bool val
```

#### Returns

* [Bool](builtin-Bool.md) val

---

### help_name
<span class="source-link">[[Source]](src/cli/_value_type.md#L-0-144)</span>


Returns the name of the help command, which defaults to "help".


```pony
fun box help_name()
: String val
```

#### Returns

* [String](builtin-String.md) val

---

### help_string
<span class="source-link">[[Source]](src/cli/_value_type.md#L-0-150)</span>


Returns a formatted help string for this command and all of its arguments.


```pony
fun box help_string()
: String val
```

#### Returns

* [String](builtin-String.md) val

---

