arnaucube
arnaucube/raspberryGPIOhtmlserverPublic Self-hosted repository
raspberryGPIOhtmlserver/node_modules/commander/lib/commander.js
node_modules/commander/lib/commander.jsRaw
   1
   2/*!
   3 * commander
   4 * Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca>
   5 * MIT Licensed
   6 */
   7
   8/**
   9 * Module dependencies.
  10 */
  11
  12var EventEmitter = require('events').EventEmitter
  13  , path = require('path')
  14  , tty = require('tty')
  15  , basename = path.basename;
  16
  17/**
  18 * Expose the root command.
  19 */
  20
  21exports = module.exports = new Command;
  22
  23/**
  24 * Expose `Command`.
  25 */
  26
  27exports.Command = Command;
  28
  29/**
  30 * Expose `Option`.
  31 */
  32
  33exports.Option = Option;
  34
  35/**
  36 * Initialize a new `Option` with the given `flags` and `description`.
  37 *
  38 * @param {String} flags
  39 * @param {String} description
  40 * @api public
  41 */
  42
  43function Option(flags, description) {
  44  this.flags = flags;
  45  this.required = ~flags.indexOf('<');
  46  this.optional = ~flags.indexOf('[');
  47  this.bool = !~flags.indexOf('-no-');
  48  flags = flags.split(/[ ,|]+/);
  49  if (flags.length > 1 && !/^[[<]/.test(flags[1])) this.short = flags.shift();
  50  this.long = flags.shift();
  51  this.description = description;
  52}
  53
  54/**
  55 * Return option name.
  56 *
  57 * @return {String}
  58 * @api private
  59 */
  60
  61Option.prototype.name = function(){
  62  return this.long
  63    .replace('--', '')
  64    .replace('no-', '');
  65};
  66
  67/**
  68 * Check if `arg` matches the short or long flag.
  69 *
  70 * @param {String} arg
  71 * @return {Boolean}
  72 * @api private
  73 */
  74
  75Option.prototype.is = function(arg){
  76  return arg == this.short
  77    || arg == this.long;
  78};
  79
  80/**
  81 * Initialize a new `Command`.
  82 *
  83 * @param {String} name
  84 * @api public
  85 */
  86
  87function Command(name) {
  88  this.commands = [];
  89  this.options = [];
  90  this.args = [];
  91  this.name = name;
  92}
  93
  94/**
  95 * Inherit from `EventEmitter.prototype`.
  96 */
  97
  98Command.prototype.__proto__ = EventEmitter.prototype;
  99
 100/**
 101 * Add command `name`.
 102 *
 103 * The `.action()` callback is invoked when the
 104 * command `name` is specified via __ARGV__,
 105 * and the remaining arguments are applied to the
 106 * function for access.
 107 *
 108 * When the `name` is "*" an un-matched command
 109 * will be passed as the first arg, followed by
 110 * the rest of __ARGV__ remaining.
 111 *
 112 * Examples:
 113 *
 114 *      program
 115 *        .version('0.0.1')
 116 *        .option('-C, --chdir <path>', 'change the working directory')
 117 *        .option('-c, --config <path>', 'set config path. defaults to ./deploy.conf')
 118 *        .option('-T, --no-tests', 'ignore test hook')
 119 *     
 120 *      program
 121 *        .command('setup')
 122 *        .description('run remote setup commands')
 123 *        .action(function(){
 124 *          console.log('setup');
 125 *        });
 126 *     
 127 *      program
 128 *        .command('exec <cmd>')
 129 *        .description('run the given remote command')
 130 *        .action(function(cmd){
 131 *          console.log('exec "%s"', cmd);
 132 *        });
 133 *     
 134 *      program
 135 *        .command('*')
 136 *        .description('deploy the given env')
 137 *        .action(function(env){
 138 *          console.log('deploying "%s"', env);
 139 *        });
 140 *     
 141 *      program.parse(process.argv);
 142  *
 143 * @param {String} name
 144 * @return {Command} the new command
 145 * @api public
 146 */
 147
 148Command.prototype.command = function(name){
 149  var args = name.split(/ +/);
 150  var cmd = new Command(args.shift());
 151  this.commands.push(cmd);
 152  cmd.parseExpectedArgs(args);
 153  cmd.parent = this;
 154  return cmd;
 155};
 156
 157/**
 158 * Parse expected `args`.
 159 *
 160 * For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`.
 161 *
 162 * @param {Array} args
 163 * @return {Command} for chaining
 164 * @api public
 165 */
 166
 167Command.prototype.parseExpectedArgs = function(args){
 168  if (!args.length) return;
 169  var self = this;
 170  args.forEach(function(arg){
 171    switch (arg[0]) {
 172      case '<':
 173        self.args.push({ required: true, name: arg.slice(1, -1) });
 174        break;
 175      case '[':
 176        self.args.push({ required: false, name: arg.slice(1, -1) });
 177        break;
 178    }
 179  });
 180  return this;
 181};
 182
 183/**
 184 * Register callback `fn` for the command.
 185 *
 186 * Examples:
 187 *
 188 *      program
 189 *        .command('help')
 190 *        .description('display verbose help')
 191 *        .action(function(){
 192 *           // output help here
 193 *        });
 194 *
 195 * @param {Function} fn
 196 * @return {Command} for chaining
 197 * @api public
 198 */
 199
 200Command.prototype.action = function(fn){
 201  var self = this;
 202  this.parent.on(this.name, function(args, unknown){    
 203    // Parse any so-far unknown options
 204    unknown = unknown || [];
 205    var parsed = self.parseOptions(unknown);
 206    
 207    // Output help if necessary
 208    outputHelpIfNecessary(self, parsed.unknown);
 209    
 210    // If there are still any unknown options, then we simply 
 211    // die, unless someone asked for help, in which case we give it
 212    // to them, and then we die.
 213    if (parsed.unknown.length > 0) {      
 214      self.unknownOption(parsed.unknown[0]);
 215    }
 216    
 217    self.args.forEach(function(arg, i){
 218      if (arg.required && null == args[i]) {
 219        self.missingArgument(arg.name);
 220      }
 221    });
 222    
 223    // Always append ourselves to the end of the arguments,
 224    // to make sure we match the number of arguments the user
 225    // expects
 226    if (self.args.length) {
 227      args[self.args.length] = self;
 228    } else {
 229      args.push(self);
 230    }
 231    
 232    fn.apply(this, args);
 233  });
 234  return this;
 235};
 236
 237/**
 238 * Define option with `flags`, `description` and optional
 239 * coercion `fn`. 
 240 *
 241 * The `flags` string should contain both the short and long flags,
 242 * separated by comma, a pipe or space. The following are all valid
 243 * all will output this way when `--help` is used.
 244 *
 245 *    "-p, --pepper"
 246 *    "-p|--pepper"
 247 *    "-p --pepper"
 248 *
 249 * Examples:
 250 *
 251 *     // simple boolean defaulting to false
 252 *     program.option('-p, --pepper', 'add pepper');
 253 *
 254 *     --pepper
 255 *     program.pepper
 256 *     // => Boolean
 257 *
 258 *     // simple boolean defaulting to false
 259 *     program.option('-C, --no-cheese', 'remove cheese');
 260 *
 261 *     program.cheese
 262 *     // => true
 263 *
 264 *     --no-cheese
 265 *     program.cheese
 266 *     // => true
 267 *
 268 *     // required argument
 269 *     program.option('-C, --chdir <path>', 'change the working directory');
 270 *
 271 *     --chdir /tmp
 272 *     program.chdir
 273 *     // => "/tmp"
 274 *
 275 *     // optional argument
 276 *     program.option('-c, --cheese [type]', 'add cheese [marble]');
 277 *
 278 * @param {String} flags
 279 * @param {String} description
 280 * @param {Function|Mixed} fn or default
 281 * @param {Mixed} defaultValue
 282 * @return {Command} for chaining
 283 * @api public
 284 */
 285
 286Command.prototype.option = function(flags, description, fn, defaultValue){
 287  var self = this
 288    , option = new Option(flags, description)
 289    , oname = option.name()
 290    , name = camelcase(oname);
 291
 292  // default as 3rd arg
 293  if ('function' != typeof fn) defaultValue = fn, fn = null;
 294
 295  // preassign default value only for --no-*, [optional], or <required>
 296  if (false == option.bool || option.optional || option.required) {
 297    // when --no-* we make sure default is true
 298    if (false == option.bool) defaultValue = true;
 299    // preassign only if we have a default
 300    if (undefined !== defaultValue) self[name] = defaultValue;
 301  }
 302
 303  // register the option
 304  this.options.push(option);
 305
 306  // when it's passed assign the value
 307  // and conditionally invoke the callback
 308  this.on(oname, function(val){
 309    // coercion
 310    if (null != val && fn) val = fn(val);
 311
 312    // unassigned or bool
 313    if ('boolean' == typeof self[name] || 'undefined' == typeof self[name]) {
 314      // if no value, bool true, and we have a default, then use it!
 315      if (null == val) {
 316        self[name] = option.bool
 317          ? defaultValue || true
 318          : false;
 319      } else {
 320        self[name] = val;
 321      }
 322    } else if (null !== val) {
 323      // reassign
 324      self[name] = val;
 325    }
 326  });
 327
 328  return this;
 329};
 330
 331/**
 332 * Parse `argv`, settings options and invoking commands when defined.
 333 *
 334 * @param {Array} argv
 335 * @return {Command} for chaining
 336 * @api public
 337 */
 338
 339Command.prototype.parse = function(argv){
 340  // store raw args
 341  this.rawArgs = argv;
 342
 343  // guess name
 344  if (!this.name) this.name = basename(argv[1]);
 345
 346  // process argv
 347  var parsed = this.parseOptions(this.normalize(argv.slice(2)));
 348  this.args = parsed.args;
 349  return this.parseArgs(this.args, parsed.unknown);
 350};
 351
 352/**
 353 * Normalize `args`, splitting joined short flags. For example
 354 * the arg "-abc" is equivalent to "-a -b -c".
 355 *
 356 * @param {Array} args
 357 * @return {Array}
 358 * @api private
 359 */
 360
 361Command.prototype.normalize = function(args){
 362  var ret = []
 363    , arg;
 364
 365  for (var i = 0, len = args.length; i < len; ++i) {
 366    arg = args[i];
 367    if (arg.length > 1 && '-' == arg[0] && '-' != arg[1]) {
 368      arg.slice(1).split('').forEach(function(c){
 369        ret.push('-' + c);
 370      });
 371    } else {
 372      ret.push(arg);
 373    }
 374  }
 375
 376  return ret;
 377};
 378
 379/**
 380 * Parse command `args`.
 381 *
 382 * When listener(s) are available those
 383 * callbacks are invoked, otherwise the "*"
 384 * event is emitted and those actions are invoked.
 385 *
 386 * @param {Array} args
 387 * @return {Command} for chaining
 388 * @api private
 389 */
 390
 391Command.prototype.parseArgs = function(args, unknown){
 392  var cmds = this.commands
 393    , len = cmds.length
 394    , name;
 395
 396  if (args.length) {
 397    name = args[0];
 398    if (this.listeners(name).length) {
 399      this.emit(args.shift(), args, unknown);
 400    } else {
 401      this.emit('*', args);
 402    }
 403  } else {
 404    outputHelpIfNecessary(this, unknown);
 405    
 406    // If there were no args and we have unknown options,
 407    // then they are extraneous and we need to error.
 408    if (unknown.length > 0) {      
 409      this.unknownOption(unknown[0]);
 410    }
 411  }
 412
 413  return this;
 414};
 415
 416/**
 417 * Return an option matching `arg` if any.
 418 *
 419 * @param {String} arg
 420 * @return {Option}
 421 * @api private
 422 */
 423
 424Command.prototype.optionFor = function(arg){
 425  for (var i = 0, len = this.options.length; i < len; ++i) {
 426    if (this.options[i].is(arg)) {
 427      return this.options[i];
 428    }
 429  }
 430};
 431
 432/**
 433 * Parse options from `argv` returning `argv`
 434 * void of these options.
 435 *
 436 * @param {Array} argv
 437 * @return {Array}
 438 * @api public
 439 */
 440
 441Command.prototype.parseOptions = function(argv){
 442  var args = []
 443    , len = argv.length
 444    , literal
 445    , option
 446    , arg;
 447
 448  var unknownOptions = [];
 449
 450  // parse options
 451  for (var i = 0; i < len; ++i) {
 452    arg = argv[i];
 453
 454    // literal args after --
 455    if ('--' == arg) {
 456      literal = true;
 457      continue;
 458    }
 459
 460    if (literal) {
 461      args.push(arg);
 462      continue;
 463    }
 464
 465    // find matching Option
 466    option = this.optionFor(arg);
 467
 468    // option is defined
 469    if (option) {
 470      // requires arg
 471      if (option.required) {
 472        arg = argv[++i];
 473        if (null == arg) return this.optionMissingArgument(option);
 474        if ('-' == arg[0]) return this.optionMissingArgument(option, arg);
 475        this.emit(option.name(), arg);
 476      // optional arg
 477      } else if (option.optional) {
 478        arg = argv[i+1];
 479        if (null == arg || '-' == arg[0]) {
 480          arg = null;
 481        } else {
 482          ++i;
 483        }
 484        this.emit(option.name(), arg);
 485      // bool
 486      } else {
 487        this.emit(option.name());
 488      }
 489      continue;
 490    }
 491    
 492    // looks like an option
 493    if (arg.length > 1 && '-' == arg[0]) {
 494      unknownOptions.push(arg);
 495      
 496      // If the next argument looks like it might be
 497      // an argument for this option, we pass it on.
 498      // If it isn't, then it'll simply be ignored
 499      if (argv[i+1] && '-' != argv[i+1][0]) {
 500        unknownOptions.push(argv[++i]);
 501      }
 502      continue;
 503    }
 504    
 505    // arg
 506    args.push(arg);
 507  }
 508  
 509  return { args: args, unknown: unknownOptions };
 510};
 511
 512/**
 513 * Argument `name` is missing.
 514 *
 515 * @param {String} name
 516 * @api private
 517 */
 518
 519Command.prototype.missingArgument = function(name){
 520  console.error();
 521  console.error("  error: missing required argument `%s'", name);
 522  console.error();
 523  process.exit(1);
 524};
 525
 526/**
 527 * `Option` is missing an argument, but received `flag` or nothing.
 528 *
 529 * @param {String} option
 530 * @param {String} flag
 531 * @api private
 532 */
 533
 534Command.prototype.optionMissingArgument = function(option, flag){
 535  console.error();
 536  if (flag) {
 537    console.error("  error: option `%s' argument missing, got `%s'", option.flags, flag);
 538  } else {
 539    console.error("  error: option `%s' argument missing", option.flags);
 540  }
 541  console.error();
 542  process.exit(1);
 543};
 544
 545/**
 546 * Unknown option `flag`.
 547 *
 548 * @param {String} flag
 549 * @api private
 550 */
 551
 552Command.prototype.unknownOption = function(flag){
 553  console.error();
 554  console.error("  error: unknown option `%s'", flag);
 555  console.error();
 556  process.exit(1);
 557};
 558
 559/**
 560 * Set the program version to `str`.
 561 *
 562 * This method auto-registers the "-V, --version" flag
 563 * which will print the version number when passed.
 564 *
 565 * @param {String} str
 566 * @param {String} flags
 567 * @return {Command} for chaining
 568 * @api public
 569 */
 570
 571Command.prototype.version = function(str, flags){
 572  if (0 == arguments.length) return this._version;
 573  this._version = str;
 574  flags = flags || '-V, --version';
 575  this.option(flags, 'output the version number');
 576  this.on('version', function(){
 577    console.log(str);
 578    process.exit(0);
 579  });
 580  return this;
 581};
 582
 583/**
 584 * Set the description `str`.
 585 *
 586 * @param {String} str
 587 * @return {String|Command}
 588 * @api public
 589 */
 590
 591Command.prototype.description = function(str){
 592  if (0 == arguments.length) return this._description;
 593  this._description = str;
 594  return this;
 595};
 596
 597/**
 598 * Set / get the command usage `str`.
 599 *
 600 * @param {String} str
 601 * @return {String|Command}
 602 * @api public
 603 */
 604
 605Command.prototype.usage = function(str){
 606  var args = this.args.map(function(arg){
 607    return arg.required
 608      ? '<' + arg.name + '>'
 609      : '[' + arg.name + ']';
 610  });
 611
 612  var usage = '[options'
 613    + (this.commands.length ? '] [command' : '')
 614    + ']'
 615    + (this.args.length ? ' ' + args : '');
 616  if (0 == arguments.length) return this._usage || usage;
 617  this._usage = str;
 618
 619  return this;
 620};
 621
 622/**
 623 * Return the largest option length.
 624 *
 625 * @return {Number}
 626 * @api private
 627 */
 628
 629Command.prototype.largestOptionLength = function(){
 630  return this.options.reduce(function(max, option){
 631    return Math.max(max, option.flags.length);
 632  }, 0);
 633};
 634
 635/**
 636 * Return help for options.
 637 *
 638 * @return {String}
 639 * @api private
 640 */
 641
 642Command.prototype.optionHelp = function(){
 643  var width = this.largestOptionLength();
 644  
 645  // Prepend the help information
 646  return [pad('-h, --help', width) + '  ' + 'output usage information']
 647    .concat(this.options.map(function(option){
 648      return pad(option.flags, width)
 649        + '  ' + option.description;
 650      }))
 651    .join('\n');
 652};
 653
 654/**
 655 * Return command help documentation.
 656 *
 657 * @return {String}
 658 * @api private
 659 */
 660
 661Command.prototype.commandHelp = function(){
 662  if (!this.commands.length) return '';
 663  return [
 664      ''
 665    , '  Commands:'
 666    , ''
 667    , this.commands.map(function(cmd){
 668      var args = cmd.args.map(function(arg){
 669        return arg.required
 670          ? '<' + arg.name + '>'
 671          : '[' + arg.name + ']';
 672      }).join(' ');
 673
 674      return cmd.name 
 675        + (cmd.options.length 
 676          ? ' [options]'
 677          : '') + ' ' + args
 678        + (cmd.description()
 679          ? '\n' + cmd.description()
 680          : '');
 681    }).join('\n\n').replace(/^/gm, '    ')
 682    , ''
 683  ].join('\n');
 684};
 685
 686/**
 687 * Return program help documentation.
 688 *
 689 * @return {String}
 690 * @api private
 691 */
 692
 693Command.prototype.helpInformation = function(){
 694  return [
 695      ''
 696    , '  Usage: ' + this.name + ' ' + this.usage()
 697    , '' + this.commandHelp()
 698    , '  Options:'
 699    , ''
 700    , '' + this.optionHelp().replace(/^/gm, '    ')
 701    , ''
 702    , ''
 703  ].join('\n');
 704};
 705
 706/**
 707 * Prompt for a `Number`.
 708 *
 709 * @param {String} str
 710 * @param {Function} fn
 711 * @api private
 712 */
 713
 714Command.prototype.promptForNumber = function(str, fn){
 715  var self = this;
 716  this.promptSingleLine(str, function parseNumber(val){
 717    val = Number(val);
 718    if (isNaN(val)) return self.promptSingleLine(str + '(must be a number) ', parseNumber);
 719    fn(val);
 720  });
 721};
 722
 723/**
 724 * Prompt for a `Date`.
 725 *
 726 * @param {String} str
 727 * @param {Function} fn
 728 * @api private
 729 */
 730
 731Command.prototype.promptForDate = function(str, fn){
 732  var self = this;
 733  this.promptSingleLine(str, function parseDate(val){
 734    val = new Date(val);
 735    if (isNaN(val.getTime())) return self.promptSingleLine(str + '(must be a date) ', parseDate);
 736    fn(val);
 737  });
 738};
 739
 740/**
 741 * Single-line prompt.
 742 *
 743 * @param {String} str
 744 * @param {Function} fn
 745 * @api private
 746 */
 747
 748Command.prototype.promptSingleLine = function(str, fn){
 749  if ('function' == typeof arguments[2]) {
 750    return this['promptFor' + (fn.name || fn)](str, arguments[2]);
 751  }
 752
 753  process.stdout.write(str);
 754  process.stdin.setEncoding('utf8');
 755  process.stdin.once('data', function(val){
 756    fn(val.trim());
 757  }).resume();
 758};
 759
 760/**
 761 * Multi-line prompt.
 762 *
 763 * @param {String} str
 764 * @param {Function} fn
 765 * @api private
 766 */
 767
 768Command.prototype.promptMultiLine = function(str, fn){
 769  var buf = [];
 770  console.log(str);
 771  process.stdin.setEncoding('utf8');
 772  process.stdin.on('data', function(val){
 773    if ('\n' == val || '\r\n' == val) {
 774      process.stdin.removeAllListeners('data');
 775      fn(buf.join('\n'));
 776    } else {
 777      buf.push(val.trimRight());
 778    }
 779  }).resume();
 780};
 781
 782/**
 783 * Prompt `str` and callback `fn(val)`
 784 *
 785 * Commander supports single-line and multi-line prompts.
 786 * To issue a single-line prompt simply add white-space
 787 * to the end of `str`, something like "name: ", whereas
 788 * for a multi-line prompt omit this "description:".
 789 *
 790 *
 791 * Examples:
 792 *
 793 *     program.prompt('Username: ', function(name){
 794 *       console.log('hi %s', name);
 795 *     });
 796 *     
 797 *     program.prompt('Description:', function(desc){
 798 *       console.log('description was "%s"', desc.trim());
 799 *     });
 800 *
 801 * @param {String|Object} str
 802 * @param {Function} fn
 803 * @api public
 804 */
 805
 806Command.prototype.prompt = function(str, fn){
 807  var self = this;
 808
 809  if ('string' == typeof str) {
 810    if (/ $/.test(str)) return this.promptSingleLine.apply(this, arguments);
 811    this.promptMultiLine(str, fn);
 812  } else {
 813    var keys = Object.keys(str)
 814      , obj = {};
 815
 816    function next() {
 817      var key = keys.shift()
 818        , label = str[key];
 819
 820      if (!key) return fn(obj);
 821      self.prompt(label, function(val){
 822        obj[key] = val;
 823        next();
 824      });
 825    }
 826
 827    next();
 828  }
 829};
 830
 831/**
 832 * Prompt for password with `str`, `mask` char and callback `fn(val)`.
 833 *
 834 * The mask string defaults to '', aka no output is
 835 * written while typing, you may want to use "*" etc.
 836 *
 837 * Examples:
 838 *
 839 *     program.password('Password: ', function(pass){
 840 *       console.log('got "%s"', pass);
 841 *       process.stdin.destroy();
 842 *     });
 843 *
 844 *     program.password('Password: ', '*', function(pass){
 845 *       console.log('got "%s"', pass);
 846 *       process.stdin.destroy();
 847 *     });
 848 *
 849 * @param {String} str
 850 * @param {String} mask
 851 * @param {Function} fn
 852 * @api public
 853 */
 854
 855Command.prototype.password = function(str, mask, fn){
 856  var self = this
 857    , buf = '';
 858
 859  // default mask
 860  if ('function' == typeof mask) {
 861    fn = mask;
 862    mask = '';
 863  }
 864
 865  process.stdin.resume();
 866  tty.setRawMode(true);
 867  process.stdout.write(str);
 868
 869  // keypress
 870  process.stdin.on('keypress', function(c, key){
 871    if (key && 'enter' == key.name) {
 872      console.log();
 873      process.stdin.removeAllListeners('keypress');
 874      tty.setRawMode(false);
 875      if (!buf.trim().length) return self.password(str, mask, fn);
 876      fn(buf);
 877      return;
 878    }
 879
 880    if (key && key.ctrl && 'c' == key.name) {
 881      console.log('%s', buf);
 882      process.exit();
 883    }
 884
 885    process.stdout.write(mask);
 886    buf += c;
 887  }).resume();
 888};
 889
 890/**
 891 * Confirmation prompt with `str` and callback `fn(bool)`
 892 *
 893 * Examples:
 894 *
 895 *      program.confirm('continue? ', function(ok){
 896 *        console.log(' got %j', ok);
 897 *        process.stdin.destroy();
 898 *      });
 899 *
 900 * @param {String} str
 901 * @param {Function} fn
 902 * @api public
 903 */
 904
 905
 906Command.prototype.confirm = function(str, fn, verbose){
 907  var self = this;
 908  this.prompt(str, function(ok){
 909    if (!ok.trim()) {
 910      if (!verbose) str += '(yes or no) ';
 911      return self.confirm(str, fn, true);
 912    }
 913    fn(parseBool(ok));
 914  });
 915};
 916
 917/**
 918 * Choice prompt with `list` of items and callback `fn(index, item)`
 919 *
 920 * Examples:
 921 *
 922 *      var list = ['tobi', 'loki', 'jane', 'manny', 'luna'];
 923 *      
 924 *      console.log('Choose the coolest pet:');
 925 *      program.choose(list, function(i){
 926 *        console.log('you chose %d "%s"', i, list[i]);
 927 *        process.stdin.destroy();
 928 *      });
 929 *
 930 * @param {Array} list
 931 * @param {Number|Function} index or fn
 932 * @param {Function} fn
 933 * @api public
 934 */
 935
 936Command.prototype.choose = function(list, index, fn){
 937  var self = this
 938    , hasDefault = 'number' == typeof index;
 939
 940  if (!hasDefault) {
 941    fn = index;
 942    index = null;
 943  }
 944
 945  list.forEach(function(item, i){
 946    if (hasDefault && i == index) {
 947      console.log('* %d) %s', i + 1, item);
 948    } else {
 949      console.log('  %d) %s', i + 1, item);
 950    }
 951  });
 952
 953  function again() {
 954    self.prompt('  : ', function(val){
 955      val = parseInt(val, 10) - 1;
 956      if (hasDefault && isNaN(val)) val = index;
 957
 958      if (null == list[val]) {
 959        again();
 960      } else {
 961        fn(val, list[val]);
 962      }
 963    });
 964  }
 965
 966  again();
 967};
 968
 969/**
 970 * Camel-case the given `flag`
 971 *
 972 * @param {String} flag
 973 * @return {String}
 974 * @api private
 975 */
 976
 977function camelcase(flag) {
 978  return flag.split('-').reduce(function(str, word){
 979    return str + word[0].toUpperCase() + word.slice(1);
 980  });
 981}
 982
 983/**
 984 * Parse a boolean `str`.
 985 *
 986 * @param {String} str
 987 * @return {Boolean}
 988 * @api private
 989 */
 990
 991function parseBool(str) {
 992  return /^y|yes|ok|true$/i.test(str);
 993}
 994
 995/**
 996 * Pad `str` to `width`.
 997 *
 998 * @param {String} str
 999 * @param {Number} width
1000 * @return {String}
1001 * @api private
1002 */
1003
1004function pad(str, width) {
1005  var len = Math.max(0, width - str.length);
1006  return str + Array(len + 1).join(' ');
1007}
1008
1009/**
1010 * Output help information if necessary
1011 *
1012 * @param {Command} command to output help for
1013 * @param {Array} array of options to search for -h or --help
1014 * @api private
1015 */
1016
1017function outputHelpIfNecessary(cmd, options) {
1018  options = options || [];
1019  for (var i = 0; i < options.length; i++) {
1020    if (options[i] == '--help' || options[i] == '-h') {
1021      process.stdout.write(cmd.helpInformation());
1022      cmd.emit('--help');
1023      process.exit(0);
1024    }
1025  }
1026}