(※Vim使いじゃない人にはよくわからんかもしれませんが、最後までお付き合いください)
皆さんはVim、大好きですよね?Rails、大好きですよね?ということは、Rails.vim、大好きですよね?
というわけで、今日は Rails.vim のご紹介…なんですが、基本的な説明はすでにたくさん良いものがあります(日本語でしたらこちらなど)。
ここで私が屋上屋を架してもしょうがない…そこで、探しても日本語情報がなかった、projections
という機能について書くことにします。
最小限の前提知識
まず、今回の説明に必要な最低限のことを説明します。「そんなの知ってるぜ!」っていうそこのアナタは次のセクションまで飛んでしまいましょう!
Rails.vimには Alternate なファイル、 Related なファイルという概念があります。Alternateなファイルとして扱われるのは主に対応するテストやスペックです。Relatedなファイルになりうるものはより幅広く、例えばActiveRecordモデルに対するRelatedなファイルはschema.rbの対応する部分(Userモデルであればcreate_table :usersの部分)になっています(詳しい説明は:help rails-alternate
で見れます)。これらのファイルにアクセスするにはそれぞれ:A
コマンドと:R
コマンドを使います。
また、上記の:A
や:R
には後ろにSやVをつけることができます。例えば:AV
や:RS
などです。これらのコマンドは対応するファイルを 別のwindowで 開きます。Sな横分割後、Vなら縦分割後に片方のwindowに対応するファイルが表示されます。もうお分かりの通り、Sはsplitの略、Vはvsplitの略です。新規タブでファイルを開くTもあります。
また、:E
コマンドもあります。これはEditの略で、後ろに様々なtypeをつけることでコマンドとして機能します。例えば:Emodel
や:Econtroller
、:Ejavascript
なんかもあります(しかもCoffeeScriptにも使えます)。EをSやV、Tに置き換えても、皆さんの想像どおりに動きます。
このコマンドの優れたところは、ファイルの作成まで出来ることです。:Emodel vimmer
と入力する場合、Vimmer
モデルがなければエラーになります(no such model vimmer
と怒られます)。ここでvimmerの直後に「!」をつけると(つまり:Emodel vimmer!
と入力すると)、Vimmerモデルが新たに作られます。作られたファイルは
class Vimmer
end
となっています。
projectionsとはなにか
この機能は今年3月の終わりにリリースされたバージョン5.0より追加されたものです。公式ドキュメントによると、
Projections let you teach rails.vim about app specific and gem specific behavior.
だそうです。Rails.vimにアプリ固有、gem固有な振る舞いを教えることができるようです。と言っても具体性に欠けますね。実際にやってみましょう(以下の内容はOSX Mavericks上のMacVim7.4-72、masterブランチのRails.vim、Rails4.0.2で動作確認しています)。
ユースケース:uploaderのためのコマンドを追加する
画像をアップロードできるようなアプリを作っているとしましょう。そのためのgemとしてはcarrierwaveが有名ですね。このgemでは#{Rails.root}/apps/uploaders
ディレクトリ下にuploaderモデルを配置することになります。
ところが、Rails.vimはuploaderについて一切関知していないのです。まあ当たり前ですね、carrierwaveのためのディレクトリなわけですから。しかしこれでは、:Euploaderコマンドも使えないし、carrierwave固有のキーワードがシンタックスハイライトされることもないのです。それはとても悲しいことです。
では、projectionsを使ってRails.vimにuploaderについて教えてあげましょう。
projectionsの設定方法は実は 4種類 あります。が、プロジェクトのディレクトリを汚してしまったり(そしてSCMにチェックインするかignoreファイルに追記するかで迷ったり)、 bundler.vim という別のプラグインが必要だったりでハードルが高い印象です(余談ですが、上記のbundler.vimはRails.vimと同じTim Pope氏によるものです。彼は pathogen.vim 、 fugitive.vim 、 surround.vim の作者でもあります。Rails使いじゃない人でも恩恵を蒙ってる人は多いでしょう)。そこで今回は一番簡単な方法、vimrc内にグローバル変数を記述する方法で行きましょう。
使用する変数はg:rails_projections
です。ここにjsonっぽく書いていくことになります(ドキュメント中にもありますが、Vimscriptはほとんどjsonなんですよね、バックスラッシュの壁を除けば)。具体的なコードは以下になります。
let g:rails_projections = {
\ "app/uploaders/*_uploader.rb": {
\ "command": "uploader",
\ "template":
\ "class %SUploader < CarrierWave::Uploader::Base\nend",
\ "test": "spec/models/%s_uploader_spec.rb",
\ "related": "app/models/images/%s.rb",
\ "keywords": "process version"
\ },
全部説明するととても長くなってしまうので、要点だけ。
2行目ではパターンを指定しています。アスタリスクはひとつだけ可能で、そこでキャプチャした文字列を後々使うことができます。
commandの部分は:Emodel
のmodelに当たる部分です。
templateに指定した文字列は、!をつけてファイルを新規に作成した際に使われるものです。%Sは先ほどアスタリスクでキャプチャした文字列をcamelizeしたものです(この%プレースホルダは他にもあります。詳細は後述します)。
testはそのまんまなので省略しますが、testはalternateのデフォルトになっているのでそこは注意。
relatedもそのままです。
keywordsはシンタックスハイライトされる文字列の指定です。複数指定する際は半角空白で区切ります。ここで指定したキーワードは2行目で指定したパターンに当てはまる場合のみ有効になりますので、無関係な場所にある同名のトークンがハイライトされることはありません。
その他のユースケース
…思いつかなかった(´・ω・`)
gem固有の振る舞いはたくさん定義することが可能であり、かつ有用ではあると思うのですが、いかんせん個別ケース過ぎて、ここでいちいち紹介する気になれませんでした。
一方、アプリ固有の振る舞いですが、そもそもRailsの規約に則って開発している限りでは不要だと思います。もしあまりにもいろいろなコマンドを自分で追加しているとしたら、それはレールから外れすぎであることの証拠かもしれません(それぐらい、デフォルトのコマンド群がよく出来ているということでもあります)。
補足
template等で利用可能な%プレースホルダですが、そのリストは以下です。
%s: original
%S: camelized
%p: pluralized
%i: singularized
%h: humanized
まとめ
Tim Popeすげーw
…というのも事実ではありますが、ある意味 それ以上にすごいのはRailsの規約 だと思います。ナビゲーション系のコマンドが恐ろしく効率良く機能し、かつ設定がほとんど不要であるのはひとえに規約があるゆえでしょう。
ともあれ、これでRails.vimで痒いところに手が届くようになりました。すでにRails.vimは使ってるけどprojectionsは知らなかったよという人は、どんどんカスタマイズして更に作業能率を上げましょう!また、テスト間の移動が楽になるのでテストを書く回数も増えるかもしれません、とてもいいことですね!
Rails使いで他のエディタを使ってる人はぜひ、Vimも使ってみてください。世界が変わるかも!?
参考資料
thoughtbotの記事
プレゼンテーション(ただし、英語の上聞き取りづらい)
githubレポジトリ
そして何より、 公式ドキュメント です。もちろん英語のみですが、必要な情報はほぼ網羅されている上、読みやすいです。ヘビーユーザーには通読をオススメします。