diff --git a/lib/commander.js b/lib/commander.js index 16a973e7b..5f6d97c3a 100644 --- a/lib/commander.js +++ b/lib/commander.js @@ -86,7 +86,8 @@ Option.prototype.is = function(arg){ function Command(name) { this.commands = []; - this.options = []; + this.options = {}; + this._options = []; this.args = []; this.name = name; } @@ -291,17 +292,22 @@ Command.prototype.option = function(flags, description, fn, defaultValue){ // default as 3rd arg if ('function' != typeof fn) defaultValue = fn, fn = null; - + // preassign default value only for --no-*, [optional], or if (false == option.bool || option.optional || option.required) { // when --no-* we make sure default is true if (false == option.bool) defaultValue = true; + // preassign only if we have a default - if (undefined !== defaultValue) self[name] = defaultValue; + if (undefined !== defaultValue) self.assign(name, defaultValue); + + } else { + // set opt to false otherwise + self.options[name] = false; } // register the option - this.options.push(option); + this._options.push(option); // when it's passed assign the value // and conditionally invoke the callback @@ -313,21 +319,34 @@ Command.prototype.option = function(flags, description, fn, defaultValue){ if ('boolean' == typeof self[name] || 'undefined' == typeof self[name]) { // if no value, bool true, and we have a default, then use it! if (null == val) { - self[name] = option.bool + self.assign(name, option.bool ? defaultValue || true - : false; + : false); } else { - self[name] = val; + self.assign(name, val); } } else if (null !== val) { // reassign - self[name] = val; + self.assign(name, val); } }); return this; }; +/** + * Assign the option name `key` with the given `value`. + * + * @param {String} key + * @param {mixed} value + * @return {Command} for chaining + * @api private + */ +Command.prototype.assign = function(key, value) { + this.options[key] = this[key] = value; + return this; +}; + /** * Parse `argv`, settings options and invoking commands when defined. * @@ -422,9 +441,9 @@ Command.prototype.parseArgs = function(args, unknown){ */ Command.prototype.optionFor = function(arg){ - for (var i = 0, len = this.options.length; i < len; ++i) { - if (this.options[i].is(arg)) { - return this.options[i]; + for (var i = 0, len = this._options.length; i < len; ++i) { + if (this._options[i].is(arg)) { + return this._options[i]; } } }; @@ -627,7 +646,7 @@ Command.prototype.usage = function(str){ */ Command.prototype.largestOptionLength = function(){ - return this.options.reduce(function(max, option){ + return this._options.reduce(function(max, option){ return Math.max(max, option.flags.length); }, 0); }; @@ -644,7 +663,7 @@ Command.prototype.optionHelp = function(){ // Prepend the help information return [pad('-h, --help', width) + ' ' + 'output usage information'] - .concat(this.options.map(function(option){ + .concat(this._options.map(function(option){ return pad(option.flags, width) + ' ' + option.description; })) @@ -672,7 +691,7 @@ Command.prototype.commandHelp = function(){ }).join(' '); return cmd.name - + (cmd.options.length + + (cmd._options.length ? ' [options]' : '') + ' ' + args + (cmd.description() diff --git a/test/test.options.args.optional.given.js b/test/test.options.args.optional.given.js index 86e9d1401..7914890b5 100644 --- a/test/test.options.args.optional.given.js +++ b/test/test.options.args.optional.given.js @@ -11,3 +11,4 @@ program program.parse(['node', 'test', '--cheese', 'feta']); program.cheese.should.equal('feta'); +program.options.cheese.should.equal('feta'); diff --git a/test/test.options.args.optional.js b/test/test.options.args.optional.js index aacaccc9f..a8136a08c 100644 --- a/test/test.options.args.optional.js +++ b/test/test.options.args.optional.js @@ -11,3 +11,4 @@ program program.parse(['node', 'test', '--cheese']); program.cheese.should.be.true; +program.options.cheese.should.be.true; diff --git a/test/test.options.bool.js b/test/test.options.bool.js index 4fc32068b..7ccf03f94 100644 --- a/test/test.options.bool.js +++ b/test/test.options.bool.js @@ -14,3 +14,6 @@ program program.parse(['node', 'test', '--pepper']); program.pepper.should.be.true; program.cheese.should.be.true; + +program.options.pepper.should.be.true; +program.options.cheese.should.be.true; diff --git a/test/test.options.bool.no.js b/test/test.options.bool.no.js index bb7b8993f..15b82d1b0 100644 --- a/test/test.options.bool.no.js +++ b/test/test.options.bool.no.js @@ -13,3 +13,4 @@ program program.parse(['node', 'test', '--no-cheese']); should.equal(undefined, program.pepper); program.cheese.should.be.false; +program.options.cheese.should.be.false; diff --git a/test/test.options.bool.small.combined.js b/test/test.options.bool.small.combined.js index 0b1a3bfc1..f5b411a3a 100644 --- a/test/test.options.bool.small.combined.js +++ b/test/test.options.bool.small.combined.js @@ -13,3 +13,6 @@ program program.parse(['node', 'test', '-pc']); program.pepper.should.be.true; program.cheese.should.be.false; + +program.options.pepper.should.be.true; +program.options.cheese.should.be.false; diff --git a/test/test.options.bool.small.js b/test/test.options.bool.small.js index 2818bfd4c..62f288d0d 100644 --- a/test/test.options.bool.small.js +++ b/test/test.options.bool.small.js @@ -13,3 +13,6 @@ program program.parse(['node', 'test', '-p', '-c']); program.pepper.should.be.true; program.cheese.should.be.false; + +program.options.pepper.should.be.true; +program.options.cheese.should.be.false; diff --git a/test/test.options.camelcase.js b/test/test.options.camelcase.js index b36e7623e..21354c55e 100644 --- a/test/test.options.camelcase.js +++ b/test/test.options.camelcase.js @@ -25,3 +25,10 @@ program.myFLOAT.should.equal(5.5); program.myVeryLongFloat.should.equal(6.5); program.myURLCount.should.equal(7.5); program.myLongRange.should.eql([1,5]); + +program.options.myInt.should.equal(5); +program.options.myNum.should.equal(15.99); +program.options.myFLOAT.should.equal(5.5); +program.options.myVeryLongFloat.should.equal(6.5); +program.options.myURLCount.should.equal(7.5); +program.options.myLongRange.should.eql([1,5]); diff --git a/test/test.options.coercion.js b/test/test.options.coercion.js index 296d9671a..d2e94d19c 100644 --- a/test/test.options.coercion.js +++ b/test/test.options.coercion.js @@ -21,3 +21,8 @@ program.int.should.equal(5); program.num.should.equal(15.99); program.float.should.equal(5.5); program.range.should.eql([1,5]); + +program.options.int.should.equal(5); +program.options.num.should.equal(15.99); +program.options.float.should.equal(5.5); +program.options.range.should.eql([1,5]); diff --git a/test/test.options.defaults.given.js b/test/test.options.defaults.given.js index d0846d7e0..0ae4c14ef 100644 --- a/test/test.options.defaults.given.js +++ b/test/test.options.defaults.given.js @@ -21,3 +21,10 @@ program.should.have.property('olives', 'black'); program.should.have.property('sauce', false); program.should.have.property('crust', 'thin'); program.should.have.property('cheese', 'wensleydale'); + +program.options.should.have.property('anchovies', true); +program.options.should.have.property('onions', true); +program.options.should.have.property('olives', 'black'); +program.options.should.have.property('sauce', false); +program.options.should.have.property('crust', 'thin'); +program.options.should.have.property('cheese', 'wensleydale'); diff --git a/test/test.options.defaults.js b/test/test.options.defaults.js index 67800a472..263236053 100644 --- a/test/test.options.defaults.js +++ b/test/test.options.defaults.js @@ -21,3 +21,10 @@ program.should.not.have.property('olives'); program.should.have.property('sauce', true); program.should.have.property('crust', 'hand-tossed'); program.should.have.property('cheese', 'mozzarella'); + +program.options.should.have.property('anchovies', false); +program.options.should.have.property('onions', false); +program.options.should.have.property('olives', false); +program.options.should.have.property('sauce', true); +program.options.should.have.property('crust', 'hand-tossed'); +program.options.should.have.property('cheese', 'mozzarella'); diff --git a/test/test.options.defaults.not.given.js b/test/test.options.defaults.not.given.js new file mode 100644 index 000000000..013d956d0 --- /dev/null +++ b/test/test.options.defaults.not.given.js @@ -0,0 +1,31 @@ +/** + * Module dependencies. + */ + +var program = require('../') + , should = require('should'); + +program + .version('0.0.1') + .option('-a, --anchovies', 'Add anchovies?') + .option('-o, --onions', 'Add onions?') + .option('-v, --olives', 'Add olives? Sorry we only have black.', 'black') + .option('-s, --no-sauce', 'Uh… okay') + .option('-r, --crust ', 'What kind of crust would you like?', 'hand-tossed') + .option('-c, --cheese [type]', 'optionally specify the type of cheese', 'mozzarella'); + +program.parse(['node', 'test', '--olives']) + +program.should.not.have.property('anchovies'); +program.should.not.have.property('onions'); +program.should.have.property('olives', 'black'); +program.should.have.property('sauce', true); +program.should.have.property('crust', 'hand-tossed'); +program.should.have.property('cheese', 'mozzarella'); + +program.options.should.have.property('anchovies', false); +program.options.should.have.property('onions', false); +program.options.should.have.property('olives', 'black'); +program.options.should.have.property('sauce', true); +program.options.should.have.property('crust', 'hand-tossed'); +program.options.should.have.property('cheese', 'mozzarella'); diff --git a/test/test.options.large-only-with-value.js b/test/test.options.large-only-with-value.js index dfd524712..5241ab96d 100644 --- a/test/test.options.large-only-with-value.js +++ b/test/test.options.large-only-with-value.js @@ -11,3 +11,5 @@ program program.parse(['node', 'test', '--longflag', 'something']); program.longflag.should.equal('something'); + +program.options.longflag.should.equal('something'); diff --git a/test/test.options.large-only.js b/test/test.options.large-only.js index 6f7e328f9..e10a9b7ac 100644 --- a/test/test.options.large-only.js +++ b/test/test.options.large-only.js @@ -11,3 +11,5 @@ program program.parse(['node', 'test', '--verbose']); program.verbose.should.be.true; + +program.options.verbose.should.be.true;