From 09d4d0a9038d7ce2df55c2aec95e16f36189fcee Mon Sep 17 00:00:00 2001 From: Kevin K Date: Sun, 18 Sep 2016 15:22:55 -0400 Subject: [PATCH 1/6] fix(Value Delimiters): fixes the confusion around implicitly setting value delimiters. (default is now `false`) Now if one wishes to use value delimiters, they must explicitly set `Arg::use_delimiter(true)` or `Arg::require_delimiter(true)`. No other methods implicitly set this value. Closes #666 --- src/args/arg.rs | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/src/args/arg.rs b/src/args/arg.rs index b62c1752b8a..f69d7aff020 100644 --- a/src/args/arg.rs +++ b/src/args/arg.rs @@ -1313,12 +1313,8 @@ impl<'a, 'b> Arg<'a, 'b> { /// [option]: ./struct.Arg.html#method.takes_value /// [`Arg::number_of_values(1)`]: ./struct.Arg.html#method.number_of_values /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple - pub fn multiple(mut self, multi: bool) -> Self { + pub fn multiple(self, multi: bool) -> Self { if multi { - if self.settings.is_set(ArgSettings::ValueDelimiterNotSet) && - self.settings.is_set(ArgSettings::TakesValue) { - self = self.use_delimiter(true); - } self.set(ArgSettings::Multiple) } else { self.unset(ArgSettings::Multiple) @@ -1689,12 +1685,6 @@ impl<'a, 'b> Arg<'a, 'b> { /// ``` /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple pub fn number_of_values(mut self, qty: u64) -> Self { - if qty > 1 && self.settings.is_set(ArgSettings::ValueDelimiterNotSet) { - self.unsetb(ArgSettings::ValueDelimiterNotSet); - self.setb(ArgSettings::UseValueDelimiter); - } else { - self = self.use_delimiter(false); - } self.setb(ArgSettings::TakesValue); self.num_vals = Some(qty); self @@ -1794,12 +1784,6 @@ impl<'a, 'b> Arg<'a, 'b> { /// ``` /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple pub fn max_values(mut self, qty: u64) -> Self { - if qty > 1 && self.settings.is_set(ArgSettings::ValueDelimiterNotSet) { - self.unsetb(ArgSettings::ValueDelimiterNotSet); - self.setb(ArgSettings::UseValueDelimiter); - } else { - self = self.use_delimiter(false); - } self.setb(ArgSettings::TakesValue); self.max_vals = Some(qty); self @@ -2004,10 +1988,12 @@ impl<'a, 'b> Arg<'a, 'b> { /// ``` pub fn require_delimiter(mut self, d: bool) -> Self { if d { + self = self.use_delimiter(true); self.unsetb(ArgSettings::ValueDelimiterNotSet); self.setb(ArgSettings::UseValueDelimiter); self.set(ArgSettings::RequireDelimiter) } else { + self = self.use_delimiter(false); self.unsetb(ArgSettings::UseValueDelimiter); self.unset(ArgSettings::RequireDelimiter) } From c81bc722ebb8a86d22be89b5aec98df9fe222a08 Mon Sep 17 00:00:00 2001 From: Kevin K Date: Sun, 18 Sep 2016 15:24:44 -0400 Subject: [PATCH 2/6] docs: updates the docs about removing implicit value_delimiter(true) --- src/args/arg.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/args/arg.rs b/src/args/arg.rs index f69d7aff020..9cf9784c0cf 100644 --- a/src/args/arg.rs +++ b/src/args/arg.rs @@ -1855,10 +1855,6 @@ impl<'a, 'b> Arg<'a, 'b> { /// **NOTE:** The default is `false`. When set to `true` the default [`Arg::value_delimiter`] /// is the comma `,`. /// - /// **NOTE:** When using methods like [`Arg::multiple`] or [`Arg::max_values`] (i.e. methods - /// that imply multiple values, this `use_delimiter` setting will automatically be set to - /// `true` and use the comma (`,`) by default. - /// /// # Examples /// /// The following example shows the default behavior. @@ -1880,7 +1876,7 @@ impl<'a, 'b> Arg<'a, 'b> { /// assert_eq!(delims.values_of("option").unwrap().collect::>(), ["val1", "val2", "val3"]); /// ``` /// The next example shows the difference when turning delimiters off. This is the default - /// behavior, unless one of the methods/settings which implies multiple values is set. + /// behavior /// /// ```rust /// # use clap::{App, Arg}; @@ -1921,6 +1917,8 @@ impl<'a, 'b> Arg<'a, 'b> { /// /// **NOTE:** The default is `false`. /// + /// **NOTE:** Setting this to true implies [`Arg::use_delimiter(true)`] + /// /// **NOTE:** It's a good idea to inform the user that use of a delimiter is required, either /// through help text or other means. /// @@ -1986,6 +1984,7 @@ impl<'a, 'b> Arg<'a, 'b> { /// assert!(delims.is_present("opt")); /// assert_eq!(delims.values_of("opt").unwrap().collect::>(), ["val1", "val2", "val3"]); /// ``` + /// [`Arg::use_delimiter(true)`]: ./struct.Arg.html#method.use_delimiter pub fn require_delimiter(mut self, d: bool) -> Self { if d { self = self.use_delimiter(true); From d12649fd7b932899958ce138b226bc00be0c936b Mon Sep 17 00:00:00 2001 From: Kevin K Date: Sun, 18 Sep 2016 15:24:59 -0400 Subject: [PATCH 3/6] tests: adds tests for value delimiters --- tests/delimiters.rs | 139 +++++++++++++++++++++++++++++++++++++++ tests/multiple_values.rs | 5 ++ 2 files changed, 144 insertions(+) create mode 100644 tests/delimiters.rs diff --git a/tests/delimiters.rs b/tests/delimiters.rs new file mode 100644 index 00000000000..30c998bd652 --- /dev/null +++ b/tests/delimiters.rs @@ -0,0 +1,139 @@ +extern crate clap; + +use clap::{App, Arg}; + +#[test] +fn opt_default_no_delim() { + let m = App::new("no_delim") + .arg(Arg::with_name("option") + .long("option") + .takes_value(true)) + .get_matches_from_safe(vec![ + "", + "--option", "val1,val2,val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3"); +} + +#[test] +fn opt_eq_no_delim() { + let m = App::new("no_delim") + .arg(Arg::with_name("option") + .long("option") + .takes_value(true)) + .get_matches_from_safe(vec![ + "", + "--option=val1,val2,val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3"); +} + +#[test] +fn opt_s_eq_no_delim() { + let m = App::new("no_delim") + .arg(Arg::with_name("option") + .short("o") + .takes_value(true)) + .get_matches_from_safe(vec![ + "", + "-o=val1,val2,val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3"); +} + +#[test] +fn opt_s_default_no_delim() { + let m = App::new("no_delim") + .arg(Arg::with_name("option") + .short("o") + .takes_value(true)) + .get_matches_from_safe(vec![ + "", + "-o", "val1,val2,val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3"); +} + +#[test] +fn opt_s_no_space_no_delim() { + let m = App::new("no_delim") + .arg(Arg::with_name("option") + .short("o") + .takes_value(true)) + .get_matches_from_safe(vec![ + "", + "-o", "val1,val2,val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3"); +} + +#[test] +fn opt_s_no_space_mult_no_delim() { + let m = App::new("no_delim") + .arg(Arg::with_name("option") + .short("o") + .multiple(true) + .takes_value(true)) + .get_matches_from_safe(vec![ + "", + "-o", "val1,val2,val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.value_of("option").unwrap(), "val1,val2,val3"); +} + +#[test] +fn opt_eq_mult_def_delim() { + let m = App::new("no_delim") + .arg(Arg::with_name("option") + .long("opt") + .multiple(true) + .use_delimiter(true) + .takes_value(true)) + .get_matches_from_safe(vec![ + "", + "--opt=val1,val2,val3", + ]); + + assert!(m.is_ok()); + let m = m.unwrap(); + + assert!(m.is_present("option")); + assert_eq!(m.occurrences_of("option"), 1); + assert_eq!(m.values_of("option").unwrap().collect::>(), &["val1", "val2", "val3"]); +} diff --git a/tests/multiple_values.rs b/tests/multiple_values.rs index 194b8303134..bdcb8926416 100644 --- a/tests/multiple_values.rs +++ b/tests/multiple_values.rs @@ -523,6 +523,7 @@ fn multiple_values_sep_long_equals() { let m = App::new("multiple_values") .arg(Arg::with_name("option") .long("option") + .use_delimiter(true) .help("multiple options") .takes_value(true) .multiple(true)) @@ -544,6 +545,7 @@ fn multiple_values_sep_long_space() { let m = App::new("multiple_values") .arg(Arg::with_name("option") .long("option") + .use_delimiter(true) .help("multiple options") .takes_value(true) .multiple(true)) @@ -567,6 +569,7 @@ fn multiple_values_sep_short_equals() { .arg(Arg::with_name("option") .short("o") .help("multiple options") + .use_delimiter(true) .takes_value(true) .multiple(true)) .get_matches_from_safe(vec![ @@ -588,6 +591,7 @@ fn multiple_values_sep_short_space() { .arg(Arg::with_name("option") .short("o") .help("multiple options") + .use_delimiter(true) .takes_value(true) .multiple(true)) .get_matches_from_safe(vec![ @@ -610,6 +614,7 @@ fn multiple_values_sep_short_no_space() { .arg(Arg::with_name("option") .short("o") .help("multiple options") + .use_delimiter(true) .takes_value(true) .multiple(true)) .get_matches_from_safe(vec![ From 325610eb041e97b634d46b8464eca0df36a808c0 Mon Sep 17 00:00:00 2001 From: Kevin K Date: Sun, 18 Sep 2016 15:29:16 -0400 Subject: [PATCH 4/6] docs: updates README.md with new website information and updated video tutorials info --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c8ff634d7eb..ef391f8b31e 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ Command Line Argument Parser for Rust It is a simple-to-use, efficient, and full-featured library for parsing command line arguments and subcommands when writing console/terminal applications. ## [documentation](https://docs.rs/clap/) +## [website](https://clap.rs/) +## [blog](https://blog.clap.rs/) Table of Contents ================= @@ -335,7 +337,7 @@ Below are a few of the features which `clap` supports, full descriptions and usa ## Quick Example -The following examples show a quick example of some of the very basic functionality of `clap`. For more advanced usage, such as requirements, conflicts, groups, multiple values and occurrences see the [documentation](https://docs.rs/clap/), [examples/](examples) directory of this repository or the [video tutorials](https://www.youtube.com/playlist?list=PLza5oFLQGTl0Bc_EU_pBNcX-rhVqDTRxv) (which are quite outdated by now). +The following examples show a quick example of some of the very basic functionality of `clap`. For more advanced usage, such as requirements, conflicts, groups, multiple values and occurrences see the [documentation](https://docs.rs/clap/), [examples/](examples) directory of this repository or the [video tutorials](https://www.youtube.com/playlist?list=PLza5oFLQGTl2Z5T8g1pRkIynR3E0_pc7U). **NOTE:** All these examples are functionally the same, but show three different styles in which to use `clap` @@ -627,9 +629,9 @@ You can also find usage examples in the [examples/](examples) directory of this #### Video Tutorials -There's also the video tutorial series [Argument Parsing with Rust](https://www.youtube.com/playlist?list=PLza5oFLQGTl0Bc_EU_pBNcX-rhVqDTRxv). +There's also the video tutorial series [Argument Parsing with Rust v2](https://www.youtube.com/playlist?list=PLza5oFLQGTl2Z5T8g1pRkIynR3E0_pc7U). -**NOTE:** This series is getting out of date and needs to be updated +These videos slowly trickle out as I finish them and currently a work in progress. ## How to Contribute From 6b9bd215c1cecfb2ca731ce92081806b7f02ad9d Mon Sep 17 00:00:00 2001 From: Kevin K Date: Sun, 18 Sep 2016 15:49:45 -0400 Subject: [PATCH 5/6] docs(Default Values): adds better examples on using default values Closes #418 --- examples/10_default_values.rs | 29 ++++++++++++++++++++++++----- src/args/arg.rs | 19 +++++++++++++++++++ 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/examples/10_default_values.rs b/examples/10_default_values.rs index 8883a40785a..577d90b4d41 100644 --- a/examples/10_default_values.rs +++ b/examples/10_default_values.rs @@ -3,19 +3,38 @@ extern crate clap; use clap::{App, Arg}; fn main() { - // You can get a "default value" like feature by using Option's .unwrap_or() method + // There are two ways in which to get a default value, one is to use claps Arg::default_value + // method, and the other is to use Rust's built in Option::unwrap_or method. // - // Let's assume you have -c argument to allow users to specify a configuration file - // but you also want to support a default file, if none is specified. + // I'll demo both here. + // + // First, we'll use clap's Arg::default_value with an "INPUT" file. let matches = App::new("myapp").about("does awesome things") + .arg(Arg::with_name("INPUT") + .help("The input file to use") // Note, we don't need to specify + // anything like, "Defaults to..." + // because clap will automatically + // generate that for us, and place + // it in the help text + .default_value("input.txt") + .index(1)) + + // Next we'll use the Option::unwrap_or method on this "CONFIG" option .arg(Arg::with_name("CONFIG") + // Note that we have to manaully include some verbage to the user + // telling them what the default will be. .help("The config file to use (default is \"config.json\")") .short("c") .takes_value(true)) .get_matches(); + // It's safe to call unwrap because the value with either be what the user input at runtime + // or "input.txt" + let input = matches.value_of("INPUT").unwrap(); + + // Using Option::unwrap_or we get the same affect, but without the added help text injection let config_file = matches.value_of("CONFIG").unwrap_or("config.json"); - // If the user passed in a -c we'll see that value, if not we'll see 'config.json' + println!("The input file is: {}", input); println!("The config file is: {}", config_file); -} \ No newline at end of file +} diff --git a/src/args/arg.rs b/src/args/arg.rs index 9cf9784c0cf..3901e033522 100644 --- a/src/args/arg.rs +++ b/src/args/arg.rs @@ -2186,6 +2186,8 @@ impl<'a, 'b> Arg<'a, 'b> { /// /// # Examples /// + /// First we use the default value without providing any value at runtime. + /// /// ```rust /// # use clap::{App, Arg}; /// let m = App::new("defvals") @@ -2200,6 +2202,23 @@ impl<'a, 'b> Arg<'a, 'b> { /// assert!(m.is_present("opt")); /// assert_eq!(m.occurrences_of("opt"), 0); /// ``` + /// + /// Next we provide a valu at runtime to override the default. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("defvals") + /// .arg(Arg::with_name("opt") + /// .long("myopt") + /// .default_value("myval")) + /// .get_matches_from(vec![ + /// "defvals", "--myopt=non_default" + /// ]); + /// + /// assert_eq!(m.value_of("opt"), Some("non_default")); + /// assert!(m.is_present("opt")); + /// assert_eq!(m.occurrences_of("opt"), 1); + /// ``` /// [`ArgMatches::occurrences_of`]: /struct.ArgMatches.html#method.occurrences_of /// [`ArgMatches::value_of`]: ./struct.ArgMatches.html#method.value_of /// [`Arg::takes_value(true)`]: /struct.Arg.html#method.takes_value From aad171d3e159020e16d1803fc7d54ee53e7a8d01 Mon Sep 17 00:00:00 2001 From: Kevin K Date: Sun, 18 Sep 2016 15:52:50 -0400 Subject: [PATCH 6/6] chore: increase version --- CHANGELOG.md | 16 ++++++++++++++++ Cargo.toml | 4 ++-- README.md | 8 ++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd16b84ddaf..20832351acc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ + +## v2.13.0 (2016-09-18) + + +#### Documentation + +* updates README.md with new website information and updated video tutorials info ([0c19c580](https://github.com/kbknapp/clap-rs/commit/0c19c580cf50f1b82ff32f70b36708ae2bcac132)) +* updates the docs about removing implicit value_delimiter(true) ([c81bc722](https://github.com/kbknapp/clap-rs/commit/c81bc722ebb8a86d22be89b5aec98df9fe222a08)) +* **Default Values:** adds better examples on using default values ([57a8d9ab](https://github.com/kbknapp/clap-rs/commit/57a8d9abb2f973c235a8a14f8fc031673d7a7460), closes [#418](https://github.com/kbknapp/clap-rs/issues/418)) + +#### Bug Fixes + +* **Value Delimiters:** fixes the confusion around implicitly setting value delimiters. (default is now `false`) ([09d4d0a9](https://github.com/kbknapp/clap-rs/commit/09d4d0a9038d7ce2df55c2aec95e16f36189fcee), closes [#666](https://github.com/kbknapp/clap-rs/issues/666)) + + + ### v2.12.1 (2016-09-13) diff --git a/Cargo.toml b/Cargo.toml index 1184cd65b89..b68c1f4125a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "clap" -version = "2.12.1" +version = "2.13.0" authors = ["Kevin K. "] exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"] repository = "https://github.com/kbknapp/clap-rs.git" documentation = "https://docs.rs/clap/" -homepage = "https://docs.rs/crate/clap/" +homepage = "https://clap.rs/" readme = "README.md" license = "MIT" keywords = ["argument", "command", "arg", "parser", "parse"] diff --git a/README.md b/README.md index ef391f8b31e..e02f7adac5d 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,14 @@ Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc) ## What's New +Here's the highlights for v2.13.0 + +* **Value Delimiters:** fixes the confusion around implicitly setting value delimiters. (The default is to *not* use a delimiter unless explicitly set) +* **Docs:** Updates README.md with new website information and updated video tutorials info +* **Docs:** Updates the docs about removing implicit `value_delimiter(true)` +* **Docs:** Adds better examples on using default values + + Here's the highlights for v2.12.1 * Fixes a regression-bug where the old `{n}` newline char stopped being replaced a properly re-aligned newline