解析docopt参数类型(任何语言)

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.