A command-line arrrrguments parser, written in Rust.
Most programs that provide a command-line interface use a special-purpose library to make the process easier, such as the GNU Project's getopt
library. The Rust team provides their own alternative, getoptions
, which deserves an award for the Most Originally Named Project Ever.
In all seriousness, getoptions
is a fantastic library that gives the developers all of the power necessary to create and interface with command-line arguments. However, with all that power comes complexity. getoptions
-- while straight forward to use -- is verbose. The developer has to call different functions repeatedly in order to add different command-line options to their programs. While the only victim here is the developer's wrists due to carpal tunnel, I felt that there was a
better way to do things.
Enter Pirate (which should totally usurp getoptions
for the award of Most Originally Named Project Ever).
Add this to your project's Cargo.toml
file:
[dependencies]
pirate = "1.0.0"
and this to your crate root:
rust
extern crate pirate;
Using Pirate is simple. First, create a vector defining all of the valid options that your program accepts:
rust
let options = vec![
"a/addend#The right side of the addition equation; default=1:",
"#Required Arguments",
":augend#The left side of an addition equation"
];
Options are defined in a very specific format:
"/addend"
.":augend"
.--help
flag is passed). Options with only a description (i.e. no short- or long-form name) are called "Groups", and are used to group options together when displaying usage.Next, create a Vars
struct, which is responsible for keeping track of all of the options, along with the program's name, defined for the program:
rust
let vars: Vars = match pirate::vars("program-name", &options) {
Ok(v) => v,
Err(why) => panic!("Error: {}", why)
}
Next, call the pirate::matches()
function, passing in a vector of the program's environment arguments, along with a mutable reference to the Vars
struct that you previously defined:
rust
let matches: Matches = match pirate::matches(env::args().collect(),
&mut vars) {
Ok(m) => m,
Err(why) => {
println!("Error: {}", why);
pirate::usage(&vars);
return;
}
}
Matches
is nothing more than a type alias to a HashMap<String, String>
. All of the custom methods that make the type easier to use are defined by the Match
trait.
And finally, check which arguments were passed to the program.
``` // Returns a reference to the given arg, or None if not found fn get(arg: &str) -> Option<&String>;
// Returns true if the match exists, false if not fn has_match(arg: &str) -> bool;
// An iterator over all matches found
fn keys() -> Keys
Something to remember when using the get()
function: by default, the pirate::matches()
function stores the opt's long-form name as the key, by default, should the long-form exist; otherwise the short-form is used. So, should you define an opt with both a short- and long-form name, when querying for it, pass the long-form as the argument. For example:
```rust let options = vec!["l/long#An example opt"]; let vars = pirate::vars("program-name", &options); let matches = pirate::matches(&env::args().collect(), &mut vars).unwrap();
let short = matches.get("l").unwrap(); // Error! This won't work! let long = matches.get("long").unwrap(); // Success!
// Usage: program-name -l ```
As shown in a previous example, should you ever want to display the program's usage data, simply call the pirate::usage()
function, passing in a reverence to your Vars
struct as an argument. E.g. pirate::usage(&vars)
Here is a trivial example that gives a general idea about how to use pirate
:
```rust extern crate pirate;
use pirate::{Matches, Match, matches, usage, vars};
fn main() {
let env_args: Vec
let matches: Matches = match matches(&env_args, &mut vars) {
Ok(m) => m,
Err(why) => {
println!("Error: {}", why);
usage(&vars);
return;
}
};
if matches.has_match("help") {
usage(&vars);
return;
}
let augend: i32 = matches.get("augend")
.unwrap()
.parse::<i32>()
.unwrap();
let addend: i32 = match matches.get("addend") {
Some(a) => a.parse::<i32>().unwrap(),
None => 1
};
let sum = augend + addend;
println!("{} + {} = {}", augend, addend, sum);
} ```
Pirate is licensed under the GNU Lesser General Public License, v3.