12FF5B8

hico_horiuchiの技術系な覚え書き.

zshでbundle exec(とrake)を補完

SLP Advent Calendar 2013 - Adventarの13日目.
(この記事を書いたのは12.03(火)だけど.)

今月からSLPのCEMプロジェクトに参加して,Ruby on Railsで開発している.
そこでbundlerを使ってるのだが,bundle exec以降で補完されないのが辛い.

調べてみた

Googleでbundle execを省略する方法を調べてみた.

どちらもaliasとして展開するもので,補完ではない.
それに,OSのgemではなくbundlerから使うことを明示したい.

ということで,初めてzshの補完関数を書いてみた.

事前準備

bundler実行時に--binstubsで実行ファイルのインストール先を指定しておく.

$ bundle install --path=vendor/bundler --binstubs=vendor/bin

rakeの補完

rakeを実行することが多いので,rakeの補完も実行できるようにする.
ここでは都合上,先にrakeの補完関数を書いておく.
zshでのrakeの補完 - znzの日記 - Rubyistを参考に,以下の点を変更した.

  • rakeをbundle exec rakeに変更.
  • 「Generating .rake_tasks...」を出力しない.
  • 補完のグループ「rake」を定義するために.rake_tasksの文字をエスケープ.
_rake_refresh () {
  if [[ ! -f .rake_tasks ]]; then
    return 0;
  else
    return $([[ Rakefile -nt .rake_tasks ]])
  fi
}
_rake () {
  if [[ -f Rakefile ]]; then
    if _rake_refresh; then
      bundle exec rake --silent --tasks | cut -d " " -f 2 > .rake_tasks
      sed -i -e 's/:/\\\:/g' -e 's/\[/\\[/g' -e 's/\]/\\]/g' .rake_tasks
    fi
    _values "rake" $(<.rake_tasks)
  fi
}

bundle execの補完

beでbundle execを実行できるように関数を定義する.
(alias be='bundle exec'では補完されなかった.)

be () { bundle exec $* }

bundle execで実行されるファイルはvendor/bin以下にあるので,
lsで一覧を取得して補完候補にする.
補完の手順は以下の通り.

  1. be直後(CURRENT=2)の場合,vendor/bin以下の実行ファイルを補完する.
  2. 「be rake」の場合,_rakeを実行してrakeを補完する.
  3. 上記以外は通常のファイル名で補完を行う.
_be () {
  if [[ -d vendor/bin ]]; then
    _arguments '*: :->'
    if [[ $CURRENT == 2 ]]; then
      _values "bundle exec" `\ls -1 vendor/bin`
    elif [[ $CURRENT == 3 && $line[1] == "rake" ]]; then
      _rake
    else
      _files
    fi
  fi
}
compdef _be be

まとめ

f:id:hico_horiuchi:20131203181933p:plain
f:id:hico_horiuchi:20131203181942p:plain
思っていたよりも簡単に補完できるようになった.
bundle execを省略して,かつ補完できて満足.

ただ,初めての自作補完関数なのでスマートではないかも.
他にいい方法があれば教えて下さい.

.zshrcの本体はコチラ

ちなみに,クリスマスの予定はギッシリ埋まってます(白目).