本質的でないところではまった話

railsでスペックを書くのが楽しくなってきた頃、そろそろテストを自動化したいな、と思いまして、以前第25回 Ruby/Rails勉強会@関西, スはスペックのス〜RSpec(関西弁)の動画 - 角谷HTML化計画(2008-04-12)を見ていて、そういえばテストの自動化ツールあったよな、ということでZenTest(の中のautotest)を導入し、このへんこのへんを参照するなどしてAutotest::Screenを使った環境を整えました。
ところが、なぜかテストが失敗しても「All Green」の表示。どうもフックが正常に機能していない様子。これらの記事がかかれた当初は動いたのでしょうが、ZenTest3.10.0ではだめでした。
まあそこからあらゆるソースを追うこと3時間、出した結論(~/.autotest)がこちらです。

require 'autotest/screen'

Autotest::HOOKS.delete(:interrupt)
Autotest::Screen.statusline = "%-w%{=b bw}%n %t%{-}%+w %u %= %m/%d %D %c"

class Autotest::Screen
  SCREEN_COLOR[:green] = 'gw'
  SCREEN_COLOR[:yellow] = 'yk'

  Autotest.add_hook :run_command do |at|
    message 'Running' if execute?
  end

  Autotest::HOOKS[:ran_command] =
    [ lambda do |at|
        next unless execute?
        results = [at.results].flatten.join("\n")
        output = results.slice(/(\d+)\sexamples?,\s*(\d+)\s.*failures?(?:,\s*(\d+)\s.*pendings?)?/)
        if output
          ex,fail,pend = $~.captures.map {|e| e.to_i}
          if 0 < fail
            message "FAIL #{ex}ex, F:#{fail} ", :red
          elsif 0 < pend
            message "Pend #{ ex}ex, F:#{fail} P:#{pend}", :yellow
          else
            message "All Green #{ex}ex", :green
          end
        end
      end
    ]
end

要するにこのバージョンのautotestのフックのしくみ(pluginと呼ばれている)は、登録されているフックメソッドをEnumerable#any?を使って実行していくため、途中で真を返すと後から登録されたフックは無視されてしまうという仕様なので、後からAutotest.add_hookで登録しても、既に登録してあるオリジナルのフックメソッドに阻まれてしまうということのようです。仕方ないので、Autotest::HOOKS[:ran_command]に直接フックメソッドの配列を上書きしてしまったというわけです。
今日も莫大な時間をこのような本質的でないことに費やされましたが、こういうことを通じてこそrubyの基礎技術が着々と身につけられているので、仕方ないね。