Coder Social home page Coder Social logo

tetsuharuohzeki / docopt.rs Goto Github PK

View Code? Open in Web Editor NEW

This project forked from docopt/docopt.rs

0.0 1.0 0.0 467 KB

Docopt for Rust (command line argument parser).

License: The Unlicense

Makefile 0.30% Shell 1.74% Rust 95.97% Python 1.88% Vim Script 0.11%

docopt.rs's Introduction

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.

Build status

Licensed under the UNLICENSE.

Current status

Fully functional but the design of the API is up for debate. I am seeking feedback.

Documentation

http://burntsushi.net/rustdoc/docopt

Installation

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.

Quick example

Here is a full working example:

extern crate serialize;
extern crate docopt;

use docopt::Docopt;

// Write the Docopt usage string.
static USAGE: &'static str = "
Usage: cp [-a] <source> <dest>
       cp [-a] <source>... <dir>

Options:
    -a, --archive  Copy everything.
";

#[deriving(Decodable, Show)]
struct Args {
    arg_source: Vec<String>,
    arg_dest: String,
    arg_dir: String,
    flag_archive: bool,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());
    println!("{}", args);
}

Here is the same example, but with the use of the docopt! macro, which will generate a struct for you:

#![feature(phase)]

extern crate serialize;

extern crate docopt;
#[phase(plugin)] extern crate docopt_macros;

docopt!(Args deriving Show, "
Usage: cp [options] <src> <dst>
       cp [options] <src>... <dir>
       cp --help

Options:
  -h, --help       Show this message.
  -a, --archive    Copy everything.
")

fn main() {
    let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());
    println!("{}", args);
}

The field names of the struct map like this:

-g       => flag_g
--group  => flag_group
FILE     => arg_FILE
<file>   => arg_file
build    => cmd_build

The Args struct has one static method defined for it: docopt. The method returns a normal Docopt value, which can be used to set configuration options, argv and parse or decode command line arguments.

Data validation example

Here's another example that shows how to specify the types of your arguments:

#![feature(phase)]

extern crate serialize;

extern crate docopt;
#[phase(plugin)] extern crate docopt_macros;

docopt!(Args, "Usage: add <x> <y>", arg_x: int, arg_y: int)

fn main() {
    let args: Args = Args::docopt().decode().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.

And of course, you don't need the macro to do this. You can do the same thing with a manually written struct too.

Modeling rustc

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 and demonstrates more Docopt features.

#![feature(phase)]

extern crate serialize;

extern crate docopt;
#[phase(plugin)] extern crate docopt_macros;

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 = Args::docopt().decode().unwrap_or_else(|e| e.exit());
    println!("{}", args);
}

Viewing the generated struct

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,
}

Traditional Docopt API

The reference implementation of Docopt returns a Python dictionary with names like <arg> or --flag. If you prefer this access pattern, then you can use docopt::ArgvMap. The disadvantage is that you have to do all of your type conversion manually. Here's the canonical Docopt example with a hash table:

extern crate docopt;

use docopt::Docopt;

static USAGE: &'static str = "
Naval Fate.

Usage:
  naval_fate.py ship new <name>...
  naval_fate.py ship <name> move <x> <y> [--speed=<kn>]
  naval_fate.py ship shoot <x> <y>
  naval_fate.py mine (set|remove) <x> <y> [--moored | --drifting]
  naval_fate.py (-h | --help)
  naval_fate.py --version

Options:
  -h --help     Show this screen.
  --version     Show version.
  --speed=<kn>  Speed in knots [default: 10].
  --moored      Moored (anchored) mine.
  --drifting    Drifting mine.
";

fn main() {
    let args = Docopt::new(USAGE)
                      .and_then(|dopt| dopt.parse())
                      .unwrap_or_else(|e| e.exit());
    println!("{}", args);

    // You can conveniently access values with `get_{bool,count,str,vec}`
    // functions. If the key doesn't exist (or if, e.g., you use `get_str` on
    // a switch), then a sensible default value is returned.
    println!("\nSome values:");
    println!("  Speed: {}", args.get_str("--speed"));
    println!("  Drifting? {}", args.get_bool("--drifting"));
    println!("  Names: {}", args.get_vec("<name>"));
}

Tab completion support

This particular implementation bundles a command called docopt-wordlist that can be used to automate tab completion. This repository also collects some basic completion support for various shells (currently only bash) in the completions directory.

You can use them to setup tab completion on your system. It should work with any program that uses Docopt (or rather, any program that outputs usage messages that look like Docopt). For example, to get tab completion support for Cargo, you'll have to install docopt-wordlist and add some voodoo to your $HOME/.bash_completion file (this may vary for other shells).

Here it is step by step:

# Download and build `docopt-wordlist` (as part of the Docopt package)
$ git clone git://github.com/docopt/docopt.rs
$ cd docopt.rs
$ cargo build --release

# Now setup tab completion (for bash)
$ echo "DOCOPT_WORDLIST_BIN=\"$(pwd)/target/release/docopt-wordlist\"" >> $HOME/.bash_completion
$ echo "source \"$(pwd)/completions/docopt-wordlist.bash\"" >> $HOME/.bash_completion
$ echo "complete -F _docopt_wordlist_commands cargo" >> $HOME/.bash_completion

My CSV toolkit is supported too:

# shameless plug...
$ echo "complete -F _docopt_wordlist_commands xsv" >> $HOME/.bash_completion

Note that this is emphatically a first pass. There are several improvements that I'd like to make:

  1. Take context into account when completing. For example, it should be possible to only show completions that can lead to a valid Docopt match. This may be hard. (i.e., It may require restructuring Docopt's internals.)
  2. Support more shells. (I'll happily accept pull requests on this one. I doubt I'll venture outside of bash any time soon.)
  3. Make tab completion support more seamless. The way it works right now is pretty hacky by intermingling file/directory completion.

docopt.rs's People

Contributors

alexcrichton avatar bkoropoff avatar burntsushi avatar carllerche avatar cburgdorf avatar crazysacx avatar dotdash avatar drbawb avatar eliovir avatar gchp avatar jauhien avatar kinghajj avatar ktossell avatar leighlondon avatar leonkunert avatar maxsnew avatar msiemens avatar netvl avatar renato-zannon avatar steveklabnik avatar tgkokk avatar wwendell avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.