fire 0.6.0

Turn functions into command-line applications with one attribute, like Python's fire
Documentation
# Rust Fire

[![Documentation](https://docs.rs/fire/badge.svg)](https://docs.rs/fire)

![](https://repository-images.githubusercontent.com/122919956/bf2aa6f1-3fa7-446a-b389-cf34ecbe68a0)

*Image by [T5](https://weibo.com/579027700), source: https://www.pixiv.net/artworks/104959772*

Turn a Rust function or module into a command-line application with one attribute.

## Installation

```sh
cargo add fire
```

## One function

```rust
/// Welcome a person.
#[fire::main]
fn welcome(name: String, excited: bool) {
    let suffix = if excited { "!" } else { "." };
    println!("Welcome, {name}{suffix}");
}
```

```console
$ app --name "John Smith" --excited
Welcome, John Smith!
```

`#[fire::main]` generates the program entry point, so no separate `fn main()` or
registration call is needed.

## Help

`-h` and `--help` are generated automatically from the function signature and
documentation comments:

```rust
/// Start the HTTP server.
#[fire::main]
fn serve(
    /// Address to listen on.
    host: String,
    /// Enable verbose logging.
    verbose: bool,
) {}
```

```console
$ app --help
Start the HTTP server.

Usage: app --host <HOST> [--verbose]

Options:
    --host <HOST>    Address to listen on.
    --verbose        Enable verbose logging.
    -h, --help       Print help
```

For module applications, `app --help` lists the subcommands and
`app <COMMAND> --help` describes one subcommand.

## Subcommands

Place `#[fire::main]` on an inline module to turn its `pub` functions into
subcommands. Private functions stay private, so a module can keep its helpers
next to its commands:

```rust
#[fire::main]
mod cli {
    pub fn hello(name: String, times: Option<u32>) {
        for _ in 0..times.unwrap_or(1) {
            println!("Hello, {name}!");
        }
    }

    pub fn bye() {
        println!("Bye!");
    }
}
```

```console
$ app hello --name John --times 2
Hello, John!
Hello, John!

$ app bye
Bye!
```

Rust `snake_case` function and parameter names are exposed as CLI `kebab-case`
names.

## Parameters

The function signature defines the CLI:

| Rust type | CLI behavior |
| --- | --- |
| `T` | required option parsed with `FromStr` |
| `Option<T>` | optional option |
| `bool` | value-less flag, defaulting to `false` |
| `&str` | borrowed string option |

Both common option formats are accepted:

```console
$ app --name John
$ app --name=John
```

An option may be given only once, and a value starting with `-` is never taken
from the next argument, so write it as `--count=-1`.

A command returns `()` or `Result<_, E>` where `E: Display`. Errors are printed
to stderr and the application exits with status 2.

```rust
#[fire::main]
fn deploy(target: String) -> Result<(), DeployError> {
    do_deploy(&target)?;
    Ok(())
}
```

The return value is dispatched through a trait rather than by matching on the
return type, so aliases such as `anyhow::Result<()>` work too. Any other return
type is a compile error.

## Async

Pass `tokio` to the attribute to write `async` commands. Each async command
runs on a multi-threaded Tokio runtime, so add `tokio` with the
`rt-multi-thread` feature to your application:

```rust
/// Fetch a URL.
#[fire::main(tokio)]
async fn fetch(url: String) {
    let body = reqwest::get(&url).await.unwrap();
    // ...
}
```

The same works on modules, and async and synchronous commands can be mixed in
one module.

## License

BSD-2-Clause.