rarg
v0.6.3
Published
A simple, focused and expressive library for building command line applications. Optimised for native ReasonML/OCaml.
Downloads
62
Maintainers
Readme
A simple, focused and expressive library for building command line applications. Optimised for native ReasonML/OCaml.
Features
- autocompletion - fast and comprehensive autocompletion of commands, arguments and values
- sync and async commands support
- sub commands - you can easily define a whole tree of commands and compose them
- auto configuration validation - you can validate your whole commands tree configuration with a single function call in your tests
- auto help generation
- autocorrection
API Reference
Note that the only external modules are:
Usage
- To add to your esy project simply use:
esy add rarg
- Define command arguments with Args.
module Args = Rarg.Args;
module Type = Rarg.Type;
module MyCmd = {
let args = []
let (args, getCopy) = Args.One.boolFlag(
~args,
~name="--copy",
~doc="Whether to copy",
Type.bool,
);
let (args, getColor) =
Args.One.default(
~args,
~name="--color",
~doc="Paint color",
~default="green",
Type.string,
);
// ...
};
For the Type argument you can either choose one of the predefined argument types or define custom argument types, for example:
// ...
type fruit = | Apple | Banana;
let fruit: Type.t(fruit) = {
name: "fruit",
parse:
fun
| "apple" => Ok(Apple)
| "banana" => Ok(Banana)
| x => Error(Some(x ++ " is not a fruit.")),
stringify:
fun
| Apple => "apple"
| Banana => "banana",
choices: Some(HelpAndSuggestions([Apple, Banana])),
};
let (args, getFruits) = Args.Many.req(~args, ~name="--fruits", ~doc="Fruits", fruit);
// ...
- Define the command with Cmd:
// ...
// Define the function that you want to execute
let handle = (~fruits: list(fruit), ~copy: bool, ~color: string) => ();
// Define a mapping function that will use the getters returned from `Args`
// and pass the provided user arguments.
// It allows you to use labeled arguments as opposed to relying on arg positions.
let run = m => handle(~fruits=getFruits(m), ~copy=getCopy(m), ~color=getColor(m));
// Define a command record that you can use to run your command,
// pass it as a child to other commands or test it
let cmd: Cmd.t(unit) = Cmd.make(~name="My Command", ~version="1.0", ~args, ~run, ());
} // module MyCmd close
You can also easily define sub commands:
module AnotherCmd = {
// ...
let cmd: Cmd.t(unit) =
Cmd.make(
~name="Another Command",
~version="1.0",
~args,
~run,
~children=[("my-cmd", MyCmd.cmd)],
(),
);
};
In
rarg
every command/subcommand is a complete unit of work, that can exist on its own, has no dependencies of its parents. That's why every command has its own version.
- And finally you can run your command with Run
let main = {
switch (Run.autorun(MyCmd.cmd)) {
| Ok(_) => exit(0)
| Error(_) => exit(1)
};
};
System arguments (auto-included)
--help
- display command help--version
- display command version--rarg-suggestions-script
- displays a script with instsructions how to install it to enable shell autocompletions--rarg-add-path
- displays a script with instructions how to add the app executable to the user's path (helpful during development)
Examples
You can check the local examples or the repo rarg-examples for more complete examples.
Comparison with cmdliner
This was the most requested comparison and is added for completeness, but the 2 are very different.
cmdliner
is hosted onopam
|rarg
onnpm
- it's likely that you would be more familiar with
cmdliner
's API if you have anOCaml
background and withrarg
's API if you are coming from other languages (includingJS
) cmdliner
is very mature and has a large ecosystem behind itrarg
has autocompletions, smaller API footprint, validation, composable commands and is simpler and less abstract in nature
Notes
All commands must follow the following structure:
command [..sub-commands] [..positionals] [..options]
The main command
, optionally followed by sub-commands
, then optional positionals
and finally options
(like --foo
).
Options always come last and cannot be between subcommands and positionals.
This consistent structure allows for more relevant autocomplete functionality and predictable options value parsing.