Code Monkey home page Code Monkey logo

Comments (2)

Taywee avatar Taywee commented on July 29, 2024

Yes, but you'd need a custom validator for the options, because normal validating groups wouldn't work in this case (because --open or --close can both be omitted, meaning they'd pass validation if neither was specified, but if --now is specified, exactly one of them is required. Doing this with nested groups would make the validation of one group need to change based on the state of the other, which isn't possible out of the box with the current design). And because of the way that the group validation is implemented, you'd have to unfortunately rely on the order of the group's children to cleanly identify what is being done (because the validator is moved into the group, and must be specified before the flags are, so you couldn't have the validator as a function object that maintains a reference to its flags without some terrible hackery like placement new). Here's a functioning example:

#include <iostream>
#include "args.hxx"

bool OpenCloseNowValidator(const args::Group &group) {
    const args::Base *now = group.Children()[0];
    const args::Base *open = group.Children()[1];
    const args::Base *close = group.Children()[2];
    if (open->Matched() && close->Matched()) {
        return false;
    }

    if (now->Matched() && !(open->Matched() || close->Matched())) {
        return false;
    }
    return true;
}

int main(int argc, char **argv)
{
    args::ArgumentParser parser("This is a test program.");
    args::HelpFlag help(parser, "help", "Display this help menu", {'h', "help"});
    args::Group nowgroup(parser, "", OpenCloseNowValidator);
    args::Flag now(nowgroup, "now", "The now flag, needs --open or --close", {'n', "now"});
    args::Flag open(nowgroup, "open", "The open flag, mutually exclusive with --close", {'o', "open"});
    args::Flag close(nowgroup, "close", "The close flag, mutually exclusive with --open", {'c', "close"});
    try {
        parser.ParseCLI(argc, argv);
    }
    catch (const args::ValidationError &e)
    {
        std::cerr << "Illegal options specified!" << std::endl;
        return 1;
    }
    catch (const args::Help&)
    {
        std::cout << parser;
        return 0;
    }
    catch (const args::ParseError& e)
    {
        std::cerr << e.what() << std::endl;
        return 1;
    }

    return 0;
}

And it in action:

$ ./test -h
  ./test {OPTIONS}

    This is a test program.

  OPTIONS:

      -h, --help                        Display this help menu
      -n, --now                         The now flag, needs --open or --close
      -o, --open                        The open flag, mutually exclusive with
                                        --close
      -c, --close                       The close flag, mutually exclusive with
                                        --open


$ ./test -o

$ ./test -c

$ ./test -on

$ ./test -cn

$ ./test -oc
Illegal options specified!

$ ./test -n 
Illegal options specified!

$ ./test -noc
Illegal options specified!

Unfortunately, the current API makes it impossible to give good messages with validation, either with the custom validators or with the inbuilt ones. In a future major release, this may be reeled back so that validators don't just return true or false, but actually throw exceptions when failing validation, and group nesting will probably be made illegal, requiring that any complex validation demands that the end programmer implement it themselves, if I get back into major feature development of this library sufficient enough to make a major release like that. I'd have to also consider a way for group validation to better access its children, as order-dependent validation in this case presents a painful case for code management, as reordering variables could easily break validation.

Anyway, I hope this is sufficient enough for your use.

from args.

darealshinji avatar darealshinji commented on July 29, 2024

In case someone needs this, one solution can be to treat the boolean return values of the arguments like integers and add them up together:

args::Flag arg_myarg1(/* ... */);
args::Flag arg_myarg2(/* ... */);
args::Flag arg_myarg3(/* ... */);
/* ... */

if (arg_myarg1 + arg_myarg2 + arg_myarg3 /* ... */ > 1) {
  // error
}

from args.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.