commander-rust 1.0.1

A better way to develop CLI in Rust
Documentation
# other languages
[中文文档](https://github.com/MSDimos/commander-rust/blob/master/docs/README_CN.md)

# why this ?

For a long time, developing cli in `Rust` is difficult.
Since Rust is a static language, the compiler needs to know all the details at compile time. 
It conflicts with the dynamics of the CLI.
The community offers a wide range of solutions. Yes, they're excellent, but they're not very simple.

Inspired by [commander.js](https://github.com/tj/commander.js) & [rocket.rs](https://rocket.rs), the crate was born.

# limit

If you want to use this crate, please guarantee that you have follow rules below:
+ using `Rust 2018` (full proc macro support is required, including [proc_macro] & [proc_macro_attribute])
+ using `cargo` (`cargo` will produce some environment variable according to `Cargo.toml`, we need that)
+ be familiar with `Rust` (because it's developed for `Rust` )

As a reference, my versions are:
+ `cargo`: cargo 1.35.0-nightly (95b45eca1 2019-03-06)
+ `rustc`: rustc 1.35.0-nightly (e68bf8ae1 2019-03-11)
+ `Linux kernal`: 4.15.0-47-generic
+ `Ubuntu`: 16.04

# usage

#### install `commander-rust`

Two ways supported: from `Github` or `crates.io`.
The difference between them is that `Github` is latest but unstable and `crates.io` is stable but might not be latest.

##### install from `Github`
(warn, it does not work now! I'm testing to guarantee that crate will work perfectly)
```toml
[dependencies.commander_rust]
git = "https://github.com/MSDimos/commander_rust"
branch = "master"
```

#### install from `crates.io`

```toml
[dependencies]
commander_rust = "^1.0.0" # or other version you want to install
```

#### using it

We offer a simple but complete example, you can learn all through it.
Yes, That's all. Very easy!

```rust

// this is required! Beacuse we used `run!()`, it's a proc_macro
#![feature(proc_macro_hygiene)]

// Only five items you will use!
use commander_rust::{ Cli, command, option, entry, run };


fn _rmdir(dir: String, other_dirs: Option<Vec<String>>, cli: Cli) {
    if cli.get_or("recursive", false) {
        let quite: bool = cli.get("quite").into();
        
        if quite {
            // silently delete all files
            // just like `rm -rf /`
        } else {
            // tell the world I'm going to delete the files
        }
    } else {
        // drink a cup of coffee, relax.
    }
}


// what's option? what's command? 
// See `commander.js` and document of `commander-rust` for more!
// Note, types of parameters are not fixed, any type implemented `From<Raw>` is valid!
// So you can even use `rmdir(dir: i32, other_dirs: Vec<i32>, cli: Cli)` here.
// And `Cli` is not required! So you can miss it.
// See document of `commander-rust` for more details.
#[option(-s, --format <format>, "format output")]
#[option(-r, --recursive, "recursively")]
#[command(rmdir <dir> [otherDirs...], "remove files and directories")]
fn rmdir(dir: String, other_dirs: Option<Vec<String>>, cli: Cli) {
    // You might be confused, 
    // Why call a function instead of doing everything here? Isn't that superfluous ?
    // This is a bug of compiler. 
    // If you do everything here, the compiler can't give good advice When your code goes wrong.
    // You can have a try, using `let three = 1 + "2"` replace code below. See compiler's error message.
    // See more details: `https://github.com/dtolnay/syn/issues/622`
    
     _rmdir(dir, other_dirs, cli);
}

// options here are public, options above `#[command]` are private
#[option(-q, --quite <quite_or_not>, "dont display anything")]
#[entry]
fn main() {
     // Run it now!!!!!
     let app = run!();
     println!("app is {:#?}", app);
}
```

#### try it

try to input `[pkg-name] --help`.

# version & description & cli-name?

`version`, `description`, `cli-name` of application are from `Cargo.toml`.

For instance:
```toml
# part of Cargo.toml
[package]
name = "example-test"
version = "0.1.0"
description = "Using for test"
```

# full example

I offered a full example, it's `hash`.
It's using for generating MD5 of files or strings.
See `./examples/`for more details.

# homepage
I developed homepage for it. See `./homepage` for more details.
It's developed bashed on `React`. I like it.

# rules

There are several rules you should follow.
1. All `#[options]` should defined above `#[command]` and `#[entry]`
2. DO NOT define options duplicate!!! As a concession, You can define the same option on different command and entry.
3. Private options are visible to specific sub-commands. Public options are visible to all sub-commands.
4. At least one sub-command!


# warn

The crate is developed using `Ubuntu 16.04`, we can't assume that all platforms will work well.
If you find that it can't work well in other platforms, please tell me.

# contribute

Any useful contribute are welcome. You can send pull request to me.

# License

GPL-3.0. Because open source is future.