Permalink
Browse files

Added .fill() feature

.fill() method makes it easy to write multiple prompt at once.
  • Loading branch information...
1 parent 8e26188 commit 65862f81144271568cff30c346fe766b7ec1084e @kuwabarahiroshi committed Feb 14, 2012
Showing with 235 additions and 0 deletions.
  1. +51 −0 examples/fill
  2. +70 −0 lib/commander.js
  3. +114 −0 test/test.prompt.fill.js
View
@@ -0,0 +1,51 @@
+#!/usr/bin/env node
+
+/**
+ * Module dependencies.
+ */
+
+var program = require('../');
+
+function normalizeSex(sex) {
+ return sex.toLowerCase() == 'm' || sex.toLowerCase == 'male' ? 'male' : 'female';
+}
+
+program
+ .version('0.0.1')
+ .option('-n --nickname <name>', 'Your nickname.')
+ .option('-a --age <age>', 'Your age.')
+ .option('-s --sex <sex>', 'Your sex. [ male | female ]', normalizeSex, 'unknown')
+ .option('-f --favorite-song <song>', 'Your favorite <song>.')
+ .parse(process.argv);
+
+program
+ .fill({
+ 'nickname': 'What is your nickname? '
+ , 'age': 'How old are your? '
+ , 'favorite-song': 'What is your favorite song? ' // option name can be camelCase as well
+ })
+
+// Filled arguments are available on 'filled' event.
+program.on('filled', function(program) {
+ console.log(' - name: %s', program.nickname);
+ console.log(' - age: %s', program.age);
+ console.log(' - sex: %s', program.sex);
+ console.log(' - favorite song: %s', program.favoriteSong);
+});
+
+
+
+/**
+ * Miscelenious
+ */
+
+/**
+ * .fill() method takes 2nd argument as a callback
+ */
+// These two lines are synonymous.
+// program.fill({'a', 'aaa: '}, main);
+// program.fill({'a': 'aaa: '}).on('filled', main);
+//
+// function main(program) {
+// console.log(program);
+// }
View
@@ -946,6 +946,76 @@ Command.prototype.choose = function(list, index, fn){
};
/**
+ * Fill arguments with prompt if it isn't specified on command line.
+ *
+ * Examples:
+ *
+ * program
+ * .option('-n, --nickname <name>')
+ * .option('-a, --age <age>')
+ * .option('-s', --sex <sex>')
+ * .parse(process.argv);
+ *
+ * // .fill() should be called after .parse()
+ * program.fill({
+ * 'nickname': 'What is your nickname? '
+ * , 'age': 'How old are you? '
+ * });
+ *
+ * // if '--nickname' or '--age' aren't supplied with command line option,
+ * // those values will be filled with prompt.
+ * // '--sex' is still just an option because it isn't specified to be filled.
+ *
+ * // Filled arguments are available on 'filled' event.
+ * program.on('filled', function(program) {
+ * console.log('name: %s', program.nickname);
+ * console.log('age: %s', program.age);
+ * console.log('sex: %s', program.sex);
+ * });
+ *
+ * @param {Object} config
+ * @param {Function} callback
+ * @return {Command} for chaining
+ * @api public
+ */
+
+Command.prototype.fill = function(config, callback) {
+ var queue = [], arg, camel;
+ if ('function' === typeof callback) this.on('filled', callback);
+
+ for (arg in config) {
+ if ((camel = camelcase(arg)) in this) continue;
+ queue.push({'arg': camel, 'prompt_message': config[arg]});
+ }
+ fillWithPrompt(this, queue);
+ return this;
+};
+
+/**
+ * Fill in queued arguments with prompt
+ *
+ * @param {Command} command
+ * @param {Array} queue
+ * @api private
+ */
+
+function fillWithPrompt(command, queue) {
+ if (!queue.length) {
+ // guaranntee to execute 'filled' callback
+ // even if all arguments are supplied with command line option.
+ setTimeout(function() { command.emit('filled', command); }, 0);
+ process.stdin.pause();
+ return;
+ }
+
+ var current = queue.shift();
+ command.prompt(current['prompt_message'], function(input) {
+ command[current.arg] = input.trim();
+ fillWithPrompt(command, queue);
+ });
+}
+
+/**
* Camel-case the given `flag`
*
* @param {String} flag
View
@@ -0,0 +1,114 @@
+/**
+ * Module dependencies.
+ */
+
+var events = require('events')
+ , should = require('should')
+ , Command = require('../').Command;
+
+//mock stdin on process
+var stdin = new events.EventEmitter();
+stdin.setEncoding = stdin.pause = stdin.resume = function() {};
+stdin.write = function(data) { stdin.emit('data', data); };
+process.__defineGetter__('stdin', function() { return stdin });
+
+//mock stdout on process
+var stdout = new events.EventEmitter();
+stdout.write = function(data) { this.emit('data', data) };
+stdout.expect = function(expected, fn) {
+ var actual = '';
+ this.once('data', function(data){ actual = data; });
+ fn();
+ actual.should.equal(expected);
+}
+//var realOut = process.stdout;
+process.__defineGetter__('stdout', function() { return stdout });
+
+var name_prompt = 'What is your name? '
+ , age_prompt = 'How old are your? '
+ , name_input_on_command = 'name input on command'
+ , age_input_on_command = 'age input on command'
+ , name_input_from_prompt = 'name input from prompt'
+ , age_input_from_prompt = 'age input from prompt'
+ , prompt_config = {
+ 'nickname': name_prompt
+ , 'age': age_prompt
+ };
+
+
+/**
+ * Test case that --nickname and --age aren't supplied on command line.
+ */
+program = new Command()
+ .option('-n, --nickname <name>')
+ .option('-a, --age <age>')
+ .parse(['node', 'test']);
+
+stdout.expect(name_prompt, function() {
+ program.fill(prompt_config);
+
+ stdout.expect(age_prompt, function() {
+ stdin.write(name_input_from_prompt);
+ });
+
+ stdin.write(age_input_from_prompt);
+})
+
+program.on('filled', function(program) {
+ program.should.have.property('nickname', name_input_from_prompt);
+ program.should.have.property('age', age_input_from_prompt);
+});
+
+
+/**
+ * Test case that --nickname is supplied on command line, but --age.
+ */
+program = new Command()
+ .option('-n, --nickname <name>')
+ .option('-a, --age <age>')
+ .parse(['node', 'test', '--nickname', name_input_on_command]);
+
+stdout.expect(age_prompt, function() {
+ program.fill(prompt_config);
+ stdin.write(age_input_from_prompt);
+})
+
+program.on('filled', function(program) {
+ program.should.have.property('nickname', name_input_on_command);
+ program.should.have.property('age', age_input_from_prompt);
+});
+
+
+/**
+ * Test case that --age is supplied on command line, but --nickname.
+ */
+program = new Command()
+ .option('-n, --nickname <name>')
+ .option('-a, --age <age>')
+ .parse(['node', 'test', '--age', age_input_on_command]);
+
+stdout.expect(name_prompt, function() {
+ program.fill(prompt_config);
+ stdin.write(name_input_from_prompt);
+})
+
+program.on('filled', function(program) {
+ program.should.have.property('nickname', name_input_from_prompt);
+ program.should.have.property('age', age_input_on_command);
+});
+
+
+/**
+ * Test case that --nickname and --age are supplied on command line.
+ */
+program = new Command()
+ .option('-n, --nickname <name>')
+ .option('-a, --age <age>')
+ .parse(['node', 'test', '--nickname', name_input_on_command, '--age', age_input_on_command]);
+
+program.fill(prompt_config);
+
+program.on('filled', function(program) {
+ program.should.have.property('nickname', name_input_on_command);
+ program.should.have.property('age', age_input_on_command);
+});

0 comments on commit 65862f8

Please sign in to comment.