0

This is the code (I'm using clap 3.2.20):

pub fn main() {
  let m = Command::new("foo")
    .arg(
      Arg::new("bar")
        .long("bar")
        .required(false)
        .action(ArgAction::SetTrue)
      )
    .get_matches();
  if m.contains_id("bar") {
    println!("Boom!");
  }
}

It prints Boom! either I provide --bar option or not. Why and how to fix?

yegor256
  • 102,010
  • 123
  • 446
  • 597
  • As I see on the docs is the behaviour of [`SetTrue`](https://docs.rs/clap/latest/clap/builder/enum.ArgAction.html#variant.SetTrue). `contains_id()` returns true, the difference is in the value. – Mario Santini Sep 05 '22 at 06:25
  • So, `action` is executed either the option was found in the command line or not? – yegor256 Sep 05 '22 at 06:26
  • I don't think so. The action is executed if the flag is present, but the check you do is not proper. You should access the value of the flag to know if it was present or not. – Mario Santini Sep 05 '22 at 06:27
  • @yegor256 it's not that `Action` is executed either way, it's that `SetTrue` specifically implies a default value (also `SetFalse`). Which makes sense: it's a flag, so why have a ternary boolean? – Masklinn Sep 05 '22 at 06:49
  • It doesn't make sense to me at all (I always thought that an "action" is something that is executed in response to some event), but let it be, as long as it works :) – yegor256 Sep 05 '22 at 06:56

1 Answers1

3

Per the documentation of contains_id

NOTE: This will always return true if default_value has been set. ArgMatches::value_source can be used to check if a value is present at runtime.

Now you might object that you're not using default_value, however you're using ArgAction::SetTrue:

When encountered, act as if "true" was encountered on the command-line

If no default_value is set, it will be false.

Emphasis mine.

So ArgAction::SetTrue implies default_value=false.

Therefore bar will always have a value, there's no need to check whether it does. Just fetch the value.

Masklinn
  • 34,759
  • 3
  • 38
  • 57