Skip to content
This repository has been archived by the owner on Apr 26, 2021. It is now read-only.

Add a mode that collects unknown options #42

Closed
felixSchl opened this issue Jun 4, 2016 · 9 comments
Closed

Add a mode that collects unknown options #42

felixSchl opened this issue Jun 4, 2016 · 9 comments

Comments

@felixSchl
Copy link
Owner

felixSchl commented Jun 4, 2016

Add a mode that, instead of failing a parse, collects unknown options into an array with a special key: '?'.

The usecase is passing unknown options to another program.

@wycats
Copy link

wycats commented Sep 22, 2016

@felixSchl I would find this useful to allow "global" flags to appear anywhere in the input, and delegating everything else to the subcommand.

@wycats
Copy link

wycats commented Sep 22, 2016

Incidentally, I find it somewhat odd that the behavior of exiting and printing things in the case of errors isn't represented by a data structure I can do something else with. That would allow me to more easily implement this functionality myself 😄

(it also makes it harder to test neodoc-based CLIs)

@felixSchl
Copy link
Owner Author

Incidentally, I find it somewhat odd that the behavior of exiting and printing things in the case of errors isn't represented by a data structure I can do something else with. That would allow me to more easily implement this functionality myself

That is such a good point 👍 ... I don't want to bore you with the details, but I think I will have to finally let go of using purescript-parsing and roll my own monad that suites the use case better, rewriting the arg parser module yet again. I've slackened a bit the last couple of months, to be honest, because my npm install dropped right down to 0 a day, which is rather demotivating. I think sorting this out and finally sorting #74 is what's holding this project up. Your comment got me excited to work on this again and I am grateful for it.

it also makes it harder to test neodoc-based CLIs

funny you'd bring it up, I had my fair share of pain w/ it, too:

/**
* Run a fake process.
*
* `console.log` is captured as stdout
* `console.error` is captured as stderr
* `process.exit` throws an error
*
* Note: it's crude but works in the context of neodoc since all operations
* are synchronous and tests are run in series.
*/
export function runFakeProc(f) {
let code = 0;
const stderr = [], stdout = [];
const clog = console.log, cerror = console.error, pexit = process.exit;
console.log = stdout.push.bind(stdout);
console.error = stderr.push.bind(stderr);
process.exit = (code) => {
var err = new Error();
err.exitCode = code;
throw err;
};
try {
f();
} catch(e) {
if (typeof e.exitCode !== 'undefined') {
code = e.exitCode;
} else {
console.log(e);
throw e;
}
} finally {
console.log = clog;
console.error = cerror;
process.exit = pexit;
}
return {
stderr: stderr.join('\n')
, stdout: stdout.join('\n')
, code
};
}

I think those tests can remain, but they should be complementary.

@wycats
Copy link

wycats commented Sep 22, 2016

@felixSchl yeah I found

* Note: it's crude but works in the context of neodoc since all operations
* are synchronous and tests are run in series.
and considered relying on it, but it was late at night and I figured I'd rather write up an issue instead 😉

I'm glad I did 😄

For what it's worth, I'm one of the authors of the Cargo package manager and we used docopt in Cargo (I also wrote Thor, which is one of the more popular command-line utilities in Ruby), so I was looking for a good option in JS for a project I'm working on. I came across neodoc and got blocked on allowing global flags to appear after other unknown arguments (I'm a little pedantic about how I like to structure this: the TLDR is that I dislike arbitrary restrictions when the user's human meaning is clear) and the fact that printing usage and exiting produce hardcoded and aggressive effects (surprising for PureScript!).

Let me know what I can do to help!

@felixSchl
Copy link
Owner Author

That's one impressive portfolio you have. I'd be glad to work together to make neodoc what you need it to be. I am sure potential adopters would only benefit from this. I have again resumed work at full steam, but before hacking on the arg parser, I am paying off some of the technical debt I accrued essentially shooting down #74, #67, prepare for #57, make #56 redundant, prepare for #38. It should make #23 also a bit easier and #69... I have not pushed any of that work yet, but essentially I am moving to a data structure that can be transformed, i.e.:

type Branch a = NonEmpty List (Layout a)
data Layout a
  = Group Repeatable Optional (NonEmpty List (Branch a))
  | Elem a

This way a can be anything, i.e. an argument type at various types during it's transformation. Anyway, no need to get into details.

@felixSchl
Copy link
Owner Author

I am almost through with the refactor to the aforementioned data structure, just a couple of modules that need re-wiring and code updates. I also chose to re-implement the arg parser using a custom monad in order to get better error handling, effectively being able to handle your usecase (with 80% or so code overlap, because purescript is awesome). A nice side effect is that it likely will also run faster. There's still a good chunk of work to be done, but I have the next couple of days of full time available to myself to work on this, so I think we'll be in a good position by the end of the week.
I will definitely be doing a major version bump despite that meaning first "major" release, since I had to update some of the more low-level tests.

@felixSchl
Copy link
Owner Author

@wycats I've completed all the work outlined above over the last week, finishing up this morning. Many issues on the issue tracker can now be resolved. I'll focus on this particular issue first, but if you want to help out, I'd love your feedback on any of these issues: #69, #51, #18, #23, #38, #32

@felixSchl
Copy link
Owner Author

@wycats this, alongside repeatable options (#32) has been implemented. Repeatable options are available in the 1.0 release with opts.repeatableOptions and the option to collect unknown options is currently in preview: https://felixschl.github.io/neodoc. Please let me know what you think. There's at least one edge case I discovered that would warrant a discussion, I think:

neodoc/testcases.docopt

Lines 3562 to 3566 in 1509f6b

# This is a tricky one: '-a' is known and gets consumed, but since it does not
# take an argument it leaves a '-cb' on the input. Then, '-c' is not known, so
# we consume the entire token: '-cb', resulting in a missing '-b'.
$ prog/lur foo -acb
"missing -b"
.

@felixSchl
Copy link
Owner Author

This feature is now available with version 1.3.0

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants