Skip to content

Commit

Permalink
Auto merge of #667 - kbknapp:issues-418,666, r=kbknapp
Browse files Browse the repository at this point in the history
Issues 418,666
  • Loading branch information
homu committed Sep 18, 2016
2 parents ecc6d89 + aad171d commit 7483cec
Show file tree
Hide file tree
Showing 7 changed files with 225 additions and 32 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
<a name="v2.13.0"></a>
## 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))



<a name="v2.12.1"></a>
### v2.12.1 (2016-09-13)

Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[package]

name = "clap"
version = "2.12.1"
version = "2.13.0"
authors = ["Kevin K. <[email protected]>"]
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"]
Expand Down
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
=================
Expand Down Expand Up @@ -39,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
Expand Down Expand Up @@ -335,7 +345,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`

Expand Down Expand Up @@ -627,9 +637,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

Expand Down
29 changes: 24 additions & 5 deletions examples/10_default_values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,38 @@ extern crate clap;
use clap::{App, Arg};

fn main() {
// You can get a "default value" like feature by using Option<T>'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 <config> 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 <file> 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);
}
}
48 changes: 26 additions & 22 deletions src/args/arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1871,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.
Expand All @@ -1896,7 +1876,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// assert_eq!(delims.values_of("option").unwrap().collect::<Vec<_>>(), ["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};
Expand Down Expand Up @@ -1937,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.
///
Expand Down Expand Up @@ -2002,12 +1984,15 @@ impl<'a, 'b> Arg<'a, 'b> {
/// assert!(delims.is_present("opt"));
/// assert_eq!(delims.values_of("opt").unwrap().collect::<Vec<_>>(), ["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);
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)
}
Expand Down Expand Up @@ -2201,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")
Expand All @@ -2215,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
Expand Down
139 changes: 139 additions & 0 deletions tests/delimiters.rs
Original file line number Diff line number Diff line change
@@ -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::<Vec<_>>(), &["val1", "val2", "val3"]);
}
Loading

0 comments on commit 7483cec

Please sign in to comment.