Node.js

Node.jsでサクッとCLIアプリ作るなら cacjs が便利だよ

こんにちは、Pちゃんです。
この記事は、DeNA IPプラットフォーム事業部 Advent Calendar 2017 18日目の記事です。
@koooootake に勧誘されて、うっかりアドベントカレンダーに登録してしまいました。


さて、今日はNode.jsを使ってサクッとCUIアプリケーションを作る方法を紹介していきたいと思います。

技術選定

一見、CLIアプリケーションの一つや二つくらい、素のNode.jsでも書くことができそうだと考えがちです。
しかし、サブコマンドの処理やオプションの処理、ヘルプを出すことなどを考えると、意外と面倒だったりします。
そこで、何かしらのフレームワークに乗っかるのが合理的です。

Node.jsでCUIアプリケーションをつくるためのフレームワークは、わりと数年前からデファクトが決まっています。
自分の観測範囲では、以下の2つがよく使われている気がします。

しかし、今回は敢えて cacjs を紹介しようと思います。
cacjs は、@egoist がつくった、シンプルでパワフルなコマンドラインインターフェイスをつくるためのフレームワークです。

特徴としては、

  • 一つのコマンドに関する処理を一箇所にまとめて書けるので、直感的に書きやすい
  • プラグイン機構を備えているため、本気でカスタマイズしていくことも可能である

などがあります。

cacjs でCLIアプリをつくる

1. cacjs をインストールする

$ mkdir cli-app-sample && cd cli-app-sample
$ npm init
$ npm install cac

2. コードを書く

index.js をつくって、以下を書きます。
以下、敬称略です。

index.js
const cac = require('cac')
const cli = cac()

const managers = ['ラミレス', '中畑', '尾花', '大矢', '牛島']

cli.command('managers', {
  desc: '横浜DeNAベイスターズの今の監督を表示します'
}, () => {
  console.log(`今の監督は${managers[0]}です`)
})

cli.parse()

3. 実行してみる

実はもうさっき書いた十数行でCLIアプリができています。
試しに managers を実行してみます。

$ node index.js managers
今の監督はラミレスです

次に --help とかも試してみます。

$ node index.js --help

  index.js 1.0.0

  USAGE

    index.js <command> [options]

  COMMANDS

    managers  横浜DeNAベイスターズの今の監督を表示します

  GLOBAL OPTIONS

    -v, --version  Display version                     [Type: boolean]
    -h, --help     Display help (You're already here)  [Type: boolean]

$ node index.js --version
1.0.0

すげえ、簡単すぎる。

4. サブコマンドを試してみる

先ほどのサンプルを改造して、過去の監督も取得できるようにしてみたいと思います。
cli.command のコールバックで input が返ってくるので、それを利用します。

index.js
const cac = require('cac')

const cli = cac()

const managers = ['ラミレス', '中畑', '尾花', '大矢', '牛島']

cli.command('managers', {
  desc: '横浜DeNAベイスターズの過去の監督を表示します'
}, (input) => {
  if (input[0] > 0) {
    console.log(`${input[0]}人前の監督は${managers[input[0]]}です`)
  } else {
    console.log(`今の監督は${managers[0]}です`)
  }
})

cli.parse()
$ node index.js managers 1
1人前の監督は中畑です

5. フラグを試してみる

さて、先ほどのサンプルをさらに改造して、監督のフルネームも取得できるようにしてみようと思います。
今回の場合、$ node index.js managers 3 --fullname などとすると、3人前の監督がフルネームで取得できるようにします。
cli.command のコールバックで flag が返ってくるので、それを利用します。

index.js
const cac = require('cac')

const cli = cac()

const managers = [
  ['アレックス', 'ラミレス'],
  ['中畑', '清'],
  ['尾花', '高夫'],
  ['大矢', '明彦'],
  ['牛島', '和彦']
]

cli.command('managers', {
  desc: '横浜DeNAベイスターズの過去の監督を表示します'
}, (input, flag) => {

  let managerNum = input[0] || 0

  if (managerNum > managers.length - 1 ) {
    console.log(`${managers.length}人以上前の監督のデータはありません...`)
    process.exit(1)
  }

  let managerName = managers[managerNum][0]

  // ここで flag.fullname を見て true ならフルネームにする
  if (flag.fullname) {
    managerName += ' ' + managers[managerNum][1]
  }

  if (!managerNum) {
    console.log(`今の監督は${managerName}です`)
  } else if (managers.length > managerNum) {
    console.log(`${managerNum}人前の監督は${managerName}です`)
  }
})

cli.parse()
$ node index.js managers 4 --fullname
4人前の監督は牛島 和彦です

まとめ

  • Node.jsで、サクッとCLIアプリ作るなら「cacjs」が便利だ
  • ラミちゃんの本名は「アレキサンダー・ラモン・ラミレス・キニョーネス」