Climb is a simple Rust crate for creating CLI applications. Allows creating commands that accept inputs, options, and optional inputs. Climb handles all input argument validation and parsing and guarantees that only the correct number of inputs and only valid options are passed into your commands. Climb will also generate help menus for your application and commands.
Climb follows the builder pattern for creating applications.
Let's say you want to make a simple calculator application with two commands:
add
- Takes in two numbers, adds them, and returns the resultdiv
- Takes in two numbers, divides them, and returns the result
In your main.rs
file, first create a basic Climb application with the create_app
macro:
use climb::*;
fn main() {
let calc_app = create_app!();
let _ = calc_app.run();
}
Call the run
function to run your application with the command line arguments. Don't
worry about the return value of this for now.
The create_app
macro will create a default application with its name, description,
and version pulled from your crate's cargo.toml file.
If you wanted to change these values you can:
let mut calc_app = create_app!();
calc_app = calc_app.name("cool_calc");
calc_app = calc_app.desc("This app does some cool math");
calc_app = calc_app.version("1.0.0");
Or chain the commands to make everything easier to read:
let _ = create_app!()
.name("cool_calc")
.desc("This app does some cool math")
.version("1.0.0")
.run();
If you run our code right now, this is what you get:
$ cool_calc
This app does some cool math
USAGE:
cool_calc [OPTIONS] [COMMAND]
OPTIONS:
-h, --help Print help information
-v, --version Print version
COMMANDS:
Run `cool_calc [COMMAND] --help` to see help information for a specific command
Climb created the application and added a few default options: help
and version
. To add more functionality to the application, you need to make use of Climb commands.
To add the two commands to the app, you can use the app::command
API. When you call the app::command
function, you have to pass in a command struct. You can use Command::new
:
let _ = create_app!()
.name("cool_calc")
.desc("This app does some cool math")
.version("1.0.0")
.command(
Command::new(
"add",
"Add two numbers",
add_fn
)
.arg("number_a")
.arg("number_b")
)
.command(
Command::new(
"div",
"Divide two numbers",
div_fn
)
.arg("number_a")
.arg("number_b")
.option(
CommandOption::new(
"round",
"Round the result"
)
)
)
.run();
The Command::new
function takes in the command name and description as arguments. It also takes in a function that will be called when the command is executed. We haven't created definitions for these functions yet; the next section describes how to create these functions.
We're also using the Command
API to add arguments and options to the commands. We've added two arguments to each command number_a
and number_b
. These will be the two numbers that the commands will operate on. We also added an option to the div
command: round
. If this option is added, the command should return a rounded result.
To add the add
and div
commands to the calculator application, you need to make the functions that these commands will actually execute. It's inside these functions that you can put the logic of the command.
Climb functions follow the CommandFunction
signature. It looks like this:
type CommandFunction = fn(FunctionInput, FunctionOptions) -> FunctionResult;
The arguments and return type are defined as:
type FunctionInput = Vec<String>;
type FunctionOptions = Vec<FunctionOption>;
type FunctionResult = Result<Option<String>, String>;
It might look intimidating, but it's actually pretty simple. FunctionInput
stores the input to our function (these are called arguments), FunctionOptions
stores any options that our command takes. Options can also have arguments. FunctionResult
is the standard result type that all Climb commands must return. The results of running your functions are always returned from the App::run()
command that was used earlier.
Let's start with making the function for the add
command. Climb functions are guaranteed to have the correct number of arguments passed into them, so you can safely assume that there are the 2 arguments passed in. If you added any options to your command, only these valid options can ever be passed into your functions:
fn add_fn(input: FunctionInput, _: FunctionOptions) -> FunctionResult {
let num_a: i32 = input.get(0).unwrap().parse().unwrap();
let num_b: i32 = input.get(1).unwrap().parse().unwrap();
let result = num_a + num_b;
println!("{}", result);
Ok(None)
}
We first unwrap the two inputs and convert them to integers. Then add them and print the result. You could return the result from the function wrapped as Ok(Some(<result>))
, but instead we're just gonna return Ok(None)
and just print the result from inside the function.
For the div
function:
fn div_fn(input: FunctionInput, options: FunctionOptions) -> FunctionResult {
let num_a: f32 = input.get(0).unwrap().parse().unwrap();
let num_b: f32 = input.get(1).unwrap().parse().unwrap();
let mut result = num_a / num_b;
if options.contains(&FunctionOption(String::from("--round"), None)) {
result = result.round();
}
println!("{}", result);
Ok(None)
}
Just like before, we can unwrap the first two inputs. The division result is stored in the result
variable and is printed to the console. We also check if the --round
option is passed into the command and round the result if it is. There are many ways of doing this, but this is just one example.
If you run the application now with no arguments, this is what you get:
$ cool_calc
This app does some cool math
USAGE:
cool_calc [OPTIONS] [COMMAND]
OPTIONS:
-h, --help Print help information
-v, --version Print version
COMMANDS:
add Add two numbers
div Divide two numbers
Run `cool_calc [COMMAND] --help` to see help information for a specific command
The two commands are listed there: add
and div
. You can try running the command: div --help
to see a help menu for just the div
command:
$ cool_calc div --help
Divide two numbers
USAGE:
cool_calc div [OPTIONS] <NUMBER_A> <NUMBER_B>
ARGS:
<NUMBER_A>
<NUMBER_B>
OPTIONS:
-h, --help Print help information
--round Round the result
Finally, we can run the commands to test that they work:
$ cool_calc add 45 22
67
$ cool_calc div 45 22
2.0454545
$ cool_calc div --round 45 22
2