とんちゃん の ぐだぐだえびでい

バックエンドエンジニアのとんちゃんが、ぐだぐだな毎日で培った技術情報を綴るブログです。

commander.jsの使い方訳してみる

どうも。
かみさんに招待されて、ドラゴンスラッシュというゲームを始めました。
ステージ選択すれば勝手に先頭が進んでいくので、楽です。

やってる方いたら一緒にレイド行きませんかね。

あ、いませんね。

今日は

node.jsのコマンドライン引数をよしなにパーシングしたりしてくれるライブラリの
commander.jsの使い方ページを日本語に訳してみます。

自分で頑張って読んでても、間違ってたら悲しいので、突っ込みお待ちしております。

元サイト

www.npmjs.com

日本語訳

rubyのcommanderAPIにインスパイアされた、
node.js コマンドライン インターフェースの完全解です。

APIドキュメントはこちら ⇒ Commander.js - nodejs cli framework

インストール方法

$ npm install commander

ちなみに

$ npm install --save-dev commander

だと、package.jsonに自動で書かれるので楽だと思いました。

参考:
qiita.com

オプションの解析

commanderでは、コマンドオプションのマニュアルとして、.option()メソッドでオプションを定義します。

次の例では、 process.argvから引数とオプションを解析し、
program.args配列として、オプションによって使用されなかった残りの引数を取得します。

#!/usr/bin/env node
 
// commanderモジュールをインポート
var program = require('commander');

// パースの設定と実行
program
  .version('0.0.1')
  .option('-p, --peppers', 'Add peppers')
  .option('-P, --pineapple', 'Add pineapple')
  .option('-b, --bbq-sauce', 'Add bbq sauce')
  .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')
  .parse(process.argv); // 引数のパース
 
console.log('you ordered a pizza with:');
if (program.peppers) console.log('  - peppers');
if (program.pineapple) console.log('  - pineapple');
if (program.bbqSauce) console.log('  - bbq');
console.log('  - %s cheese', program.cheese);

ショートフラグ、例えば、-abcは -a -b -cと同等である、1つの引数として渡すことができます。
"--template-engine"のような、複数単語オプションは、キャメルケースprogram.templateEngineになります。

オプションの強制
function range(val) {
  return val.split('..').map(Number);
}
 
function list(val) {
  return val.split(',');
}
 
function collect(val, memo) {
  memo.push(val);
  return memo;
}
 
function increaseVerbosity(v, total) {
  return total + 1;
}
 
program
  .version('0.0.1')
  .usage('[options] <file ...>')
  .option('-i, --integer <n>', 'An integer argument', parseInt)
  .option('-f, --float <n>', 'A float argument', parseFloat)
  .option('-r, --range <a>..<b>', 'A range', range)
  .option('-l, --list <items>', 'A list', list)
  .option('-o, --optional [value]', 'An optional value')
  .option('-c, --collect [value]', 'A repeatable value', collect, [])
  .option('-v, --verbose', 'A value that can be increased', increaseVerbosity, 0)
  .parse(process.argv);
 
console.log(' int: %j', program.integer);
console.log(' float: %j', program.float);
console.log(' optional: %j', program.optional);
program.range = program.range || [];
console.log(' range: %j..%j', program.range[0], program.range[1]);
console.log(' list: %j', program.list);
console.log(' collect: %j', program.collect);
console.log(' verbosity: %j', program.verbose);
console.log(' args: %j', program.args);
正規表現
program
  .version('0.0.1')
  .option('-s --size <size>', 'Pizza size', /^(large|medium|small)$/i, 'medium')
  .option('-d --drink [drink]', 'Drink', /^(coke|pepsi|izze)$/i)
  .parse(process.argv);
  
console.log(' size: %j', program.size);
console.log(' drink: %j', program.drink);
可変引数

コマンドの最後の引数は可変長引数、および唯一の最後の引数にすることができます。
...を引数名に持つ引数を可変長引数とします。

#!/usr/bin/env node
 
/**
 * Module dependencies.
 */
 
var program = require('commander');
 
program
  .version('0.0.1')
  .command('rmdir <dir> [otherDirs...]')
  .action(function (dir, otherDirs) {
    console.log('rmdir %s', dir);
    if (otherDirs) {
      otherDirs.forEach(function (oDir) {
        console.log('rmdir %s', oDir);
      });
    }
  });
program.parse(process.argv);

可変引数の値は、配列に展開されます。
上で示したように、アクションに渡された引数をprogram.argsから解析します。

引数の構文を指定する
#!/usr/bin/env node
 
var program = require('../');
 
program
  .version('0.0.1')
  .arguments('<cmd> [env]')
  .action(function (cmd, env) {
     cmdValue = cmd;
     envValue = env;
  });
 
program.parse(process.argv);
 
if (typeof cmdValue === 'undefined') {
   console.error('no command given!');
   process.exit(1);
}
console.log('command:', cmdValue);
console.log('environment:', envValue || "no environment given");
gitのようなサブコマンドを扱う
// file: ./examples/pm 
var program = require('..');

program
  .version('0.0.1')
  .command('install [name]', 'install one or more packages')
  .command('search [query]', 'search with optional query')
  .command('list', 'list packages installed', {isDefault: true})
  .parse(process.argv);

