[Pkg-javascript-commits] [node-nomnom] 01/02: Imported Upstream version 1.8.1

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Fri Mar 20 20:47:44 UTC 2015


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository node-nomnom.

commit 64904f5383324dfde760ee722ad55c5c9963883a
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Tue Mar 17 22:30:20 2015 +0100

    Imported Upstream version 1.8.1
---
 .npmignore        |   1 +
 LICENSE           |  20 ++
 README.md         | 325 ++++++++++++++++++++++++++++++
 nomnom.js         | 584 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 num-vals-fix.diff |  31 +++
 package.json      |  28 +++
 test.js           |  23 +++
 test/callback.js  |  33 +++
 test/commands.js  | 120 +++++++++++
 test/expected.js  |  60 ++++++
 test/matching.js  |  70 +++++++
 test/option.js    |  44 ++++
 test/transform.js |  65 ++++++
 test/usage.js     | 121 +++++++++++
 test/values.js    |  75 +++++++
 15 files changed, 1600 insertions(+)

diff --git a/.npmignore b/.npmignore
new file mode 100644
index 0000000..3c3629e
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1 @@
+node_modules
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..8092929
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2010 Heather Arthur
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5864a09
--- /dev/null
+++ b/README.md
@@ -0,0 +1,325 @@
+# nomnom
+nomnom is an option parser for node. It noms your args and gives them back to you in a hash.
+
+```javascript
+var opts = require("nomnom")
+   .option('debug', {
+      abbr: 'd',
+      flag: true,
+      help: 'Print debugging info'
+   })
+   .option('config', {
+      abbr: 'c',
+      default: 'config.json',
+      help: 'JSON file with tests to run'
+   })
+   .option('version', {
+      flag: true,
+      help: 'print version and exit',
+      callback: function() {
+         return "version 1.2.4";
+      }
+   })
+   .parse();
+
+if (opts.debug)
+   // do stuff
+```
+
+You don't have to specify anything if you don't want to:
+
+```javascript
+var opts = require("nomnom").parse();
+
+var url = opts[0];     // get the first positional arg
+var file = opts.file   // see if --file was specified
+var verbose = opts.v   // see if -v was specified
+var extras = opts._    // get an array of the unmatched, positional args
+```
+
+# Install
+for [node.js](http://nodejs.org/) and [npm](http://github.com/isaacs/npm):
+
+	npm install nomnom
+
+# More Details
+Nomnom supports args like `-d`, `--debug`, `--no-debug`, `--file=test.txt`, `--file test.txt`, `-f test.txt`, `-xvf`, and positionals. Positionals are arguments that don't fit the `-a` or `--atomic` format and aren't attached to an option.
+
+Values are JSON parsed, so `--debug=true --count=3 --file=log.txt` would give you:
+
+```
+{
+   "debug": true,
+   "count": 3,
+   "file": "log.txt"
+}
+```
+
+# Commands
+Nomnom supports command-based interfaces (e.g. with git: `git add -p` and `git rebase -i` where `add` and `rebase` are the commands):
+
+```javascript
+var parser = require("nomnom");
+
+parser.command('browser')
+   .callback(function(opts) {
+      runBrowser(opts.url);
+   })
+   .help("run browser tests");
+
+parser.command('sanity')
+   .option('outfile', {
+      abbr: 'o',
+      help: "file to write results to"
+   })
+   .option('config', {
+      abbr: 'c',
+      default: 'config.json',
+      help: "json manifest of tests to run"
+   })
+   .callback(function(opts) {
+      runSanity(opts.filename);
+   })
+   .help("run the sanity tests")
+
+parser.parse();
+```
+
+Each command generates its own usage message when `-h` or `--help` is specified with the command.
+
+# Usage
+Nomnom prints out a usage message if `--help` or `-h` is an argument. Usage for these options in `test.js`:
+
+```javascript
+var opts = require("nomnom")
+   .script("runtests")
+   .options({
+      path: {
+         position: 0,
+         help: "Test file to run",
+         list: true
+      },
+      config: {
+         abbr: 'c',
+         metavar: 'FILE',
+         help: "Config file with tests to run"
+      },
+      debug: {
+         abbr: 'd',
+         flag: true,
+         help: "Print debugging info"
+      }
+   }).parse();
+```
+
+...would look like this:
+
+	usage: runtests <path>... [options]
+
+	path     Test file to run
+
+	options:
+	   -c FILE, --config FILE   Config file with tests to run
+	   -d, --debug              Print debugging info
+
+# Options
+You can either add a specification for an option with `nomnom.option('name', spec)` or pass the specifications to `nomnom.options()` as a hash keyed on option name. Each option specification can have the following fields:
+
+#### abbr and full
+`abbr` is the single character string to match to this option, `full` is the full-length string (defaults to the name of the option).
+
+This option matches `-d` and `--debug` on the command line:
+
+```javascript
+nomnom.option('debug', {
+   abbr: 'd'
+})
+```
+
+This option matches `-n 3`, `--num-lines 12` on the command line:
+
+```javascript
+nomnom.option('numLines', {
+   abbr: 'n',
+   full: 'num-lines'
+})
+```
+
+#### flag
+
+If this is set to true, the option acts as a flag and doesn't swallow the next value on the command line. Default is `false`, so normally if you had a command line `--config test.js`, `config` would get a value of `test.js` in the options hash. Whereas if you specify:
+
+```javascript
+nomnom.option('config', {
+   flag: true
+})
+```
+
+`config` would get a value of `true` in the options hash, and `test.js` would be a free positional arg.
+
+#### metavar
+
+`metavar` is used in the usage printout e.g. `"PATH"` in `"-f PATH, --file PATH"`.
+
+#### string
+
+A shorthand for `abbr`, `full`, and `metavar`. For example, to attach an option to `-c` and `--config` use a `string: "-c FILE, --config=FILE"`
+
+#### help
+
+A string description of the option for the usage printout.
+
+#### default
+
+The value to give the option if it's not specified in the arguments.
+
+#### type
+
+If you don't want the option JSON-parsed, specify type `"string"`.
+
+#### callback
+
+A callback that will be executed as soon as the option is encountered. If the callback returns a string it will print the string and exit:
+
+```javascript
+nomnom.option('count', {
+   callback: function(count) {
+      if (count != parseInt(count)) {
+         return "count must be an integer";
+      }
+   }
+})
+```
+
+#### position
+
+The position of the option if it's a positional argument. If the option should be matched to the first positional arg use position `0`, etc.
+
+#### list
+
+Specifies that the option is a list. Appending can be achieved by specifying the arg more than once on the command line:
+
+	node test.js --file=test1.js --file=test2.js
+
+If the option has a `position` and `list` is `true`, all positional args including and after `position` will be appended to the array.
+
+#### required
+
+If this is set to `true` and the option isn't in the args, a message will be printed and the program will exit.
+
+#### choices
+
+A list of the possible values for the option (e.g. `['run', 'test', 'open']`). If the parsed value isn't in the list a message will be printed and the program will exit.
+
+#### transform
+
+A function that takes the value of the option as entered and returns a new value that will be seen as the value of the option.
+
+```javascript
+nomnom.option('date', {
+   abbr: 'd',
+   transform: function(timestamp) {
+     return new Date(timestamp);
+   }
+})
+```
+
+#### hidden
+
+Option won't be printed in the usage
+
+
+# Parser interface
+`require("nomnom")` will give you the option parser. You can also make an instance of a parser with `require("nomnom")()`. You can chain any of these functions off of a parser:
+
+#### option
+
+Add an option specification with the given name:
+
+```javascript
+nomnom.option('debug', {
+   abbr: 'd',
+   flag: true,
+   help: "Print debugging info"
+})
+```
+
+#### options
+
+Add options as a hash keyed by option name, good for a cli with tons of options like [this example](http://github.com/harthur/replace/blob/master/bin/replace.js):
+
+```javascript
+nomnom.options({
+   debug: {
+      abbr: 'd',
+      flag: true,
+      help: "Print debugging info"
+   },
+   fruit: {
+      help: "Fruit to buy"
+   }
+})
+```
+
+#### usage
+
+The string that will override the default generated usage message.
+
+#### help
+
+A string that is appended to the usage.
+
+#### script
+
+Nomnom can't detect the alias used to run your script. You can use `script` to provide the correct name for the usage printout instead of e.g. `node test.js`.
+
+#### printer
+
+Overrides the usage printing function.
+
+#### command
+
+Takes a command name and gives you a command object on which you can chain command options.
+
+#### nocommand
+
+Gives a command object that will be used when no command is called.
+
+#### nocolors
+
+Disables coloring of the usage message.
+
+#### parse
+
+Parses node's `process.argv` and returns the parsed options hash. You can also provide argv:
+
+```javascript
+var opts = nomnom.parse(["-xvf", "--atomic=true"])
+```
+
+#### nom
+
+The same as `parse()`.
+
+# Command interface
+A command is specified with `nomnom.command('name')`. All these functions can be chained on a command:
+
+#### option
+
+Add an option specifically for this command.
+
+#### options
+
+Add options for this command as a hash of options keyed by name.
+
+#### callback
+
+A callback that will be called with the parsed options when the command is used.
+
+#### help
+
+A help string describing the function of this command.
+
+#### usage
+
+Override the default generated usage string for this command.
diff --git a/nomnom.js b/nomnom.js
new file mode 100644
index 0000000..3155974
--- /dev/null
+++ b/nomnom.js
@@ -0,0 +1,584 @@
+var _ = require("underscore"), chalk = require('chalk');
+
+
+function ArgParser() {
+   this.commands = {};  // expected commands
+   this.specs = {};     // option specifications
+}
+
+ArgParser.prototype = {
+  /* Add a command to the expected commands */
+  command : function(name) {
+    var command;
+    if (name) {
+      command = this.commands[name] = {
+        name: name,
+        specs: {}
+      };
+    }
+    else {
+      command = this.fallback = {
+        specs: {}
+      };
+    }
+
+    // facilitates command('name').options().cb().help()
+    var chain = {
+      options : function(specs) {
+        command.specs = specs;
+        return chain;
+      },
+      opts : function(specs) {
+        // old API
+        return this.options(specs);
+      },
+      option : function(name, spec) {
+        command.specs[name] = spec;
+        return chain;
+      },
+      callback : function(cb) {
+        command.cb = cb;
+        return chain;
+      },
+      help : function(help) {
+        command.help = help;
+        return chain;
+      },
+      usage : function(usage) {
+        command._usage = usage;
+        return chain;
+      }
+    };
+    return chain;
+  },
+
+  nocommand : function() {
+    return this.command();
+  },
+
+  options : function(specs) {
+    this.specs = specs;
+    return this;
+  },
+
+  opts : function(specs) {
+    // old API
+    return this.options(specs);
+  },
+
+  globalOpts : function(specs) {
+    // old API
+    return this.options(specs);
+  },
+
+  option : function(name, spec) {
+    this.specs[name] = spec;
+    return this;
+  },
+
+  usage : function(usage) {
+    this._usage = usage;
+    return this;
+  },
+
+  printer : function(print) {
+    this.print = print;
+    return this;
+  },
+
+  script : function(script) {
+    this._script = script;
+    return this;
+  },
+
+  scriptName : function(script) {
+    // old API
+    return this.script(script);
+  },
+
+  help : function(help) {
+    this._help = help;
+    return this;
+  },
+
+  colors: function() {
+    // deprecated - colors are on by default now
+    return this;
+  },
+
+  nocolors : function() {
+    this._nocolors = true;
+    return this;
+  },
+
+  parseArgs : function(argv) {
+    // old API
+    return this.parse(argv);
+  },
+
+  nom : function(argv) {
+    return this.parse(argv);
+  },
+
+  parse : function(argv) {
+    this.print = this.print || function(str, code) {
+      console.log(str);
+      process.exit(code || 0);
+    };
+    this._help = this._help || "";
+    this._script = this._script || process.argv[0] + " "
+          + require('path').basename(process.argv[1]);
+    this.specs = this.specs || {};
+
+    var argv = argv || process.argv.slice(2);
+
+    var arg = Arg(argv[0]).isValue && argv[0],
+        command = arg && this.commands[arg],
+        commandExpected = !_(this.commands).isEmpty();
+
+    if (commandExpected) {
+       if (command) {
+          _(this.specs).extend(command.specs);
+          this._script += " " + command.name;
+          if (command.help) {
+            this._help = command.help;
+          }
+          this.command = command;
+       }
+       else if (arg) {
+          return this.print(this._script + ": no such command '" + arg + "'", 1);
+       }
+       else {
+          // no command but command expected e.g. 'git -v'
+          var helpStringBuilder = {
+            list : function() {
+               return 'one of: ' + _(this.commands).keys().join(", ");
+            },
+            twoColumn : function() {
+              // find the longest command name to ensure horizontal alignment
+              var maxLength = _(this.commands).max(function (cmd) {
+                return cmd.name.length;
+              }).name.length;
+
+              // create the two column text strings
+              var cmdHelp = _.map(this.commands, function(cmd, name) {
+                var diff = maxLength - name.length;
+                var pad = new Array(diff + 4).join(" ");
+                return "  " + [ name, pad, cmd.help ].join(" ");
+              });
+              return "\n" + cmdHelp.join("\n");
+            }
+          };
+
+          // if there are a small number of commands and all have help strings,
+          // display them in a two column table; otherwise use the brief version.
+          // The arbitrary choice of "20" comes from the number commands git
+          // displays as "common commands"
+          var helpType = 'list';
+          if (_(this.commands).size() <= 20) {
+            if (_(this.commands).every(function (cmd) { return cmd.help; })) {
+                helpType = 'twoColumn';
+            }
+          }
+
+          this.specs.command = {
+            position: 0,
+            help: helpStringBuilder[helpType].call(this)
+          }
+
+          if (this.fallback) {
+            _(this.specs).extend(this.fallback.specs);
+            this._help = this.fallback.help;
+          } else {
+            this.specs.command.required = true;
+          }
+       }
+    }
+
+    if (this.specs.length === undefined) {
+      // specs is a hash not an array
+      this.specs = _(this.specs).map(function(opt, name) {
+        opt.name = name;
+        return opt;
+      });
+    }
+    this.specs = this.specs.map(function(opt) {
+      return Opt(opt);
+    });
+
+    if (argv.indexOf("--help") >= 0 || argv.indexOf("-h") >= 0) {
+      return this.print(this.getUsage());
+    }
+
+    var options = {};
+    var args = argv.map(function(arg) {
+      return Arg(arg);
+    })
+    .concat(Arg());
+
+    var positionals = [];
+
+    /* parse the args */
+    var that = this;
+    args.reduce(function(arg, val) {
+      /* positional */
+      if (arg.isValue) {
+        positionals.push(arg.value);
+      }
+      else if (arg.chars) {
+        var last = arg.chars.pop();
+
+        /* -cfv */
+        (arg.chars).forEach(function(ch) {
+          that.setOption(options, ch, true);
+        });
+
+        /* -v key */
+        if (!that.opt(last).flag) {
+           if (val.isValue)  {
+              that.setOption(options, last, val.value);
+              return Arg(); // skip next turn - swallow arg
+           }
+           else {
+              that.print("'-" + (that.opt(last).name || last) + "'"
+                + " expects a value\n\n" + that.getUsage(), 1);
+           }
+        }
+        else {
+          /* -v */
+          that.setOption(options, last, true);
+        }
+
+      }
+      else if (arg.full) {
+        var value = arg.value;
+
+        /* --key */
+        if (value === undefined) {
+          /* --key value */
+          if (!that.opt(arg.full).flag) {
+            if (val.isValue) {
+              that.setOption(options, arg.full, val.value);
+              return Arg();
+            }
+            else {
+              that.print("'--" + (that.opt(arg.full).name || arg.full) + "'"
+                + " expects a value\n\n" + that.getUsage(), 1);
+            }
+          }
+          else {
+            /* --flag */
+            value = true;
+          }
+        }
+        that.setOption(options, arg.full, value);
+      }
+      return val;
+    });
+
+    positionals.forEach(function(pos, index) {
+      this.setOption(options, index, pos);
+    }, this);
+
+    options._ = positionals;
+
+    this.specs.forEach(function(opt) {
+      if (opt.default !== undefined && options[opt.name] === undefined) {
+        options[opt.name] = opt.default;
+      }
+    }, this);
+
+    // exit if required arg isn't present
+    this.specs.forEach(function(opt) {
+      if (opt.required && options[opt.name] === undefined) {
+         var msg = opt.name + " argument is required";
+         msg = this._nocolors ? msg : chalk.red(msg);
+
+         this.print("\n" + msg + "\n" + this.getUsage(), 1);
+      }
+    }, this);
+
+    if (command && command.cb) {
+      command.cb(options);
+    }
+    else if (this.fallback && this.fallback.cb) {
+      this.fallback.cb(options);
+    }
+
+    return options;
+  },
+
+  getUsage : function() {
+    if (this.command && this.command._usage) {
+      return this.command._usage;
+    }
+    else if (this.fallback && this.fallback._usage) {
+      return this.fallback._usage;
+    }
+    if (this._usage) {
+      return this._usage;
+    }
+
+    // todo: use a template
+    var str = "\n"
+    if (!this._nocolors) {
+      str += chalk.bold("Usage:");
+    }
+    else {
+      str += "Usage:";
+    }
+    str += " " + this._script;
+
+    var positionals = _(this.specs).select(function(opt) {
+      return opt.position != undefined;
+    })
+    positionals = _(positionals).sortBy(function(opt) {
+      return opt.position;
+    });
+    var options = _(this.specs).select(function(opt) {
+      return opt.position === undefined;
+    });
+
+    // assume there are no gaps in the specified pos. args
+    positionals.forEach(function(pos) {
+      str += " ";
+      var posStr = pos.string;
+      if (!posStr) {
+        posStr = pos.name || "arg" + pos.position;
+        if (pos.required) {
+            posStr = "<" + posStr + ">";
+        } else {
+            posStr = "[" + posStr + "]";
+        }
+        if (pos.list) {
+          posStr += "...";
+        }
+      }
+      str += posStr;
+    });
+
+    if (options.length) {
+      if (!this._nocolors) {
+        // must be a better way to do this
+        str += chalk.blue(" [options]");
+      }
+      else {
+        str += " [options]";
+      }
+    }
+
+    if (options.length || positionals.length) {
+      str += "\n\n";
+    }
+
+    function spaces(length) {
+      var spaces = "";
+      for (var i = 0; i < length; i++) {
+        spaces += " ";
+      }
+      return spaces;
+    }
+    var longest = positionals.reduce(function(max, pos) {
+      return pos.name.length > max ? pos.name.length : max;
+    }, 0);
+
+    positionals.forEach(function(pos) {
+      var posStr = pos.string || pos.name;
+      str += posStr + spaces(longest - posStr.length) + "     ";
+      if (!this._nocolors) {
+        str += chalk.grey(pos.help || "")
+      }
+      else {
+        str += (pos.help || "")
+      }
+      str += "\n";
+    }, this);
+    if (positionals.length && options.length) {
+      str += "\n";
+    }
+
+    if (options.length) {
+      if (!this._nocolors) {
+        str += chalk.blue("Options:");
+      }
+      else {
+        str += "Options:";
+      }
+      str += "\n"
+
+      var longest = options.reduce(function(max, opt) {
+        return opt.string.length > max && !opt.hidden ? opt.string.length : max;
+      }, 0);
+
+      options.forEach(function(opt) {
+        if (!opt.hidden) {
+          str += "   " + opt.string + spaces(longest - opt.string.length) + "   ";
+
+          var defaults = (opt.default != null ? "  [" + opt.default + "]" : "");
+          var help = opt.help ? opt.help + defaults : "";
+          str += this._nocolors ? help: chalk.grey(help);
+
+          str += "\n";
+        }
+      }, this);
+    }
+
+    if (this._help) {
+      str += "\n" + this._help;
+    }
+    return str;
+  }
+};
+
+ArgParser.prototype.opt = function(arg) {
+  // get the specified opt for this parsed arg
+  var match = Opt({});
+  this.specs.forEach(function(opt) {
+    if (opt.matches(arg)) {
+       match = opt;
+    }
+  });
+  return match;
+};
+
+ArgParser.prototype.setOption = function(options, arg, value) {
+  var option = this.opt(arg);
+  if (option.callback) {
+    var message = option.callback(value);
+
+    if (typeof message == "string") {
+      this.print(message, 1);
+    }
+  }
+
+  if (option.type != "string") {
+     try {
+       // infer type by JSON parsing the string
+       value = JSON.parse(value)
+     }
+     catch(e) {}
+  }
+
+  if (option.transform) {
+     value = option.transform(value);
+  }
+
+  var name = option.name || arg;
+  if (option.choices && option.choices.indexOf(value) == -1) {
+     this.print(name + " must be one of: " + option.choices.join(", "), 1);
+  }
+
+  if (option.list) {
+    if (!options[name]) {
+      options[name] = [value];
+    }
+    else {
+      options[name].push(value);
+    }
+  }
+  else {
+    options[name] = value;
+  }
+};
+
+
+/* an arg is an item that's actually parsed from the command line
+   e.g. "-l", "log.txt", or "--logfile=log.txt" */
+var Arg = function(str) {
+  var abbrRegex = /^\-(\w+?)$/,
+      fullRegex = /^\-\-(no\-)?(.+?)(?:=(.+))?$/,
+      valRegex = /^[^\-].*/;
+
+  var charMatch = abbrRegex.exec(str),
+      chars = charMatch && charMatch[1].split("");
+
+  var fullMatch = fullRegex.exec(str),
+      full = fullMatch && fullMatch[2];
+
+  var isValue = str !== undefined && (str === "" || valRegex.test(str));
+  var value;
+  if (isValue) {
+    value = str;
+  }
+  else if (full) {
+    value = fullMatch[1] ? false : fullMatch[3];
+  }
+
+  return {
+    str: str,
+    chars: chars,
+    full: full,
+    value: value,
+    isValue: isValue
+  }
+}
+
+
+/* an opt is what's specified by the user in opts hash */
+var Opt = function(opt) {
+  var strings = (opt.string || "").split(","),
+      abbr, full, metavar;
+  for (var i = 0; i < strings.length; i++) {
+    var string = strings[i].trim(),
+        matches;
+    if (matches = string.match(/^\-([^-])(?:\s+(.*))?$/)) {
+      abbr = matches[1];
+      metavar = matches[2];
+    }
+    else if (matches = string.match(/^\-\-(.+?)(?:[=\s]+(.+))?$/)) {
+      full = matches[1];
+      metavar = metavar || matches[2];
+    }
+  }
+
+  matches = matches || [];
+  var abbr = opt.abbr || abbr,   // e.g. v from -v
+      full = opt.full || full, // e.g. verbose from --verbose
+      metavar = opt.metavar || metavar;  // e.g. PATH from '--config=PATH'
+
+  var string;
+  if (opt.string) {
+    string = opt.string;
+  }
+  else if (opt.position === undefined) {
+    string = "";
+    if (abbr) {
+      string += "-" + abbr;
+      if (metavar)
+        string += " " + metavar
+      string += ", ";
+    }
+    string += "--" + (full || opt.name);
+    if (metavar) {
+      string += " " + metavar;
+    }
+  }
+
+  opt = _(opt).extend({
+    name: opt.name || full || abbr,
+    string: string,
+    abbr: abbr,
+    full: full,
+    metavar: metavar,
+    matches: function(arg) {
+      return opt.full == arg || opt.abbr == arg || opt.position == arg
+        || opt.name == arg || (opt.list && arg >= opt.position);
+    }
+  });
+  return opt;
+}
+
+
+var createParser = function() {
+  return new ArgParser();
+}
+
+var nomnom = createParser();
+
+for (var i in nomnom) {
+  if (typeof nomnom[i] == "function") {
+     createParser[i] = _(nomnom[i]).bind(nomnom);
+  }
+}
+
+module.exports = createParser;
diff --git a/num-vals-fix.diff b/num-vals-fix.diff
new file mode 100644
index 0000000..3c4f167
--- /dev/null
+++ b/num-vals-fix.diff
@@ -0,0 +1,31 @@
+diff --git a/test/values.js b/test/values.js
+index efad789..7fa1078 100644
+--- a/test/values.js
++++ b/test/values.js
+@@ -26,6 +26,12 @@ var opts = {
+    },
+    def2: {
+       default: "val1"
++   },
++   "2d": {
++      flag: true
++   },
++   "3d": {
++      abbr: "3"
+    }
+ }
+ 
+@@ -80,8 +86,12 @@ exports.testDash = function(test) {
+ };
+ 
+ exports.testNumbers = function(test) {
+-  var options = parser.parseArgs(['sum', '-1', '2.5', '-3.5', '4']);
++  var options = parser.parseArgs(['sum', '-1', '2.5', '-3.5', '4', '--2d', '-3', 'test']);
+ 
+   test.deepEqual(options.list3, ['-1', '2.5', '-3.5', '4']);
++  test.strictEqual(options['2d'], true);
++  test.strictEqual(options['3d'], "test")
+   test.done();
+ };
++
++
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..6556f58
--- /dev/null
+++ b/package.json
@@ -0,0 +1,28 @@
+{
+  "name": "nomnom",
+  "description": "Option parser with generated usage and commands",
+  "version": "1.8.1",
+  "author": "Heather Arthur <fayearthur at gmail.com>",
+  "scripts": {
+    "test": "./node_modules/.bin/nodeunit test/*.js"
+  },
+  "repository": {
+    "type": "git",
+    "url": "http://github.com/harthur/nomnom.git"
+  },
+  "main": "./nomnom",
+  "keywords": [
+    "arguments",
+    "option parser",
+    "command line",
+    "options",
+    "parser"
+  ],
+  "dependencies": {
+    "underscore": "~1.6.0",
+    "chalk": "~0.4.0"
+  },
+  "devDependencies": {
+    "nodeunit": "~0.7.4"
+  }
+}
diff --git a/test.js b/test.js
new file mode 100644
index 0000000..db99a1e
--- /dev/null
+++ b/test.js
@@ -0,0 +1,23 @@
+var opts = require("./nomnom")
+   .option('debug', {
+      abbr: 'd',
+      flag: true,
+      help: 'Print debugging info'
+   })
+   .option('config', {
+      abbr: 'c',
+      default: 'config.json',
+      help: 'JSON file with tests to run'
+   })
+   .option('version', {
+      flag: true,
+      help: 'print version and exit',
+      callback: function() {
+         return "version 1.2.4";
+      }
+   })
+   .parse();
+
+if (opts.debug) {
+  console.log("debug")
+}
diff --git a/test/callback.js b/test/callback.js
new file mode 100644
index 0000000..3d512db
--- /dev/null
+++ b/test/callback.js
@@ -0,0 +1,33 @@
+var nomnom = require("../nomnom");
+
+exports.testVersion = function(test) {
+   test.expect(1);
+   
+   nomnom().options({
+      date: {
+         callback: function(date) {
+            test.equal(date, "2010-02-03", "date should match value")
+         }
+      }
+   }).parse(["--date=2010-02-03"]);
+
+   test.done();
+}
+
+exports.testReturnString = function(test) {
+   test.expect(1);
+
+   nomnom().options({
+      version: {
+         flag: true,
+         callback: function() {
+            return "v0.3";
+         }
+      }
+   })
+   .printer(function(string) { 
+      test.equal(0, string.indexOf("v0.3"))
+      test.done();
+   })
+   .parse(["--version"]);
+}
\ No newline at end of file
diff --git a/test/commands.js b/test/commands.js
new file mode 100644
index 0000000..1fbb60f
--- /dev/null
+++ b/test/commands.js
@@ -0,0 +1,120 @@
+var nomnom = require("../nomnom");
+
+function strip(str) {
+  return str.replace(/\s+/g, '');
+}
+
+exports.testCallback = function(test) {
+   test.expect(1);
+
+   var parser = nomnom();
+   parser.command('run').callback(function(options) {
+      test.equal(options.v, 3);
+   });
+   parser.command('other').callback(function() {
+      test.ok(false, "callback for other command shouldn't be called");
+   });
+
+   parser.parse(["run","-v", "3"]);
+   test.done();
+}
+
+exports.testMissingCommand = function(test) {
+   test.expect(1);
+
+   var parser = nomnom().scriptName("test");
+
+   parser.command('run');
+
+   parser.printer(function(string) {
+      test.equal(string, "test: no such command 'other'");
+      test.done();
+   });
+
+   parser.parse(["other"]);
+}
+
+exports.testNoCommand = function(test) {
+   test.expect(2);
+
+   var parser = nomnom();
+
+   parser.nocommand()
+     .options({
+        version: {
+           flag: true
+        }
+     })
+     .callback(function(options) {
+        test.strictEqual(options.version, true);
+     })
+     .usage("fallback usage");
+
+   parser.command('run');
+
+   var options = parser.parse(["--version"]);
+
+   test.strictEqual(options.version, true);
+   test.done();
+}
+
+function createParser() {
+  var parser = nomnom().scriptName("test")
+     .options({
+        debug: {
+           flag: true
+        }
+     });
+
+  parser.command('run')
+    .options({
+       file: {
+          help: 'file to run'
+       }
+    })
+    .help("run all");
+
+  parser.command('test').usage("test usage");
+
+  parser.nocommand()
+    .options({
+       verbose: {
+          flag: true
+       }
+    })
+    .help("nocommand");
+
+  return parser;
+}
+
+exports.testUsage = function(test) {
+   test.expect(4);
+
+   var parser = createParser();
+   parser.printer(function(string) {
+      test.equal(strip(string), "testusage");
+   });
+   parser.parse(["test", "-h"]);
+
+   parser = createParser().nocolors();
+   parser.printer(function(string) {
+      test.equal(strip(string), "Usage:testrun[options]Options:--debug--filefiletorunrunall");
+   });
+   parser.parse(["run", "-h"]);
+
+   parser = createParser().nocolors();
+   parser.printer(function(string) {
+      test.equal(strip(string), "Usage:test[command][options]commandoneof:run,testOptions:--debug--verbosenocommand");
+   });
+   parser.parse(["-h"]);
+
+   parser = createParser().nocolors();
+   parser.nocommand()
+      .usage("fallback");
+   parser.printer(function(string) {
+      test.equal(strip(string), "fallback");
+   });
+   parser.parse(["-h"]);
+
+   test.done();
+}
diff --git a/test/expected.js b/test/expected.js
new file mode 100644
index 0000000..f52bd57
--- /dev/null
+++ b/test/expected.js
@@ -0,0 +1,60 @@
+var nomnom = require("../nomnom");
+
+var opts = {
+   file: {
+      position: 0,
+      required: true
+   }
+}
+
+var parser = nomnom().options(opts);
+
+exports.testFlag = function(test) {
+   test.expect(1);
+
+   nomnom().options({
+      file: {
+         position: 0,
+      }
+   })
+   .printer(function(string) {
+      test.equal(0, string.indexOf("'--key1' expects a value"))
+      test.done();
+   })
+   .parse(["--key1"]);
+}
+
+exports.testRequired = function(test) {
+   test.expect(1);
+
+   nomnom().options({
+      file: {
+         required: true
+      }
+   })
+   .printer(function(string) {
+      test.equal(0, string.trim().indexOf("file argument is required"))
+      test.done();
+   })
+   .nocolors()
+   .parse([]);
+}
+
+exports.testChoices = function(test) {
+   test.expect(2);
+
+   var parser = nomnom().options({
+      color: {
+         choices: ['green', 'blue']
+      }
+   })
+   .printer(function(string) {
+      test.equal(0, string.indexOf("color must be one of: green, blue"))
+   });
+
+   parser.parse(['--color', 'red']);
+
+   var options = parser.parse(['--color', 'green']);
+   test.equal(options.color, 'green');
+   test.done();
+}
diff --git a/test/matching.js b/test/matching.js
new file mode 100644
index 0000000..8d347eb
--- /dev/null
+++ b/test/matching.js
@@ -0,0 +1,70 @@
+var nomnom = require("../nomnom");
+    
+var opts = {
+   pos1: {
+      position: 0
+   },
+   pos2: {
+      position: 1
+   },
+   flag1: {
+      flag: true
+   },
+   debug: {
+      abbr: 'd'
+   },
+   numLines: {
+      abbr: 'n',
+      full: 'num-lines'
+   },
+   version: {
+      string: '-v, --version'
+   },
+   config: {
+      string: '-c FILE, --config=FILE'
+   },
+   skey : {
+      string: '-k val'
+   },
+   skey2: {
+      string: '-k2 val2, --key2 val2'
+   },
+   skey3: {
+      string: '--key3=val'
+   },
+   skey4: {
+      string: '--key4=val, -y val'
+   }
+}
+
+var parser = nomnom().options(opts);
+
+exports.testPositional = function(test) {
+   var options = parser.parse(["--flag1", "val1", "--config", "file", "val2"]);
+   
+   test.equal(options.pos1, "val1");
+   test.equal(options.pos2, "val2");
+   test.deepEqual(options._, ["val1", "val2"])
+   test.done();
+}
+
+exports.testAbbr = function(test) {
+   var options = parser.parse(["-d", "yes", "--num-lines", "3"]);
+   
+   test.equal(options.debug, "yes")
+   test.equal(options.numLines, 3)
+   test.done();
+}
+
+exports.testString = function(test) {
+   var options = parser.parse(["-k", "val", "--config=test.js",
+      "--key2", "val2", "--key3", "val3", "--key4=val4", "-v", "v0.3"]);
+
+   test.equal(options.version, "v0.3")
+   test.equal(options.config, "test.js")
+   test.equal(options.skey, "val")
+   test.equal(options.skey2, "val2")
+   test.equal(options.skey3, "val3")
+   test.equal(options.skey4, "val4")
+   test.done();
+}
diff --git a/test/option.js b/test/option.js
new file mode 100644
index 0000000..e3934d7
--- /dev/null
+++ b/test/option.js
@@ -0,0 +1,44 @@
+var nomnom = require("../nomnom");
+
+var parser = nomnom()
+   .option('debug', {
+      abbr: 'x',
+      flag: true,
+      help: 'Print debugging info'
+   })
+   .option('config', {
+      abbr: 'c',
+      default: 'config.json',
+      help: 'JSON file with tests to run'
+   })
+   .option('version', {
+      flag: true,
+      help: 'print version and exit',
+      callback: function() {
+         return "version 1.2.4";
+      }
+   });
+
+
+exports.testOption = function(test) {
+   var opts = parser.parse(["-x", "--no-verbose"]);
+
+   test.strictEqual(opts.debug, true);
+   test.equal(opts.config, "config.json");
+   test.done();
+}
+
+
+exports.testCommandOption = function(test) {
+   var parser = nomnom()
+   parser.command('test')
+     .option('fruit', {
+        abbr: 'f',
+        flag: true
+     })
+
+   var opts = parser.parse(["test", "-f"]);
+
+   test.strictEqual(opts.fruit, true);
+   test.done();
+}
diff --git a/test/transform.js b/test/transform.js
new file mode 100644
index 0000000..666a6a2
--- /dev/null
+++ b/test/transform.js
@@ -0,0 +1,65 @@
+var nomnom = require("../nomnom");
+
+var parser = nomnom()
+    .option("addr", {
+        abbr: "a",
+        help: "host:port address",
+        transform: function(value) {
+            var parts = value.split(":");
+            return {host: parts[0], port: Number(parts[1])};
+        }
+    })
+    .option("string", {
+        abbr: "s",
+        help: "always a string",
+        transform: function(value) {
+            return value.toString();
+        }
+    });
+
+
+exports.testTransformComplexValue = function(test) {
+    var opts = parser.parse(["-a", "localhost:1234"]);
+
+    test.strictEqual(opts.addr.host, "localhost");
+    test.strictEqual(opts.addr.port, 1234);
+    test.done();
+};
+
+
+exports.testTransformString = function(test) {
+    var opts = parser.parse(["-s", "3"]);
+
+    test.strictEqual(opts.string, "3");
+    test.done();
+};
+
+
+exports.testTransformCommand = function(test) {
+    test.expect(1);
+
+    var parser = nomnom().scriptName("test")
+        .options({
+            addr: {
+                transform: function(value) {
+                    var parts = value.split(":");
+                    return {host: parts[0], port: Number(parts[1])};
+                }
+            }
+        });
+
+    parser.command("run")
+        .options({
+            string: {
+                transform: function(value) {
+                    return value.toString();
+                }
+            }
+        })
+        .callback(function(options) {
+            test.strictEqual(options.string, "true");
+        });
+
+    parser.parse(["run", "--string=true"]);
+    test.done();
+};
diff --git a/test/usage.js b/test/usage.js
new file mode 100644
index 0000000..9a08179
--- /dev/null
+++ b/test/usage.js
@@ -0,0 +1,121 @@
+var nomnom = require("../nomnom");
+
+function strip(str) {
+  return str.replace(/\s+/g, '');
+};
+
+var opts = {
+   apple: {
+      abbr: 'a',
+      help: 'how many apples'
+   },
+
+   banana: {
+      full: "b-nana"
+   },
+
+   carrot: {
+      string: '-c NUM, --carrots=NUM'
+   },
+
+   dill: {
+      metavar: 'PICKLE'
+   },
+
+   egg: {
+      position: 0,
+      help: 'robin'
+   }
+}
+
+var parser = nomnom().options(opts).help("all the best foods").scriptName("test").nocolors();
+
+var expected = "Usage:test[egg][options]eggrobinOptions:-a,--applehowmanyapples--b-nana-cNUM,--carrots=NUM--dillPICKLEallthebestfoods"
+
+exports.testH = function(test) {
+   test.expect(1);
+
+   parser.printer(function(string) {
+      test.equal(strip(string), expected)
+      test.done();
+   })
+   .nocolors()
+   .parse(["-h"]);
+}
+
+exports.testHelp = function(test) {
+   test.expect(1);
+
+   parser.printer(function(string) {
+      test.equal(strip(string), expected)
+      test.done();
+   })
+   .nocolors()
+   .parse(["--help"]);
+}
+
+exports.testScriptName = function(test) {
+   test.expect(1);
+
+   nomnom()
+     .script("test")
+     .printer(function(string) {
+        test.equal(strip(string),"Usage:test")
+        test.done();
+     })
+     .nocolors()
+     .parse(["-h"]);
+}
+
+exports.testUsage = function(test) {
+   test.expect(1);
+
+   parser
+      .usage("test usage")
+      .printer(function(string) {
+         test.equal(string, "test usage")
+         test.done();
+      })
+      .nocolors()
+      .parse(["--help"]);
+}
+
+exports.testHidden = function(test) {
+   test.expect(1);
+
+   nomnom().options({
+      file: {
+         hidden: true
+      }
+   })
+   .scriptName("test")
+   .printer(function(string) {
+      test.equal(strip("Usage:test[options]Options:"), strip(string))
+      test.done();
+   })
+   .nocolors()
+   .parse(["-h"]);
+}
+
+exports.testRequiredOptional = function(test) {
+   test.expect(1);
+
+   nomnom().options({
+      foo: {
+         position: 0,
+         required: true,
+         help: 'The foo'
+      },
+      bar: {
+         position: 1,
+         help: 'The bar'
+      }
+   })
+   .scriptName("test")
+   .printer(function(string) {
+      test.equal(strip("Usage:test<foo>[bar]fooThefoobarThebar"), strip(string))
+      test.done();
+   })
+   .nocolors()
+   .parse(["-h"]);
+}
diff --git a/test/values.js b/test/values.js
new file mode 100644
index 0000000..797807e
--- /dev/null
+++ b/test/values.js
@@ -0,0 +1,75 @@
+var nomnom = require("../nomnom");
+
+var opts = {
+   debug: {
+      flag: true
+   },
+   verbose: {
+      flag: true,
+      default: true
+   },
+   list1: {
+      list: true
+   },
+   list2: {
+      list: true
+   },
+   list3: {
+      position: 1,
+      list: true
+   },
+   num1: {
+      type: "string"
+   },
+   def1: {
+      default: "val1"
+   },
+   def2: {
+      default: "val1"
+   }
+}
+
+var parser = nomnom().options(opts);
+
+exports.testFlag = function(test) {
+   var options = parser.parse(["--debug", "pos0", "--no-verbose"]);
+
+   test.strictEqual(options.debug, true);
+   test.strictEqual(options.verbose, false);
+   test.equal(options[0], "pos0");
+   test.equal(options._[0], "pos0");
+   test.done();
+}
+
+exports.testList = function(test) {
+   var options = parser.parse(["pos0", "pos1", "--list1=val0", "--list2", "val1",
+     "--list2", "val2", "pos2"]);
+  
+   test.deepEqual(options.list1, ["val0"]);
+   test.deepEqual(options.list2, ["val1", "val2"]);
+   test.deepEqual(options.list3, ["pos1", "pos2"]);
+   test.done();
+}
+
+exports.testDefault = function(test) {
+   var options = parser.parse(["--def2", "val2", "--def3", "val3"]);
+
+   test.strictEqual(options.def1, "val1");
+   test.strictEqual(options.def2, "val2");
+   test.strictEqual(options.def3, "val3");
+   test.done();
+}
+
+exports.testTypes = function(test) {
+   var options = parser.parseArgs(["", "-x", "3.14", "-w", "true", "-q", "120",
+     "--num1", "4"]);
+     
+   test.strictEqual(options[0], "");
+   test.strictEqual(options.x, 3.14);
+   test.strictEqual(options.w, true);
+   test.strictEqual(options.q, 120);
+   test.strictEqual(options.num1, "4");
+   test.done();
+}
+
+

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-nomnom.git



More information about the Pkg-javascript-commits mailing list