Docopt for Rust with automatic type based decoding (i.e., data validation). This implementation conforms to the official description of Docopt and passes its test suite.
Licensed under the UNLICENSE.
Fully functional but the design of the API is up for debate. I am seeking feedback.
http://burntsushi.net/rustdoc/docopt
There are several examples and most things are documented, but not quite well enough yet.
This crate is fully compatible with Cargo. Just add it to your Cargo.toml
:
[dependencies.docopt_macros]
git = "git://github.com/docopt/docopt.rs"
If you don't want to use the macro, then you can change your entry to
dependencies.docopt
.
Here is a full working example:
#![feature(phase)]
extern crate serialize;
#[phase(plugin)] extern crate docopt_macros;
extern crate docopt;
use docopt::FlagParser;
docopt!(Args deriving Show, "
Usage: cp [-a] SOURCE DEST
cp [-a] SOURCE... DIR
Options:
-a, --archive Copy everything.
")
fn main() {
let args: Args = FlagParser::parse().unwrap_or_else(|e| e.exit());
// The Args struct satisfies `Show` because of the `deriving Show`.
println!("{}", args);
// Try running with `example -a file1 file2 dest/`.
assert!(args.flag_archive);
assert_eq!(args.arg_SOURCE, vec!["file1".to_string(), "file2".to_string()]);
assert_eq!(args.arg_DIR, "dest/".to_string());
}
The docopt!
macro will create a struct for you! The field names map like
this:
-g => flag_g
--group => flag_group
FILE => arg_FILE
<file> => arg_file
build => cmd_build
The Args
struct has three static methods defined for it: parse
,
parse_conf
and parse_args
. These correspond to the module functions
docopt,
docopt_conf
and docopt_args
respectively. (The only difference is that the parse_*
methods don't
take a Docopt string.)
Here's another example that shows how to specify the types of your arguments:
#![feature(phase)]
extern crate serialize;
#[phase(plugin)] extern crate docopt_macros;
extern crate docopt;
use docopt::FlagParser;
docopt!(Args deriving Show, "Usage: add <x> <y>", arg_x: int, arg_y: int)
fn main() {
let args: Args = FlagParser::parse().unwrap_or_else(|e| e.exit());
println!("x: {:d}, y: {:d}", args.arg_x, args.arg_y);
}
In this example, specific type annotations were added. They will be
automatically inserted into the generated struct. You can override as many (or
as few) fields as you want. If you don't specify a type, then one of bool
,
uint
, String
or Vec<String>
will be chosen depending on the type of
argument. In this case, both arg_x
and arg_y
would have been String
.
If any value cannot be decoded into a value with the right type, then an error will be shown to the user.
Here's a selected subset for some of rustc
's options. This also shows how to
restrict values to a list of choices via an enum
type.
#![feature(phase)]
extern crate serialize;
#[phase(plugin)] extern crate docopt_macros;
extern crate docopt;
use docopt::FlagParser;
docopt!(Args deriving Show, "
Usage: rustc [options] [--cfg SPEC... -L PATH...] INPUT
rustc (--help | --version)
Options:
-h, --help Show this message.
--version Show the version of rustc.
--cfg SPEC Configure the compilation environment.
-L PATH Add a directory to the library search path.
--emit TYPE Configure the output that rustc will produce.
Valid values: asm, ir, bc, obj, link.
--opt-level LEVEL Optimize with possible levels 0-3.
", flag_opt_level: Option<OptLevel>, flag_emit: Option<Emit>)
#[deriving(Decodable, Show)]
enum Emit { Asm, Ir, Bc, Obj, Link }
#[deriving(Show)]
enum OptLevel { Zero, One, Two, Three }
impl<E, D: serialize::Decoder<E>> serialize::Decodable<D, E> for OptLevel {
fn decode(d: &mut D) -> Result<OptLevel, E> {
Ok(match try!(d.read_uint()) {
0 => Zero, 1 => One, 2 => Two, 3 => Three,
n => {
let err = format!("Could not decode '{}' as opt-level.", n);
return Err(d.error(err.as_slice()));
}
})
}
}
fn main() {
let args: Args = FlagParser::parse().unwrap_or_else(|e| e.exit());
println!("{}", args);
}
Generating a struct is pretty magical, but if you want, you can look at it by
expanding all macros. Say you wrote the above example for Usage: add <x> <y>
into a file called add.rs
. Then running:
rustc -L path/containing/docopt/lib --pretty expanded add.rs
Will show all macros expanded. In the generated code, you should be able to find the generated struct:
struct Args {
pub arg_x: int,
pub arg_y: int,
}