-
-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Iterating over ArgMatches
#1206
Comments
Sorry for the wait, I've been on vacation with my kids this past week :) Do you mean iterating over only positional values, or over all args that have been used? Also, do you envision this iterating over non-matched args as well? If you'd like to take a stab at implementing I'd be happy to mentor you! This is how I'd attack it:
For the implementation once we have a good design I can give you some pointers as to where the changes you'll want to make are located / any particulars associated with those changes. Once all your new tests pass, I'd run a full test suite If you need to see the debug output while you're building testing a single function use |
First of all, thanks for taking the time to address this! I hope you enjoyed your vacation. The API I had in mind wouldn't be constrained only to positional arguments, but to all the arguments that have been used. Currently I mean adding an API to access the order in which options are given. Ex.:
Let's say my command's behavior is specific to the order in which the options
This example is just off the top of my head and I am sure it could be improved. Please correct me if I talked nonsense at any point because I am not very familiar with the API. |
To make sure it's not an The only other form I've seen is for things like include/exclude logic where there aren't really hard conflicts/overrides at the parsing level, but further up the execution stack there are. I've only seen this between a handlful of args at the most, and hence iterating over the indices isn't an issue. This is of course not to say my list is exhaustive, I'm sure there are other use cases out there! This actually wouldn't be a huge change for clap to implement this, but it would introduce an additional dep (such as The change you'd make is using For the iterator itself, it'd fine to use the |
Another more lengthy option (but arguably more correct) is instead of returning an Iterator of some custom data type tuple, returning the |
My application has a custom
However there are many other use cases. Tasks execution order in a Gulp-like application, apply filters in a specific order in GNU find, ecc. |
That's a pity. I thought it would be as simple as adding a method to |
Right now, clap uses a So it basically would be just a cfg statement which adds the method on the matches struct and uses an indexmap instead of hashmap. And I'd create a struct to act as the iterator, and impl Iterator for it. Something like (details left out for brevity): #[cfg(not(feature = "indexmap"))]
struct ArgMatches {
args: HashMap
}
#[cfg(feature = "indexmap")]
struct ArgMatches {
args: IndexMap
}
impl ArgMatches {
#[cfg(feature = "indexmap")]
fn iter(&self) -> MatchIter {
MatchIter { iter: self.args.iter() }
}
}
#[cfg(feature = "indexmap")]
struct MatchIter {
iter: // whatever IndexMap::iter returns
}
#[cfg(feature = "indexmap")]
impl Iterator for MatchIter {
type Item = // whatever args.iter().next() returns
fn next(&mut self) -> Self::Item {
self.iter().next()
}
} So it's a pretty straight forward change. |
Thanks for the tips, I'll start working on a prototype then. 👍 |
I feel hesitant adding an |
You can take a look at the prototype here. There is some more work to do, specifically:
Please let me know how you like the API and if you want any changes. Congrats on the codebase BTW, I know this is a small change but still, it is a pleasure to dive in. |
My current policy is public, but undocumented internals are effectively private and should not be relied on. Sure, I can't stop anyone from using them directly, but there's the caveat that if I change them without warning it's considered a breaking change. Hence the Most of the time public but undocumented is because it needs to be public because other mods (or eventually crates) need to touch it, but those mods (or crates) are maintained by myself or other clap members and thus it's essentially just a private API. |
Looks like a good start! It's a small nit, but let's change the feature name to Let me know if you have any other questions 👍 |
I'll create a PR for discussing further details, sounds good? |
Yep, I'd actually prefer it that way because it's easier to comment and review 😄 👍 |
I also need this functionality |
Hi all, I'm also looking to use something like this. I'd like to process my args in a functional fashion. The PR, however, seems to have died a death. Given that 3.0 is on the horizon how much of a bad idea is it for me to just use PS, I don't need ordering. |
@bradwood Not as bad as you'd think: 2.x branch is frozen. I'd be really surprised if we change something regarding publicity of those fields because there is plenty of code out there relying on those, ugh. So, if you aren't planning on switching to 3.0 and you're OK with the fact that every time you use private API god kills a kitten, you can do that, yes. Beware: those will be truly private in 3.0. I suspect it won't make it into 3.0. The main question is: what are you going to iterate through? You can't have |
i am trying to call And, as regards the kittens, I'm cool with that! :) |
clap has |
I think I can see a certain use case for this where people want to do dependency injection pattern for evaluating their args. |
For a while I was floating around the idea of adding filter/map capabilities to arguments themselves, in a similar manner to the current But others also wanted more a "handler" type functionality (which is something some python libraries offer). This can be done already by (hackily) using the validator functionality. Currently, the mapping of values can be done pretty easily after the parsing in user code manually, but not during parsing. I'm not 100% sure where I fall on the thinking of this one though, as is the added complexity and public API space worth the small benefit of doing something at parse time instead of manually afterwards? Also perhaps more importantly, have users thought through what happens if a particular map/filter/handler whatever we'd call it has side affects, but parsing ultimately fails? Maybe that's just a, "hey probably best you don't have side affects, but if you do be aware it can have XYZ consequences." I mean you can already (mis)use the validators for handlers, so I'd be less inclined to include that functionality. |
Resolved by derive (and partially by I'm not sure I get your "handlers" idea, I imagine it's something akin #1185:
Some thoughts:
In nutshell: I think this kind of tool is too vague and too powerful for a command line parsing library to provide. I don't think clap should be trying to accommodate every single CLI in existence, the number of well-supported designs is quite enough already. |
FWIW, I'm not needing these |
@bradwood Out of morbid curiosity, what is the core problem you're trying to solve? Why do you think I suspect you're just "doing it wrong". |
Exactly. I'm describing a problem/issue that existed prior to derive macros. The "handlers" was just a common theme that popped up every so often, especially when people were moving from Python based CLIs which offer a "when this argument is used, run this function." Although that's a totally different way to build/design a CLI and thus I don't think it's really applicable to how clap runs.
100% agree. I'm just providing some historic context 😉 @bradwood I agree with @CreepySkeleton it sounds like you may be approaching the problem from a particular design angle and we may be seeing it as an XY problem. Some of the principal issues with a feature mapping over arguments (and their values) is:
Those final three bullets are some of what making this feature a general clap feature difficult. If you don't have any of those requirements and are truly only wanting blind side affects, I'd question if there may be a better way to represent the CLI. If you can give some examples of what you're trying to do, we may be able to either point you in a direction or give you a way to accomplish that task with existing features. |
Writing this comment because of #3286: absence of iterator blocks our update from 2x to 3x |
@tonyshkurenko can you expand on the use case for why this blocks updating? |
I mean we literally used field Line 66 in d51ae89
Part of our app was based on this. Now it's not available (correct me, if I'm wrong) without any alternative. That's why we can't update |
Yes, I am asking for your use case or why you use the field. What problem are you trying to solve by accessing |
I was attempting this about a year ago, and my particular use case was either:
|
I was looking at exposing a We only store an In general, resolving this is getting hairy and something we are unlikely to want to take on. Our current plan is to wait around 6 months at minimum between major breaking releases (which this change would probably be part of), so we are looking around June for resolving this. |
Also, when implementing this, my expectation is that we'll provide something like: pub fn present_arg_ids(&self) -> Iterator<Item=&Id>
|
So if I want to iterate over matched arguments (flags) how should I approach this today? |
You'll need to define a slice of all of you argument IDs (names) and iterate through that. |
Does that mean I have to check if the flag was set. Because I have dozens of flags, so it seems to me to be a waste to check for all flags when I only want to know which flags were set. |
Yes. This is just a workaround. Like I said, we cannot fix this until clap 4.0. |
A few minor cleanups to make it easier to submit PRs: * migrate to 2021 edition * run `cargo fmt` * bump some dependencies to their latest * Note that Clap is locked to 2.x until clap-rs/clap#1206 is fixed in v4 (?) * spelling fixes TODO for another PR: * fix many clippy [from_over_into](https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into) warnings in the src/map/map_value.rs file. * README.md still has a few bugs. Uncomment a section in the lib.rs to show them during the test run.
@epage thx for all the hard work on this! Is there a PR or some other work being done in this space? Per #2763 (comment), it seems all layered configuration projects need to be able to enumerate over |
From my note I added in the issue
We cannot make these changes in clap v3 and but this should be available in clap v4.0.0. My expectation is that I'm going to soon wrap up the work I'm doing for clap 3.2, give time to collect and handle any feedback, and then start on v4.0.0. v3.2 is a big change, see #3732. My intention is to make this big change right before 4.0 so we don't have to live a long time with any mistakes identified through feedback. |
For now, we are focusing only on iterating over the argument ids and not the values. This provides a building block for more obscure use cases like iterating over argument values, in order. We are not providing it out of the box at the moment both to not overly incentize a less common case, because it would abstract away a performance hit, and because we want to let people experiment with this and if a common path emerges we can consider it then if there is enough users. Fixes clap-rs#1206
Maintainer's notes
Id
s for arguments to something the user can programmatically act onHi, I am using Clap in a little side project and I would like to suggest a minor feature. I am ready to implement it myself and send a PR if needed, I just need a few pointers. The feature at hand is an ordered iterator over
ArgMatches
: as far as my understanding goes, Clap doesn't allow to freely iterate over the parsed arguments. What if my application APIs are dependent upon the order of the arguments? GNUfind
comes to my mind. Callingindex_of
for every argument can be expensive if you have a lot of them.If this feature were to be implemented, what would the return type and name of the method be?
The text was updated successfully, but these errors were encountered: