I have a use case where users provide a docopt string, and based on it, I generate some code. So I do not know my docopt string up front.
For certain "argument types" (not datatypes), I wish to generate various code.
In the following, I will distinguish between "types" and "datatypes". For the docopt argument --arg=DEGREES
and the argv input --arg=10
, the "type" of --arg
is DEGREES
, while the datatype is integer
. The value is 10
.
A user may give me the following docopt string:
Naval Fate.
Usage:
naval_fate --dir=FILE [--speed=ABC]
Options:
--dir=FILE Moored (anchored) mine.
--speed=ABC Speed in knots [default: 10].
Besides parsing this docopt string as usual, I'm trying to also figure out what "type" of argument dir
and speed
asks for. I want to know that dir
is of type FILE
and speed
is of type ABC
.
Example:
Given the above docopt string, and an argv string naval_fate --dir=/tmp --speed 1234
, I hope to access not just the value and datatype (<key> => <value,datatype>
), but also the "config type" (<key> => <value,datatype,argtype>
, i.e. something along the lines of:
dir
=> val: /tmp
, datatype: String
, type: FILE
speed
=> val: 1234
, datatype: Integer
, type: ABC
Any (managed) implementation of docopt is acceptable, including Python's, though preferably I'm looking for a solution in a compiled language, be it C, Go, Rust etc.
This is pretty easy with Rust's Docopt:
#![allow(unstable)]
extern crate docopt;
use docopt::Docopt;
static USAGE: &'static str = "
Naval Fate.
Usage:
naval_fate ship --dir=FILE [--speed <kn>]
naval_fate (-h | --help)
Options:
-h --help Show this screen.
--speed <kn> Speed in knots [default: 10].
--dir=FILE Moored (anchored) mine.
";
fn main() {
let args = Docopt::new(USAGE)
.and_then(|d| d.parse())
.unwrap_or_else(|e| e.exit());
println!("Type of 'ship': {:?}", args.find("ship"));
println!("Type of '--dir': {:?}", args.find("--dir"));
println!("Type of '--speed': {:?}", args.find("--speed"));
}
Which outputs:
$ ./target/scratch ship --dir /tmp --speed 1234
Type of 'ship': Some(Switch(true))
Type of '--dir': Some(Plain(Some("/tmp")))
Type of '--speed': Some(Plain(Some("1234")))
The key is that the return type of find
is Value
, which is an algebraic data type: http://burntsushi.net/rustdoc/docopt/enum.Value.html --- So by construction, you get the "type" of the argument for free.
Note that this will work for any "argument" in the Docopt usage string, even if it isn't passed into the argument list.