kex docs Standard Library 0.4.0-alpha kex.run ↗

OptionParser

type OptionKind

Declarative command-line parsing, shared by Kex tools and applications.

You describe the options and commands a tool accepts, and the parser turns an argument list into typed values, dispatches to the right command, and renders the help text.

foul greet(options: ParsedOptions) -> Integer do
  IO.printLine("hello, ${options.value("name", "world")}")
  return 0
end

main(args) do
  let cli = OptionParser.define("demo", "a small demo tool")
    .string("name", Just('n'), "who to greet", Just("world"), false)
    .flag("help", Just('h'), "show this help")
    .command("greet", "", "print a greeting", ~greet)
  System.exit(cli.run(args))
end

$ demo greet --name Ada
hello, Ada

Note that --help is not automatic: run shows the help when a flag named help is set, so declare that flag if you want it.

Start at OptionParser.define, chain the string / integer / flag / command builders, and finish with run (dispatch and exit code) or parse (the parsed values, and nothing else).

What kind of value an option carries: StringValue takes any text, IntegerValue must parse as a number, and FlagValue takes none at all and reads as "true" when present.

Variants

  • StringValue
  • IntegerValue
  • FlagValue

record OptionSpec

One declared option. Built for you by the OptionConfig builders: you rarely construct one by hand.

Fields

long
String
short
Char? optional
kind
OptionKind optional
description
String optional
default
String? optional
required?
Bool optional

type CommandHandler

What a command does once the line has been parsed. It receives the parsed options with the command's own words already removed, so tey add greet hands its handler ["greet"], and returns the process exit code.

Variants

  • abstract

record CommandSpec

One declared command. Built for you by the OptionConfig.command builders.

Fields

name
String
description
String optional
usage
String optional
section
String optional

record OptionConfig

A tool's whole command-line interface: its name, its options, and its commands.

Build one with OptionParser.define and add to it with the chainable string, integer, flag and command methods. Each returns a new OptionConfig, so the chain reads as one declaration.

Fields

name
String optional
description
String optional
options
[OptionSpec] optional
commands
[CommandSpec] optional

record ParsedOptions

The result of a successful parse: the option values, and the words that were not options.

Fields

values
{String: String}
arguments
[String]

type OptionParseError

Why a command line could not be parsed.

OptionParser.errorMessage turns one into a sentence for the user; OptionConfig.run does that for you.

Variants

  • UnknownOption(String)
  • MissingValue(String)
  • UnexpectedValue(String)
  • MissingRequired(String)
  • InvalidInteger(String, String)

make ParsedOptions

value

Returns the value given for the option named name, or None when it was neither supplied nor defaulted.

value(name)
Parameters
name String
the option's long name, without dashes

Returns: String? — the value, or None

Examples
options.value("name")     # => Just("Ada")
options.value("missing")  # => None

flagEnabled?

Returns true when the flag named name was given.

flagEnabled?(name)
Parameters
name String
the flag's long name, without dashes

Returns: Booltrue when the flag is set

Examples
if options.flagEnabled?("verbose")
  IO.printLine("verbose mode")
end

integerValue

Returns the value of an integer option as an Integer, or None when it is absent or does not parse.

An option declared with integer has already been checked at parse time, so None here means absent rather than malformed.

integerValue(name)
Parameters
name String
the option's long name, without dashes

Returns: Integer? — the number, or None

Examples
let times = options.integerValue("times").or(1)

make OptionConfig

string

Declares an option that takes a text value.

string(long, short, description, default, required?)
Parameters
long String
the long spelling, without dashes
short Char?
an optional one-character spelling
description String
the help-text description
default String?
the value used when the option is absent
required? Bool
whether the option must be given

Returns: OptionConfig — the config, with the option added

Examples
OptionParser.define("demo", "a small demo tool")
  .string("name", Just('n'), "who to greet", Just("world"), false)

An option the tool cannot run without

config.string("output", Just('o'), "where to write", None, true)

integer

Declares an option that takes a whole number.

A value that does not parse is rejected at parse time with InvalidInteger, so a handler never sees a malformed number. Read it back with ParsedOptions.integerValue.

integer(long, short, description, default, required?)
Parameters
long String
the long spelling, without dashes
short Char?
an optional one-character spelling
description String
the help-text description
default String?
the value used when the option is absent
required? Bool
whether the option must be given

Returns: OptionConfig — the config, with the option added

Examples
config.integer("port", Just('p'), "port to listen on", Just("8080"), false)

flag

Declares an option that takes no value and is either present or not.

It defaults to "false" and reads as "true" when given. Read it back with ParsedOptions.flagEnabled?. Giving it a value is an error (UnexpectedValue).

Declare a flag named help if you want --help to print the help text: run looks for exactly that name, and adds nothing on its own.

flag(long, short, description)
Parameters
long String
the long spelling, without dashes
short Char?
an optional one-character spelling
description String
the help-text description