.command()が説明的な引数に対して呼び出された場合、
.action(callback)は、エラーがあるかもしれないサブコマンドを処理するために呼び出されるべきではありません。
これは、多くのgitや他のツールと同様に、実行プログラムにサブコマンドがあることをcommanderに教えます。

commanderは、pm-install,pm-searchのような、プログラムコマンドに設定された名前の実行可能ファイルを、エントリスクリプトのあるディレクトリで探します。

オプションは.command()関数を呼ぶことで、渡すことができます。
opts.noHelpにtrueを設定した項目は、ヘルプには表示しません。
opt.isDefaultにtrueを指定すると、他のサブコマンドが指定されていない場合は、デフォルトのサブコマンドとして実行します。

モジュールがグローバルにインストールされている場合、
実行プログラムは755のように、適切なモードを持っていることを確認してください。

ハーモニーオプション(--hermony)

ハーモニーオプション(--hermony)を有効にするために、2つの方法があります:
1.
サブコマンド用スクリプトにて、

#! /usr/bin/env node --harmony

を記述します。
※いくつかのOSバージョンはこのパターンをサポートしていません。

2.

node --harmony examples/pm

のように、--harmonyオプション付きでcallします。

    • harmonyオプションは、サブコマンドプロセス生成時に保持されます。
自動で--help

ヘルプ情報は、既にプログラムに設定されたものを元に、自動的に生成されます。
つまり、何もしなくても--helpオプションは効きます。

 $ ./examples/pizza --help
 
   Usage: pizza [options]
 
   An application for pizzas ordering
 
   Options:
 
     -h, --help           output usage information
     -V, --version        output the version number
     -p, --peppers        Add peppers
     -P, --pineapple      Add pineapple
     -b, --bbq            Add bbq sauce
     -c, --cheese <type>  Add the specified type of cheese [marble]
     -C, --no-cheese      You do not want any cheese

カスタムヘルプ

任意の-h,--helpを補足して、ヘルプ情報を表示できます。
commanderは、それ以降の処理は行わずに終了します。
例えば以下のサンプルは、"stuff"の表示は行われません。

#!/usr/bin/env node
 
/**
 * Module dependencies.
 */
 
var program = require('commander');
 
program
  .version('0.0.1')
  .option('-f, --foo', 'enable some foo')
  .option('-b, --bar', 'enable some bar')
  .option('-B, --baz', 'enable some baz');
 
// must be before .parse() since 
// node's emit() is immediate 
 
program.on('--help', function(){
  console.log('  Examples:');
  console.log('');
  console.log('    $ custom-help --help');
  console.log('    $ custom-help -h');
  console.log('');
});
 
program.parse(process.argv);
 
console.log('stuff');
ヘルプ出力時のオプションについて
node script-name.js -h
node script-name.js --help

で実行すると、以下のようにヘルプが表示されます。

Usage: custom-help [options]
 
Options:
 
  -h, --help     output usage information
  -V, --version  output the version number
  -f, --foo      enable some foo
  -b, --bar      enable some bar
  -B, --baz      enable some baz
 
Examples:
 
  $ custom-help --help
  $ custom-help -h

.outputHelp(cb)

終了せずにヘルプ情報を出力する。
オプションのコールバックCBは、ヘルプテキストが表示される前の後処理を可能にします。

デフォルトでヘルプを表示したい場合(コマンドが提供されなかった場合など)は、次のようなものを使用することができます:

var program = require('commander');
var colors = require('colors');
 
program
  .version('0.0.1')
  .command('getstream [url]', 'get stream URL')
  .parse(process.argv);
 
  if (!process.argv.slice(2).length) {
    program.outputHelp(make_red);
  }
 
function make_red(txt) {
  return colors.red(txt); //display the help text in red on the console 
}
.help(cb)

出力ヘルプすぐに情報を表示して終了します。
オプションのコールバックCBは、ヘルプテキストが表示される前の後処理を可能にします。

サンプル
var program = require('commander');
 
program
  .version('0.0.1')
  .option('-C, --chdir <path>', 'change the working directory')
  .option('-c, --config <path>', 'set config path. defaults to ./deploy.conf')
  .option('-T, --no-tests', 'ignore test hook')
 
program
  .command('setup [env]')
  .description('run setup commands for all envs')
  .option("-s, --setup_mode [mode]", "Which setup mode to use")
  .action(function(env, options){
    var mode = options.setup_mode || "normal";
    env = env || 'all';
    console.log('setup for %s env(s) with %s mode', env, mode);
  });
 
program
  .command('exec <cmd>')
  .alias('ex')
  .description('execute the given remote cmd')
  .option("-e, --exec_mode <mode>", "Which exec mode to use")
  .action(function(cmd, options){
    console.log('exec "%s" using %s mode', cmd, options.exec_mode);
  }).on('--help', function() {
    console.log('  Examples:');
    console.log();
    console.log('    $ deploy exec sequential');
    console.log('    $ deploy exec async');
    console.log();
  });
 
program
  .command('*')
  .action(function(env){
    console.log('deploying "%s"', env);
  });
 
program.parse(process.argv);

もっとサンプルが見たい方は、GitHubリポジトリの、examplesディレクトリを探してみてください。

github.com


ライセンス
MIT