An opts Group stores a set of options and provides methods to define and parse
them. NewGroup creates an empty group. The parameter passed to NewGroup
becomes the *Group.Name.
Options (aka, flags) are added to a Group by calling type-specific methods on
the Group. These methods come in two forms: long and short. The long versions
take three arguments: a pointer to store the value, a name, and a default value.
The short versions take only the pointer and name arguments since they default
to the zero value for that type. E.g., *Group.StringZero defaults to "" and
*Group.IntZero defaults to 0. Boolean options are an exception: they always
default to false. Thus, there is only *Group.Bool for boolean options.
Valid option names must not be empty, must not begin with "-", and must not contain whitespace, control characters, quotes, backslashes, or equal signs. Option definition methods will panic if a name is invalid.
After all options are defined, a call to *Group.Parse or *Group.ParseAll
will attempt to assign values to options. These methods take a slice of strings
as an argument. This slice should contain everything on the command line other
than the name of the program. In other words, users should usually pass
os.Args[1:], or its equivalent, to Parse or ParseAll.
The parsing methods will return an error if a user passes an unknown option, if an option is missing a value, or if a value cannot be parsed as its type. If a parsing method returns without error, then the variables associated with options are ready for use.
Parsing stops at the first non-option argument. If there are leftover positional
arguments after parsing stops, Parse returns them. On the other hand,
ParseAll returns *UnexpectedArgumentsError if there are leftover positional
arguments after parsing stops. Leftover positional arguments are stored as
*UnexpectedArgumentsError.Args so the caller can inspect or display them.
As a usage example, imagine a tool that validates and optionally corrects the case conventions in one or more files.
og := opts.NewGroup("caser")
cfg := struct {
rcfile string
convention string
strictness uint
verbosity uint
dryRun bool
write bool
}{}
og.String(&cfg.rcfile, "rcfile", "caser.ini")
og.String(&cfg.convention, "convention", "camel")
og.Uint(&cfg.strictness, "strictness", 3)
og.UintZero(&cfg.verbosity, "verbosity")
og.Bool(&cfg.dryRun, "dry-run")
og.Bool(&cfg.write, "write")
// Later...
fileNames, err := og.Parse(os.Args[1:])
if err != nil {
// Handle the error.
}
// No error? The values in cfg are safe to use and fileNames contains everything
// left of os.Args[1:] after parsing stopped.The syntax for options is largely the same as for Go's flag library.
-option // one dash is accepted
--option // two dashes are accepted
-option=x // non-boolean flags only
-option x // non-boolean flags onlyOn the command line, options can begin with one or two dashes; they are
equivalent during parsing. As such, there is no distinction between long and
short options. This means there is no way to stack options. That is, -abc is
always read as one option, named "abc", rather than -a -b -c. Boolean options
do not accept arguments; they are switches. All boolean options are initially
false. If a boolean option is present on the command line, the option's value is
set to true.
Although the library does not distinguish long from short options when parsing, it can provide users a short and a long option for use on the command line or in scripts.
cfg := struct {
helpWanted bool
versionWanted bool
}{}
og.Bool(&cfg.helpWanted, "help")
og.Bool(&cfg.helpWanted, "h")
og.Bool(&cfg.versionWanted, "version")
og.Bool(&cfg.versionWanted, "V")Here are some of the key ways that this library is opinionated.
- Single dash and double dash are identical. When parsing arguments, the library
treats, e.g.,
-helpand--helpas if they were identical. (In this way, the library followsflagin Go's standard library.) - No (traditional) short options and no automatic binding of long and short
options. The library does not distinguish traditional short options (preceded
by a single dash, always one letter, and stackable) from traditional long
options (preceded by two dashes, more than one letter, and not stackable).
Although users can bind two options to one variable, the library does not
provide methods that take two options at once and bind them to the same
variable. (Again, this is like Go's
flaglibrary.) - No automatic usage. Although most option parsing libraries provide ways to
generate formatted help messages,
optsdoes not. It's more work to write help messages by hand, but I think the results can be worth it. - Booleans always default to false, and they never accept arguments. They function only as switches: if a boolean option appears on the command line, its value becomes true.
- Options with numeric types are decimal only: opts rejects hex, octal, underscores, NaN, and Inf.
- Types are limited. The library provides options for the following types: boolean, date (using civil.Date), duration, float64, int, string, and uint. Users cannot extend the types.