Permalink
Browse files

Adding library and tests.

  • Loading branch information...
1 parent 1f90d6c commit b783a94addc70bd3e3e2c07df9f7e7931f815ed4 @mde committed Aug 29, 2010
Showing with 201 additions and 0 deletions.
  1. +104 −0 lib/parseopts.js
  2. +97 −0 tests/test-parse.js
View
104 lib/parseopts.js
@@ -0,0 +1,104 @@
+/*
+ * Parseopts command-line options parser in JavaScript
+ * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+
+var parseopts = {};
+
+/**
+ * @constructor
+ * Parses a list of command-line args into a key/value object of
+ * options and an array of positional commands.
+ * @ param {Array} opts A list of options in the following format:
+ * [{full: 'foo', abbr: 'f'}, {full: 'bar', abbr: 'b'}]]
+ */
+parseopts.Parser = function (opts) {
+ // Positional commands parse out of the args
+ this.cmds = [];
+ // A key/value object of matching options parsed out of the args
+ this.opts = {};
+
+ // Data structures used for parsing
+ this.reg = [];
+ this.shortOpts = {};
+ this.longOpts = {};
+
+ var item;
+ for (var i = 0, ii = opts.length; i < ii; i++) {
+ item = opts[i];
+ this.shortOpts[item.abbr] = item.full;
+ this.longOpts[item.full] = item.full;
+ }
+ this.reg = opts;
+};
+
+parseopts.Parser.prototype = new function () {
+
+ /**
+ * Parses an array of arguments into options and positional commands
+ * Any matcthing opts end up in a key/value object keyed by the 'full'
+ * name of the option. Any args that aren't passed as options end up in
+ * an array of positional commands.
+ * Any options passed without a value end up with a value of null
+ * in the key/value object of options
+ * If the user passes options that are not defined in the list passed
+ * to the constructor, the parser throws an error 'Unknown option.'
+ * @param {Array} args The command-line args to parse
+ */
+ this.parse = function (args) {
+ var cmds = []
+ , opts = {}
+ , arg
+ , argName
+ , argItems;
+
+ while (args.length) {
+ arg = args.shift();
+ if (arg.indexOf('--') == 0) {
+ argItems = arg.split('=');
+ argName = this.longOpts[argItems[0].substr(2)];
+ if (argName) {
+ // If there's no attached value, value is null
+ opts[argName] = argItems[1] || null;
+ }
+ else {
+ throw new Error('Unknown option "' + argItems[0] + '"');
+ }
+ }
+ else if (arg.indexOf('-') == 0) {
+ argName = this.shortOpts[arg.substr(1)];
+ if (argName) {
+ // If there is no following item, or the next item is
+ // another opt, value is null
+ opts[argName] = (!args[0] || (args[0].indexOf('-') == 0)) ?
+ null : args.shift();
+ }
+ else {
+ throw new Error('Unknown option "' + arg + '"');
+ }
+ }
+ else {
+ cmds.push(arg);
+ }
+ }
+
+ this.cmds = cmds;
+ this.opts = opts;
+ };
+
+};
+
+module.exports = parseopts;
View
97 tests/test-parse.js
@@ -0,0 +1,97 @@
+var parseopts = require('../lib/parseopts');
+
+var Parser = parseopts.Parser;
+
+var taskTests = new function () {
+ var _opts = [
+ {
+ full: 'howdy'
+ , abbr: 'h'
+ }
+ ];
+
+ this.testConstrutor = function () {
+ var p = new Parser(_opts);
+ assert.equal(p.longOpts.howdy, 'howdy');
+ assert.equal(p.shortOpts.h, 'howdy');
+ };
+
+ this.testParseShort = function () {
+ var p = new Parser(_opts);
+ p.parse(['-h', 'foo']);
+ assert.equal(p.opts.howdy, 'foo');
+ };
+
+ this.testParseLong = function () {
+ var p = new Parser(_opts);
+ p.parse(['--howdy=bar']);
+ assert.equal(p.opts.howdy, 'bar');
+ };
+
+ this.testParseShortWithCmds = function () {
+ var p = new Parser(_opts);
+ p.parse(['asdf', '-h', 'foo', 'qwer']);
+ assert.equal(p.opts.howdy, 'foo');
+ assert.equal(p.cmds[0], 'asdf');
+ assert.equal(p.cmds[1], 'qwer');
+ };
+
+ this.testParseShortWithCmds = function () {
+ var p = new Parser(_opts);
+ p.parse(['asdf', '--howdy=bar', 'qwer']);
+ assert.equal(p.opts.howdy, 'bar');
+ assert.equal(p.cmds[0], 'asdf');
+ assert.equal(p.cmds[1], 'qwer');
+ };
+
+ this.testParseShortNullValue = function () {
+ var p = new Parser(_opts);
+ p.parse(['-h']);
+ assert.equal(p.opts.howdy, null);
+ };
+
+ this.testParseLongNullValue = function () {
+ var p = new Parser(_opts);
+ p.parse(['--howdy']);
+ assert.equal(p.opts.howdy, null);
+ };
+
+ this.testParseShortNotPassed = function () {
+ var p = new Parser(_opts);
+ p.parse(['foo']);
+ assert.equal(p.opts.howdy, undefined);
+ };
+
+ this.testParseLongNotPassed = function () {
+ var p = new Parser(_opts);
+ p.parse(['foo']);
+ assert.equal(p.opts.howdy, undefined);
+ };
+
+ this.testParseShortDoesntExist = function () {
+ var p = new Parser(_opts);
+ try {
+ p.parse(['-i', 'foo']);
+ }
+ catch (e) {
+ assert.ok(e.message.indexOf('Unknown option') > -1);
+ }
+ };
+
+ this.testParseLongDoesntExist = function () {
+ var p = new Parser(_opts);
+ var p = new Parser(_opts);
+ try {
+ p.parse(['--hello=bar']);
+ }
+ catch (e) {
+ assert.ok(e.message.indexOf('Unknown option') > -1);
+ }
+ };
+
+
+
+}();
+
+logan.run(taskTests);
+

0 comments on commit b783a94

Please sign in to comment.