Permalink
Browse files

Small refactor for parseopts, added tests

  • Loading branch information...
1 parent b345ceb commit 0f91af2e2ed6e3806e9793b44b0c6665166468eb mde committed Dec 21, 2012
Showing with 172 additions and 89 deletions.
  1. +70 −15 bin/cli.js
  2. +44 −38 lib/parseopts.js
  3. +58 −36 test/parseopts.js
View
85 bin/cli.js
@@ -86,21 +86,76 @@ usage = [
// Options available
optsMap = [
- { full: 'origins', abbr: 'o' }
- , { full: 'bind', abbr: 'b' }
- , { full: 'port', abbr: 'p' }
- , { full: 'workers', abbr: ['n', 'w'] }
- , { full: 'version', abbr: ['v', 'V'], args: false }
- , { full: 'help', abbr: 'h', args: false }
- , { full: 'debug', abbr: 'd' }
- , { full: 'loglevel', abbr: 'l' }
- , { full: 'environment', abbr: 'e' }
- , { full: 'spawned', abbr: ['s', 'q', 'Q'] }
- , { full: 'jade', abbr: 'j', args: false }
- , { full: 'handle', abbr: 'H', args: false }
- , { full: 'handlebars', abbr: 'H', args: false }
- , { full: 'mustache', abbr: 'm', args: false }
- , { full: 'realtime', abbr: 'rt', args: false}
+ { full: 'origins'
+ , abbr: 'o'
+ , args: true
+ , canon: 'origins'
+ }
+, { full: ['hostname', 'bind']
+ , abbr: 'b'
+ , args: true
+ , canon: 'hostname'
+ }
+, { full: 'port'
+ , abbr: 'p'
+ , args: true
+ , canon: 'port'
+ }
+, { full: 'workers'
+ , abbr: ['n', 'w']
+ , args: true
+ , canon: 'workers'
+ }
+, { full: 'version'
+ , abbr: ['v', 'V']
+ , args: false
+ , canon: 'version'
+ }
+, { full: 'help'
+ , abbr: 'h'
+ , args: false
+ , canon: 'help'
+ }
+, { full: 'debug'
+ , abbr: 'd'
+ , args: true
+ , canon: 'debug'
+ }
+, { full: 'loglevel'
+ , abbr: 'l'
+ , args: true
+ , canon: 'loglevel'
+ }
+, { full: 'environment'
+ , abbr: 'e'
+ , args: true
+ , canon: 'environment'
+ }
+, { full: 'spawned'
+ , abbr: ['s', 'q', 'Q']
+ , args: true
+ , canon: 'spawned'
+ }
+, { full: 'jade'
+ , abbr: 'j'
+ , args: false
+ , canon: 'jade'
+ }
+, { full: ['handle', 'handlebars']
+ , abbr: 'H'
+ , args: false
+ , canon: 'handlebars'
+ }
+, { full: 'mustache'
+ , abbr: 'm'
+ , args: false
+ , canon: 'mustache'
+ }
+, { full: 'realtime'
+ , abbr: 'rt'
+ , args: false
+ , canon: 'realtime'
+ }
];
// Parse optsMap and generate options and cmd commands
View
82 lib/parseopts.js
@@ -25,53 +25,59 @@ var parseopts = {};
* @param {Array} opts A list of options
*
* Examples:
- * [{full: 'foo', abbr: 'f'}, {full: 'bar', abbr: ['b', 'x']}]
+ * [
+ * { full: 'foo'
+ * , abbr: 'f'
+ * , args: true
+ * , canon: 'foo'
+ * }
+ * , { full: 'bar'
+ * , abbr: ['b', 'x']
+ * , args: false
+ * , canon: 'bar'
+ * }
+ * ]
*/
parseopts.Parser = function (opts) {
var self = this
- , i, key, value;
+ , key
+ , value;
this.cmds = []; // Positional commands parsed from args
this.opts = {}; // A key/value object of matching options parsed from args
// Data structures used for parsing
this.reg = [];
+ this.canonicalOpts = {};
this.shortOpts = {};
this.longOpts = {};
- for (i in opts) {
- key = i;
- value = opts[key];
-
- // Defaults and alias's
- value.abbr = value.abbreviation || value.abbr;
- if (typeof value.args === 'undefined') {
- value.args = true;
- }
-
- // If the abbreviation is a Array then all of those inside are
- // added to shortOpts
- if (value.abbr instanceof Array) {
- value.abbr.forEach(function (item, index) {
- self.shortOpts[item] = {full: value.full};
- self.shortOpts[item]['args'] = value.args;
+ opts.forEach(function (value) {
+ // Create the canonical
+ self.canonicalOpts[value.canon] = {
+ canon: value.canon
+ , args: value.args
+ };
+ // Create short and long aliases that all point to the same canonical
+ ['full', 'abbr'].forEach(function (k) {
+ var v = value[k]
+ , keyType = k == 'full' ?
+ 'longOpts' : 'shortOpts';
+ v = Array.isArray(v) ? v : [v]; // Handle single vals or arrays of them
+ v.forEach(function (o) {
+ self[keyType][o] = self.canonicalOpts[value.canon];
});
- } else {
- this.shortOpts[value.abbr] = {full: value.full};
- this.shortOpts[value.abbr]['args'] = value.args;
- }
+ });
+ });
- this.longOpts[value.full] = {full: value.full};
- this.longOpts[value.full]['args'] = value.args;
- }
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'
+ * Any matcthing opts end up in a key/value object keyed by the 'canon'
* 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
@@ -85,7 +91,7 @@ parseopts.Parser.prototype = new function () {
, opts = {}
, arg
, argObj
- , fullArgName
+ , canonArgName
, argItems;
while (args.length) {
@@ -99,27 +105,27 @@ parseopts.Parser.prototype = new function () {
if (argObj) {
// Args included a space instead of usual = value
if (argItems.length === 1) {
- fullArgName = argObj.full;
+ canonArgName = argObj.canon;
if (!argObj.args) {
- opts[fullArgName] = true;
+ opts[canonArgName] = true;
} else {
// If no argument is given for this option then set it's value to true
if(!args[0] || (args[0].indexOf('-') == 0) || (args[0].indexOf('--') == 0)) {
- opts[fullArgName] = true;
+ opts[canonArgName] = true;
} else {
- opts[fullArgName] = args.shift();
+ opts[canonArgName] = args.shift();
}
}
}
else {
- fullArgName = argObj.full;
+ canonArgName = argObj.canon;
// If the opt doesn't take args then set value to true
if (!argObj.args) {
- opts[fullArgName] = true;
+ opts[canonArgName] = true;
} else {
- opts[fullArgName] = argItems[1] || true;
+ opts[canonArgName] = argItems[1] || true;
}
}
}
@@ -134,17 +140,17 @@ parseopts.Parser.prototype = new function () {
// If argument exists
if (argObj) {
- fullArgName = argObj.full; // Get full name
+ canonArgName = argObj.canon; // Get canon name
// If the option doesn't rake arguments then set value to true
if(!argObj.args) {
- opts[fullArgName] = true;
+ opts[canonArgName] = true;
} else {
// If no argument is given for this option then set it's value to true
if(!args[0] || (args[0].indexOf('-') == 0) || (args[0].indexOf('--') == 0)) {
- opts[fullArgName] = true;
+ opts[canonArgName] = true;
} else {
- opts[fullArgName] = args.shift();
+ opts[canonArgName] = args.shift();
}
}
} else throw new Error('Unknown option "' + arg + '"');
View
94 test/parseopts.js
@@ -1,96 +1,118 @@
var assert = require('assert')
, parseopts = require('../lib/parseopts')
, Parser = parseopts.Parser
- , tests;
+ , tests
+ , _opts;
+
+ _opts = [
+ { full: 'howdy'
+ , abbr: 'h'
+ , args: true
+ , canon: 'howdy'
+ }
+, { full: ['derp', 'zoom']
+ , abbr: 'd'
+ , args: false
+ , canon: 'derp'
+ }
+, { full: ['zong', 'asdf']
+ , abbr: ['n', 'b']
+ , args: false
+ , canon: 'zong'
+ }
+];
-tests = new function () {
- var _opts = [
- {
- full: 'howdy'
- , abbr: 'h'
- }
- ];
- this.testConstrutor = function () {
+tests = {
+ 'constructor': function () {
var p = new Parser(_opts);
- assert.equal(p.longOpts.howdy.full, 'howdy');
- assert.equal(p.shortOpts.h.full, 'howdy');
- };
+ assert.equal(p.longOpts.howdy.canon, 'howdy');
+ assert.equal(p.shortOpts.h.canon, 'howdy');
+ }
- this.testParseShort = function () {
+, 'parse short': function () {
var p = new Parser(_opts);
p.parse(['-h', 'foo']);
assert.equal(p.opts.howdy, 'foo');
- };
+ }
- this.testParseLong = function () {
+, 'parse long': function () {
var p = new Parser(_opts);
p.parse(['--howdy=bar']);
assert.equal(p.opts.howdy, 'bar');
- };
+ }
- this.testParseShortWithCmds = function () {
+, 'parse short with cmds': 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 () {
+, 'parse short with cmds': 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 () {
+, 'parse short null value': function () {
var p = new Parser(_opts);
p.parse(['-h']);
- assert.equal(p.opts.howdy.full, null);
- };
+ assert.equal(p.opts.howdy.canon, null);
+ }
- this.testParseLongNullValue = function () {
+, 'parse long null value': function () {
var p = new Parser(_opts);
p.parse(['--howdy']);
- assert.equal(p.opts.howdy.full, null);
- };
+ assert.equal(p.opts.howdy.canon, null);
+ }
- this.testParseShortNotPassed = function () {
+, 'parse short not passed': function () {
var p = new Parser(_opts);
p.parse(['foo']);
assert.equal(p.opts.howdy, undefined);
- };
+ }
- this.testParseLongNotPassed = function () {
+, 'parse long not passed': function () {
var p = new Parser(_opts);
p.parse(['foo']);
assert.equal(p.opts.howdy, undefined);
- };
+ }
- this.testParseShortDoesntExist = function () {
+, 'parse short doesn\'t exist': 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);
+, 'parse long doesn\'t exist': function () {
var p = new Parser(_opts);
try {
p.parse(['--hello=bar']);
}
catch (e) {
assert.ok(e.message.indexOf('Unknown option') > -1);
}
- };
+ }
+
+, 'long alias': function () {
+ var p = new Parser(_opts);
+ assert.equal(p.longOpts.derp, p.longOpts.zoom);
+ }
+
+, 'short alias': function () {
+ var p = new Parser(_opts);
+ assert.equal(p.shortOpts.n, p.shortOpts.b);
+ }
-}();
+};
module.exports = tests;

0 comments on commit 0f91af2

Please sign in to comment.