みなさん、sbtのtest-onlyとか使ってますか?
http://www.scala-sbt.org/0.12.3/docs/Detailed-Topics/Testing#test-only
簡単にtest-onlyの動作を説明すると
- あたえられた名前のclassのテストのみ実行*1
- テストコードのコンパイルがされていれば、それらのテストのclassの名前が補完候補にでてくる
- それらの補完候補は、*2projectをreloadしたりしてもずっと有効!
など、とても便利です。され、これらの
- タブで補完がされる
- 補完候補が動的に変わる
- 補完候補がキャッシュされる
という仕組みは、test-onlyのためだけに特別に用意されているのではなく、すごく汎用的になっていて誰でも使えるようになっています。
というわけで、似たようなサンプルを作ってみました。今回はseratchさんのscalikejdbcのサンプルプロジェクトを利用しました。
コードはこれ↓
https://github.com/xuwei-k/devteam-app/commit/5bb642b306d5c4
https://github.com/xuwei-k/devteam-app/blob/5bb642b3/project/DB.scala
動作としては
- "show-describe テーブル名"
- そのテーブルのdescribeを表示(内部的にscalikejdbc.DB.describeを呼んで表示するだけ)
- "show-column-names テーブル名"
- 同じく内部的にscalikejdbc.DB. getColumnNamesを呼ぶ
- そして、そのテーブル名が補完が効く
- テーブル名の補完候補は"table-names"というTaskで、取得、更新
です。
以下ひたすら実装の細かい説明
- 公式にドキュメントはあるけど、このあたり全部載ってるわけではないので、こういう結構凝ったものを作る場合はソース読もう
- なぜprojectをreloadしてもキャッシュできるか*3というと、sbtがsbinaryというscalaで作られたシンプルなシリアライゼーションライブラリに依存しているからです。
- https://github.com/harrah/sbinary
- sbinaryの作者はsbt作者と同じ
- "tableNames <<= tableNames storeAs tableNames"とかやってるのがキャッシュ設定してる
- sbtのKeyの仕組みと統合されていて使いやすい
- 補完のための独自Parserについては以前書いた
- project/project/plugins.sbt にscalikejdbcの依存を書いてもできるが、それはせずに本体側をリフレクション経由で呼び出ししてる
- 今回のサンプル程度ならどちらでも変わらないが、もっと「モデルのclassのコードと関連したTask定義」などをする場合、そうするしかない
- sbt側からリフレクション経由でのメインコード呼び出しも以前blog書いた
- sbt側は現状の0.12系はScala2.9で、本体は2.10というようにScalaのversionが異なる場合注意が必要
- 本当は、本体に作ったDatabase.scalaは(開発時のみで実際運用時に必要ないなら)専用プロジェクトに分けるべき
- サンプルなのでDatabase.scalaの設定はベタ書きで色々雑です
最後に実行した画面を貼り付けておきます