Returns: OptionConfig — the config, with the flag added

Examples
config
  .flag("verbose", Just('v'), "print more detail")
  .flag("help", Just('h'), "show this help")

command

Declares a command and the function that runs it.

A command name may be several words ("docs build") and the longest match wins, so a group and its subcommands can both be declared. The handler receives the parsed options with the command's own words already removed, and returns the process exit code.

Declares a command. usage is what the help line shows after the name (<name>, [args...]); leave it empty for a command that takes none.

command(name, description, handler)
Parameters
name String
the command's name, one or more words
description String
the help-text description
handler CommandHandler
what to run

Returns: OptionConfig — the config, with the command added

Examples
foul greet(options: ParsedOptions) -> Integer do
  IO.printLine("hello, ${options.value("name", "world")}")
  return 0
end

config.command("greet", "print a greeting", ~greet)

parse

Parses args into option values and leftover words, without dispatching to a command.

Use it when the tool has no commands, or when you want to inspect the parse before deciding what to do. run is the one-call alternative.

parse(args)
Parameters
args [String]
the command-line arguments

Returns: Result<ParsedOptions, OptionParseError> — the parse, or why it failed

Examples
match config.parse(args) do
  Ok(options) => IO.printLine(options.value("name", "world"))
  Error(e)    => IO.printError(OptionParser.errorMessage(e))
end

run

Parses args, runs the command they name, and returns its exit code.

This is the whole of a tool's main: hand it the argument list and pass the result to System.exit.

A parse failure, an unknown command, or a line with no command at all reports the problem along with the help text and returns 1: the one place that policy has to live for every tool to behave the same way. A set help flag prints the help and returns 0.

run(args)
Parameters
args [String]
the command-line arguments

Returns: Integer — the exit code to give the shell

Examples
main(args) do
  let cli = OptionParser.define("demo", "a small demo tool")
    .flag("help", Just('h'), "show this help")
    .command("greet", "", "print a greeting", ~greet)
  System.exit(cli.run(args))
end

printHelp

Prints the help text and returns 0, the exit code for a successful run.

run calls this for you when the help flag is set; call it directly when a tool decides on its own that help is the right answer.

printHelp()

Returns: Integer — always 0

Examples

A tool with no arguments shows its help

args.empty? then cli.printHelp else cli.run(args)

module OptionParser

function define

Starts an immutable command-line interface definition.

Chain options and commands onto the returned OptionConfig, then call parse with the process arguments. name appears in usage text and description introduces the generated help page.

define(name, description)
Parameters
name String
the executable name shown in usage
description String
the one-line purpose of the command

Returns: OptionConfig — an empty parser configuration

Examples

Defining a small file-conversion command

let cli = OptionParser.define("convert", "Convert a document to PDF")
  .string("input", Just('i'), "Source document", None, true)
  .flag("verbose", Just('v'), "Show conversion details")

function commandLabel

Returns the label a command is listed under in the help text: its name, followed by its usage when it has one.

commandLabel(command)
Parameters
command CommandSpec
the command to label

Returns: String — the help-text label

Examples
OptionParser.commandLabel(spec)   # => "build <file>"

function commandFor

Finds the declared command whose words open arguments, and returns it with whatever is left after them.

Longest match first, so "kex install" is preferred over a "kex" that also exists. Answers None when no command matches.

commandFor(commands, arguments)
Parameters
commands [CommandSpec]
the declared commands
arguments [String]
the positional words from the command line

Returns: (CommandSpec, [String])? — the command and the remaining words

Examples
OptionParser.commandFor(commands, ["docs", "build", "src"])
# => Just((docsBuildSpec, ["src"]))

function opensWith?

Returns true when arguments begins with the words of name.

The word-wise prefix test commandFor matches with: "docs build" opens ["docs", "build", "src"] but not ["docs"].

opensWith?(arguments, name)
Parameters
arguments [String]
the positional words from the command line
name String
the command name, one or more words

Returns: Booltrue when the words match at the front

Examples
OptionParser.opensWith?(["docs", "build"], "docs")   # => true
OptionParser.opensWith?(["docs"], "docs build")      # => false

function errorMessage

Renders a parse error as a sentence for the user.

OptionConfig.run does this for you; call it directly when handling a parse result yourself.

errorMessage(error)
Parameters
error OptionParseError
the failure to describe

Returns: String — the message to show

Examples
OptionParser.errorMessage(UnknownOption("--nope"))
# => "unknown option '--nope'"
OptionParser.errorMessage(MissingValue("output"))
# => "--output requires a value"

function parse

Parses args against a list of option and command specs.

The engine behind OptionConfig.parse, which is the form to call from ordinary code.

parse(options, commands, args)
Parameters
options [OptionSpec]
the declared options
commands [CommandSpec]
the declared commands
args [String]
the command-line arguments

Returns: Result<ParsedOptions, OptionParseError> — the parse, or why it failed