script/console の履歴機能が上手く動かなくなった...ので対応

環境

現象

  • irb は通常通り~/.irb_history に履歴をためていく
  • rails のscript/console を起動すると、~/.irb_history の内容が上書きされ、先程までirb_history にあった最新の履歴が消えてしまう

script/console の実行中も、~/.irb_history をtail すると、どんどん履歴が書き込まれていっているのだけれど、何故かscript/console を終了して、再度起動したタイミングでやはり元の内容に戻ってしまう。~/.irb_history を空にしてもscript/console を実行すると中身が復活することから、どこからかコピーされている感じ。

原因

  • 未だソースとかを追っていない
  • もしかしたらrvm 関連の可能性もあるかも。rvm 使っていないときには何も発生しなかった
    • あくまで可能性です。原因を調べていないのでなんとも言えないです

対応

# http://github.com/gmarik/dotfiles/blob/84073cf564b601c99dc4b3b7910bd91234ff94f5/.ruby/lib/gmarik/irb-1.8-history-fix.rb
# http://stackoverflow.com/questions/2065923/irb-history-not-working
require 'irb/ext/save-history'
module IRB
  # use at_exit hook instead finalizer to save history
  # as finalizer is NOT guaranteed to run
  def HistorySavingAbility.extended(obj); 
    Kernel.at_exit{ HistorySavingAbility.create_finalizer.call }
    obj.load_history #TODO: super?
    obj
  end
end if IRB::HistorySavingAbility.respond_to?(:create_finalizer)

# http://rvm.beginrescueend.com/workflow/irbrc/
# for RVM
IRB.conf[:PROMPT_MODE] = :DEFAULT

# ヒストリーを有効にする
IRB.conf[:EVAL_HISTORY] = 1000 
IRB.conf[:SAVE_HISTORY] = 100 
HISTFILE = "~/.irb_history"
MAXHISTSIZE = 100
   
begin
  if defined? Readline::HISTORY
    histfile = File::expand_path( HISTFILE )
    if File::exists?( histfile )
      lines = IO::readlines( histfile ).collect {|line| line.chomp}
      puts "Read %d saved history commands from %s." %
        [ lines.nitems, histfile ] if $DEBUG || $VERBOSE
      Readline::HISTORY.push( *lines )
    else
      puts "History file '%s' was empty or non-existant." %
        histfile if $DEBUG || $VERBOSE
    end
    
    Kernel::at_exit {
      lines = Readline::HISTORY.to_a.reverse.uniq.reverse
      lines = lines[ -MAXHISTSIZE, MAXHISTSIZE ] if lines.nitems > MAXHISTSIZE
      $stderr.puts "Saving %d history lines to %s." %

      [ lines.length, histfile ] if $VERBOSE || $DEBUG
      File::open( histfile, File::WRONLY|File::CREAT|File::TRUNC ) {|ofh|
        lines.each {|line| ofh.puts line }
      }
    }
  end
end