2014/03/14

Recent entries from same category

  1. Ruby の Array#<< は Array#push よりも速いか
  2. Ruby の a = a + 1 はなぜ undefined method '+' for nil:NilClass なのか
  3. Re: Ruby 製バッチ処理を省メモリ化した
  4. Crystal と CRuby でHTTPサーバのベンチマーク
  5. pure mruby な JSON パーサ書いた。

ruby のアプリを動かす時にいちいち bundle exec って書くのがダルい。書きたくない。でもシステムに入ってたり違うバージョンの物が動いて変な動作をされても困る。
どうにかしてこのダルさを解消できないかと考えてみた。

まず rbenv を使ってるなら gem でインストールされるコマンドは必ずシェルのラッパとして生成され、そこから本物が起動する様になっている。例えば rails であれば以下の様なシェルになっている。
#!/usr/bin/env bash
set -e
[ -n "$RBENV_DEBUG" ] && set -x

program="${0##*/}"
if [ "$program" = "ruby" ]then
  for arg; do
    case "$arg" in
    -e* | -- ) break ;;
    */* )
      if [ -f "$arg" ]then
        export RBENV_DIR="${arg%/*}"
        break
      fi
      ;;
    esac
  done
fi

export RBENV_ROOT="/home/mattn/.rbenv"
exec "/home/mattn/.rbenv/libexec/rbenv" exec "$program" "$@"
おっと、運良く /usr/bin/env を使ってくれている。つまりはパスを書き換えれば rails とタイプしたコマンドを自前のコマンドに置き換えられるという事だ。
って事で direnv を入れよう。
direnv - unclutter your .profile

Usage Use direnv edit . to open an ".envrc" in your 1EDITOR. This script is going to be executed onc...

http://direnv.net/
$ go get github.com/zimbatm/direnv bash をインタラクティブシェルに使っているなら以下を .bashrc に追加する。
eval "$(direnv hook bash)"
これでこのディレクトリ特有のフックが実行出来る。次に rails や middleman 等を起動しているディレクトリに .envrc というファイルを作ろう。
中身はパスを書き換えるだけ。
export PATH=$PWD/.bin:$PATH
シェルを起動し直すか source ~/.bashrc した後でこのディレクトリに移動すると direnv: error .envrc is blocked. Run `direnv allow` to approve its content. と怒られる。すかさず $ direnv allow を実行しよう。さて、後は .bin というディレクトリを作り、その中に bash というファイルを作る。勘のいい方であればそろそろ気付いたはず。
#!/bin/bash

PATH=`echo $PATH sed 's/^[^:]*://g'` bundle exec "$@"
追加したパスを元に戻して bundle exec "$@" しています。
これでいちいち bundle exec middleman とかしなくても middleman とするだけで同じコマンドが実行出来る様になります。

さようなら、bundle exec、いい思い出をありがとう。

ちなみに shebang が bash じゃなくて perl な物を起動しようとしているなら同様に .bin/perl を書いてしまえば、carton exec にも対応出来るかもしれませんね。
(だらだら書いてますが bundle install --binstubs してそこにパス通すのでいいです)
Posted at by