Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Allow required unmatched positional arguments #21

Closed
wants to merge 1 commit into from

2 participants

Sonny Michaud Heather Arthur
Sonny Michaud

Hello!

I have really been enjoying using nomnom, but I have found a use case I was unable to perform. I wanted to allow the user to specify a command, and have a trailing list of unmatched positional arguments, but at least one was required.

The problem therein was that, it is not possible to specify positional arguments that behave this way, as I do not know before hand the index at which they will begin.

I am not sure if this is something you want to pull in, but I think others could find it useful, e.g. as a workaround for #12 . I tried to follow your code conventions, but please let me know if this pull request needs any work - if you decide to pull it in I can document this feature in the README.

Thanks!

Sonny Michaud sonnym allow required unmatched positional arguments
By having a separate spec for positional arguments, it is possible to
have options come before, and then simply use the list of positionals in
_ aftering parsing.

Before this change, it was only posible to specify positional options,
which appear before typical options in the usage output
a2dc165
Heather Arthur
Owner

Do the list: true, required: true options not satisfy your requirements? You can use it with positionals and it will capture an array of all the positionals after a certain position.

Can you give an example use case?

Sonny Michaud

Thanks for the response on this @harthur - I have really enjoyed working with nomnom thus far.

Those options, unfortunately, do not quite seem to work for me, in terms of I just want to capture all trailing positionals, but I also want at least one to be required.

I am looking more for something along the lines of: git add [options] <list of files> when printing and parsing the help message. I would prefer for them to be trailing positionals, which the pull request attempts to address but with admittedly poor semantics, rather than a separate option such as git add --files list,of.

One problem I encounter with the way positionals currently work is that they have a priority over options, so something that could simply be a mistake like git commit a --amend bar would add both "a" and "bar" to the unmatched positional arguments array.

Ultimately my goal is to have a listing of all positionals after the options - something like a trailing options array - and an error thrown on any unexpected positionals before that point. I am pretty much amenable to any solution, but I do not think nomnom can really handle this use case yet - please let me know if I am being daft and missing something or if you would prefer a different implementation or anything else.

Thanks again!

Heather Arthur
Owner

Okay, thanks for clearing that up. Sorry for not getting back sooner as well, I've been busy at work.

I tended to think that allowing the positionals to be anywhere was a good thing. I think it would be confusing to both allow them everywhere and have some required ones expected to be at the end. Would fixing issue #12 be sufficient for you? I think that would be less confusing.

Sonny Michaud sonnym closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 8, 2012
  1. Sonny Michaud

    allow required unmatched positional arguments

    sonnym authored
    By having a separate spec for positional arguments, it is possible to
    have options come before, and then simply use the list of positionals in
    _ aftering parsing.
    
    Before this change, it was only posible to specify positional options,
    which appear before typical options in the usage output
This page is out of date. Refresh to see the latest.
Showing with 36 additions and 1 deletion.
  1. +19 −1 nomnom.js
  2. +17 −0 test/expected.js
20 nomnom.js
View
@@ -5,6 +5,7 @@ var _ = require("underscore")._,
function ArgParser() {
this.commands = {}; // expected commands
this.specs = {}; // option specifications
+ this.positional_spec = {}; // specification for positional arguments
}
ArgParser.prototype = {
@@ -77,6 +78,11 @@ ArgParser.prototype = {
return this;
},
+ positionals : function(spec) {
+ this.positional_spec = spec;
+ return this;
+ },
+
usage : function(usage) {
this._usage = usage;
return this;
@@ -244,8 +250,16 @@ ArgParser.prototype = {
this.setOption(options, index, pos);
}, this);
+ if (this.positional_spec.required && positionals.length == 0) {
+ if (this.positional_spec.help) {
+ this.print(this.positional_spec.help + "\n" + this.getUsage(), 1);
+ } else {
+ this.print("At least one positional argument is required\n" + this.getUsage(), 1);
+ }
+ }
+
options._ = positionals;
-
+
this.specs.forEach(function(opt) {
if (opt.default !== undefined && options[opt.name] === undefined) {
options[opt.name] = opt.default;
@@ -327,6 +341,10 @@ ArgParser.prototype = {
str += " [options]";
}
}
+
+ if (this.positional_spec.required) {
+ str += " <" + this.positional_spec.name + ">...";
+ };
if (options.length || positionals.length) {
str += "\n\n";
17 test/expected.js
View
@@ -57,3 +57,20 @@ exports.testChoices = function(test) {
test.equal(options.color, 'green');
test.done();
}
+
+exports.testPositionalArgumentsRequired = function(test) {
+ test.expect(2);
+ var help = "something about positionals being required";
+
+ var parser = nomnom().positionals({
+ required: true, help: help, name: "foobarpositionals"
+ })
+ .printer(function(string) {
+ test.equal(0, string.indexOf(help))
+ test.ok(string.indexOf("<foobarpositionals>..." > 0));
+ });
+
+ parser.parse([]);
+
+ test.done();
+}
Something went wrong with that request. Please try again.