最近MItamaeやxkremapなど、Rubyで設定ファイルを既述するCLIツールをCRubyではなくmrubyで実装することがあったのだが、そのようなCLIツールを作る際にCRubyではなくmrubyを使うことへの妥当性について考えていたことをダンプしておく。
以下、ハードウェアにmrubyを組み込む用途や、Ruby以外で書かれた既存のツールにmrubyを組み込む用途については(僕は特に経験してないので)除外して書きます。
CLIツールの作成にmrubyを使うメリット
- CRubyやrubygemsの存在に依存しないバイナリとしてCLIツールを作ることができる
- gem installする場合に比べ、rbenvに気を使わずバイナリを叩くだけで手軽に実行できる
- gem installして入れたCLIツールは、rbenvが入っている環境ではrbenv globalや.ruby-versionが違ったりsudoでユーザーが変わると動かなかったりするので、rbenvに気を使って実行しないといけない
- Ruby以外の依存も解決できれば、ダウンロードするだけで実行可能なバイナリにでき、配布が楽になる
- CRubyで作ったツールは、CRubyが既に入った環境でgem installさせるか、chef/omnibusなどを使って各OS/ディストリビューションごとにCRubyごとパッケージングする必要がある
- gem installする場合に比べ、rbenvに気を使わずバイナリを叩くだけで手軽に実行できる
CLIツールの作成にmrubyを使うデメリット
- CLI関係なくmrubyを使う際のデメリットがある
- 実装する時に一部の標準ライブラリやrubygemsが使えないので、自分で移植する必要がある
- デフォルトでは require がないし、ほぼ確実にそのままでは動かない
- mruby-requireを使うと、実行時にそのRubyのファイルが必要になってしまうので、mrubyが何らかのハードウェア/ソフトウェアに組み込む用途に使われる以上、極力使わない方が良い
- 移植しても、本家に変更を追従させるのが大変
- 移植する時にCのコードを書く機会が多い
- 特に、CLIツールで使いそうなmruby-ioに必要なメソッドが足りなかったりする
- RSpecが使えない
- pryが使えない
- デフォルトでは require がないし、ほぼ確実にそのままでは動かない
- mrubyはRubyの言語機能が一部実装されていない
- キーワード引数とかない
- CRubyに比べるとmrubyやサードパーティmrbgemの安定性が低い
- CRubyだとcoreに入っているような機能もmrubyだとサードパーティなので信頼性は低い
- undefined methodの時にたまにSEGVするが再現が困難で報告しにくい
- mruby-threadを使うとmruby-ioとかが壊れる
- 実装する時に一部の標準ライブラリやrubygemsが使えないので、自分で移植する必要がある
- mruby-cliを使っていても、Cのライブラリに依存したmrbgemを追加するとリンクやクロスコンパイル環境の準備が面倒
- 例えばmruby-cli上でmruby-onig-regexpのWindows向けのクロスコンパイルがうまくいかない
Rubyのスクリプトを評価するCLIツールはどんな時にmrubyで実装するべきなのか
これまでの話を総合すると、「mrubyを使ってCLIツールを実装すると、mrubyのエコシステムの成熟度的にメンテが大変になる代わりに、ツールを実行するまでのコストを下げることができる」という話になる。デメリットに上げた部分は がんばれば どれも解決可能な点が重要で、ツールを実装する時にがんばるのと、CLIツールを配布・実行する時にがんばるのとどちらが大変かで決めればよさそう。
で、技術選定の基準となりそうな事象のそれぞれにかかるコストを比べ、僕はmrubyで作るかどうかを以下のような基準で考えている。
まあrbenvについては大分細かい話な気もするが、rubygemでインストールしたツールの実行時にrbenvに悩まされたことがある人は普通にいるんじゃないだろうか。
お気持ち
mrubyがもっと便利になれば、どんなCLIツールもmrubyで実装した方が手軽で便利、という日も来るかもしれない。
CRubyを使うかどうか迷わせるほどmrubyやそのエコシステムを便利にしてくださっているみなさま、いつもありがとうございます。