From 6ce9714e2bbbccb9d6af1e0a6987562b32e1bc91 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 18 Nov 2021 14:27:21 -0600 Subject: [PATCH] fix: Deprecate YAML API Fixes #9 --- FAQ.md | 2 - README.md | 70 +----------------------------- examples/17_yaml.rs | 50 --------------------- examples/17_yaml.yaml | 98 ------------------------------------------ src/build/app/mod.rs | 7 ++- src/build/arg/mod.rs | 14 +++--- src/build/arg_group.rs | 10 +++-- src/lib.rs | 7 ++- tests/examples.rs | 9 +--- tests/yaml.rs | 1 + 10 files changed, 27 insertions(+), 241 deletions(-) delete mode 100644 examples/17_yaml.rs delete mode 100644 examples/17_yaml.yaml diff --git a/FAQ.md b/FAQ.md index df4a4d1c..d905cef0 100644 --- a/FAQ.md +++ b/FAQ.md @@ -73,14 +73,12 @@ To build an `App` there are three: * Derive Macros * Builder Pattern -* Yaml To build an `Arg` there are four: * Derive Macros * Builder Pattern * Usage Strings -* Yaml ### Why is there a default subcommand of help? diff --git a/README.md b/README.md index 275d7134..9b93dbe0 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,7 @@ We are currently hard at work trying to release `3.0`. We have a `3.0.0-beta.5` 4. [Quick Example](#quick-example) 1. [Using Derive Macros](#using-derive-macros) 2. [Using Builder Pattern](#using-builder-pattern) - 3. [Using YAML](#using-yaml) - 4. [Running it](#running-it) + 3. [Running it](#running-it) 5. [Try it!](#try-it) 1. [Pre-Built Test](#pre-built-test) 2. [Build Your Own Binary](#build-your-own-binary) @@ -92,7 +91,6 @@ Below are a few of the features which `clap` supports, full descriptions and usa * **Sub-Commands** (i.e. `git add ` where `add` is a sub-command of `git`) - Support their own sub-arguments, and sub-sub-commands independent of the parent - Get their own auto-generated Help, Version, and Usage independent of parent -* **Support for building CLIs from YAML** - This keeps your Rust source nice and tidy and makes supporting localized translation very simple! * **Requirement Rules**: Arguments can define the following types of requirement rules - Can be required by default - Can be required only if certain arguments are present @@ -304,72 +302,6 @@ fn main() { } ``` -#### Using YAML - -This third method shows how you can use a YAML file to build your CLI and keep your Rust source tidy -or support multiple localized translations by having different YAML files for each localization. - -First, create the `cli.yaml` file to hold your CLI options, but it could be called anything we like: - -```yaml -name: myapp -version: "1.0" -author: Kevin K. -about: Does awesome things -args: - - config: - short: c - long: config - value_name: FILE - help: Sets a custom config file - takes_value: true - - INPUT: - help: Sets the input file to use - required: true - index: 1 - - verbose: - short: v - multiple_occurrences: true - help: Sets the level of verbosity -subcommands: - - test: - about: controls testing features - version: "1.3" - author: Someone E. - args: - - debug: - short: d - long: debug - help: Print debug information -``` - -Since this feature requires additional dependencies that not everyone may want, it is *not* compiled in by default and we need to enable a feature flag in Cargo.toml: - -Simply add the `yaml` feature flag to your `Cargo.toml`. - -```toml -[dependencies] -clap = { version = "3.0.0-beta.5", features = ["yaml"] } -``` - -Finally we create our `main.rs` file just like we would have with the previous two examples: - -```rust,ignore -// (Full example with detailed comments in examples/17_yaml.rs) -// -// This example demonstrates clap's building from YAML style of creating arguments which is far -// more clean, but takes a very small performance hit compared to the other two methods. -use clap::{App, load_yaml}; - -fn main() { - // The YAML file is found relative to the current file, similar to how modules are found - let yaml = load_yaml!("cli.yaml"); - let matches = App::from(yaml).get_matches(); - - // Same as previous examples... -} -``` - #### Running it If you were to compile any of the above programs and run them with the flag `--help` or `-h` (or `help` subcommand, since we defined `test` as a subcommand) the following would be output (except the first example where the help message sort of explains the Rust code). diff --git a/examples/17_yaml.rs b/examples/17_yaml.rs deleted file mode 100644 index bc1a6822..00000000 --- a/examples/17_yaml.rs +++ /dev/null @@ -1,50 +0,0 @@ -// In order to use YAML to define your CLI you must compile clap with the "yaml" feature because -// it's **not** included by default. -// -// In order to do this, ensure your Cargo.toml looks like one of the following: -// -// [dependencies.clap] -// features = ["yaml"] -// -// __OR__ -// -// [dependencies] -// clap = { features = ["yaml"] } - -// Using yaml requires calling a clap macro `load_yaml!()`. -// Note: If you're using clap as a dependency and don't have a feature for your users called -// "yaml", you'll need to remove the #[cfg(feature = "yaml")] conditional compilation attribute -#[cfg(feature = "yaml")] -fn main() { - use clap::{load_yaml, App}; - - // To load a yaml file containing our CLI definition such as the example '17_yaml.yaml' we can - // use the convenience macro which loads the file at compile relative to the current file - // similar to how modules are found. - // - // Then we pass that yaml object to App to build the CLI. - // - // Finally we call get_matches() to start the parsing process. We use the matches just as we - // normally would - let yaml = load_yaml!("17_yaml.yaml"); - let m = App::from_yaml(yaml).get_matches(); - - // Because the example 17_yaml.yaml is rather large we'll just look a single arg so you can - // see that it works... - if let Some(mode) = m.value_of("mode") { - match mode { - "vi" => println!("You are using vi"), - "emacs" => println!("You are using emacs..."), - _ => unreachable!(), - } - } else { - println!("--mode wasn't used..."); - } -} - -#[cfg(not(feature = "yaml"))] -fn main() { - // As stated above, if clap is not compiled with the YAML feature, it is disabled. - println!("YAML feature is disabled."); - println!("Pass --features yaml to cargo when trying this example."); -} diff --git a/examples/17_yaml.yaml b/examples/17_yaml.yaml deleted file mode 100644 index d40ae6ca..00000000 --- a/examples/17_yaml.yaml +++ /dev/null @@ -1,98 +0,0 @@ -name: yaml_app -version: "1.0" -about: an example using a .yaml file to build a CLI -author: Kevin K. - -# AppSettings can be defined as a list and are **not** ascii case sensitive -settings: - - ArgRequiredElseHelp - -# All Args must be defined in the 'args:' list where the name of the arg, is the -# key to a Hash object -args: - # The name of this argument, is 'opt' which will be used to access the value - # later in your Rust code - - opt: - help: example option argument from yaml - short: o - long: option - multiple_occurrences: true - takes_value: true - - pos: - help: example positional argument from yaml - index: 1 - # A list of possible values can be defined as a list - possible_values: - - fast - - slow - - flag: - help: demo flag argument - short: F - multiple_occurrences: true - takes_value: true - global: true - # Conflicts, mutual overrides, and requirements can all be defined as a - # list, where the key is the name of the other argument - conflicts_with: - - opt - requires: - - pos - - mode: - long: mode - help: shows an option with specific values - # possible_values can also be defined in this list format - possible_values: [ vi, emacs ] - takes_value: true - - mvals: - long: mult-vals - help: demos an option which has two named values - # value names can be described in a list, where the help will be shown - # --mult-vals - value_names: - - one - - two - - minvals: - long: min-vals - multiple_values: true - help: you must supply at least two values to satisfy me - min_values: 2 - - maxvals: - long: max-vals - multiple_values: true - help: you can only supply a max of 3 values for me! - max_values: 3 - -# All subcommands must be listed in the 'subcommand:' object, where the key to -# the list is the name of the subcommand, and all settings for that command are -# are part of a Hash object -subcommands: - # The name of this subcommand will be 'subcmd' which can be accessed in your - # Rust code later - - subcmd: - about: demos subcommands from yaml - version: "0.1" - author: Kevin K. - # Subcommand args are exactly like App args - args: - - scopt: - short: B - multiple_occurrences: true - help: example subcommand option - takes_value: true - - scpos1: - help: example subcommand positional - index: 1 - -# ArgGroups are supported as well, and must be specified in the 'groups:' -# object of this file -groups: - # the name of the ArgGoup is specified here - - min-max-vals: - # All args and groups that are a part of this group are set here - args: - - minvals - - maxvals - # setting conflicts is done the same manner as setting 'args:' - # - # to make this group required, you could set 'required: true' but for - # this example we won't do that. diff --git a/src/build/app/mod.rs b/src/build/app/mod.rs index ac703250..5df30a88 100644 --- a/src/build/app/mod.rs +++ b/src/build/app/mod.rs @@ -398,9 +398,14 @@ impl<'help> App<'help> { ) } - /// TODO + /// Deprecated in Issue #9, maybe clap::Parser would fit your use case? #[cfg(feature = "yaml")] + #[deprecated( + since = "3.0.0", + note = "Deprecated in Issue #9, maybe clap::Parser would fit your use case?" + )] pub fn from_yaml(y: &'help Yaml) -> Self { + #![allow(deprecated)] let yaml_file_hash = y.as_hash().expect("YAML file must be a hash"); // We WANT this to panic on error...so expect() is good. let (mut a, yaml, err) = if let Some(name) = y["name"].as_str() { diff --git a/src/build/arg/mod.rs b/src/build/arg/mod.rs index 3a6e638b..1e467a24 100644 --- a/src/build/arg/mod.rs +++ b/src/build/arg/mod.rs @@ -349,16 +349,12 @@ impl<'help> Arg<'help> { Self::new(n) } - /// Creates a new instance of [`Arg`] from a .yaml (YAML) file. - /// - /// # Examples - /// - /// ```ignore - /// use clap::{Arg, load_yaml}; - /// let yaml = load_yaml!("arg.yaml"); - /// let arg = Arg::from(yaml); - /// ``` + /// Deprecated in Issue #9, maybe clap::Parser would fit your use case? #[cfg(feature = "yaml")] + #[deprecated( + since = "3.0.0", + note = "Deprecated in Issue #9, maybe clap::Parser would fit your use case?" + )] pub fn from_yaml(y: &'help Yaml) -> Self { let yaml_file_hash = y.as_hash().expect("YAML file must be a hash"); // We WANT this to panic on error...so expect() is good. diff --git a/src/build/arg_group.rs b/src/build/arg_group.rs index cb509667..44951161 100644 --- a/src/build/arg_group.rs +++ b/src/build/arg_group.rs @@ -114,9 +114,12 @@ impl<'help> ArgGroup<'help> { Self::new(n) } - /// Deprecated, see [`ArgGroup::from`] + /// Deprecated in Issue #9, maybe clap::Parser would fit your use case? #[cfg(feature = "yaml")] - #[deprecated(since = "3.0.0", note = "Replaced with `ArgGroup::from`")] + #[deprecated( + since = "3.0.0", + note = "Deprecated in Issue #9, maybe clap::Parser would fit your use case?" + )] pub fn from_yaml(yaml: &'help Yaml) -> Self { Self::from(yaml) } @@ -436,9 +439,10 @@ impl<'help> From<&'_ ArgGroup<'help>> for ArgGroup<'help> { } } +/// Deprecated in Issue #9, maybe clap::Parser would fit your use case? #[cfg(feature = "yaml")] impl<'help> From<&'help Yaml> for ArgGroup<'help> { - /// TODO + /// Deprecated in Issue #9, maybe clap::Parser would fit your use case? fn from(y: &'help Yaml) -> Self { let b = y.as_hash().expect("ArgGroup::from:: expects a table"); // We WANT this to panic on error...so expect() is good. diff --git a/src/lib.rs b/src/lib.rs index 4e682f7f..0e792346 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,9 +77,14 @@ impl SubCommand { App::new(name) } - /// TODO + /// Deprecated in Issue #9, maybe clap::Parser would fit your use case? #[cfg(feature = "yaml")] + #[deprecated( + since = "3.0.0", + note = "Deprecated in Issue #9, maybe clap::Parser would fit your use case?" + )] pub fn from_yaml(yaml: &yaml_rust::Yaml) -> App { + #![allow(deprecated)] App::from_yaml(yaml) } } diff --git a/tests/examples.rs b/tests/examples.rs index 737852a8..8f2f4394 100644 --- a/tests/examples.rs +++ b/tests/examples.rs @@ -5,14 +5,7 @@ use std::fs; use std::process::{Command, Output}; fn run_example>(name: S, args: &[&str]) -> Output { - let mut all_args = vec![ - "run", - "--example", - name.as_ref(), - "--features", - "yaml", - "--", - ]; + let mut all_args = vec!["run", "--example", name.as_ref(), "--"]; all_args.extend_from_slice(args); Command::new(env!("CARGO")) diff --git a/tests/yaml.rs b/tests/yaml.rs index ea045388..3f903d24 100644 --- a/tests/yaml.rs +++ b/tests/yaml.rs @@ -1,4 +1,5 @@ #![cfg(feature = "yaml")] +#![allow(deprecated)] use clap::{load_yaml, App, Arg, ErrorKind, ValueHint};