ruby 1.9 の gem でのインストール時に test を行うとエラーが記録される。

はじめに

ruby 1.9 向けのアプリケーション(Google Code Archive - Long-term storage for Google Code Project Hosting.)を開発している。
そろそろリリースしようと思って、gem を作成してインストールを試した。インストールがうまくいったので、test もやってみようと思ったら、エラーが発生したので、原因を調査し、対応する。

ragdoll$ gem19trunk install --test pkg/s7-0.0.1.gem 
  (以下、実際の実行結果)
  Successfully installed s7-0.0.1
  1 gem installed
  Installing ri documentation for s7-0.0.1...
  Updating class cache with 1339 classes...
  Installing RDoc documentation for s7-0.0.1...
  :0:Warning: Gem::SourceIndex#search support for String patterns is deprecated
  Loaded suite /Users/kouji/local/bin/gem19trunk
  Started
  ................
  Finished in 0.328068 seconds.
  
  16 tests, 1353 assertions, 0 failures, 0 errors, 0 skips
  ERROR:  While executing gem ... (NoMethodError)
      undefined method `passed?' for #<MiniTest::Unit:0x17a6b78>

ragdoll$ gem19trunk install --debug --test pkg/s7-0.0.1.gem --no-ri --no-rdoc
  (以下、実際の実行結果)
  Exception `NoMethodError' at /Users/kouji/local/lib/ruby19trunk/1.9.1/rubygems/commands/install_command.rb:136 - undefined method `passed?' for #<MiniTest::Unit:0x77d1fc>
  ERROR:  While executing gem ... (NoMethodError)
      undefined method `passed?' for #<MiniTest::Unit:0x77d1fc>
          /Users/kouji/local/lib/ruby19trunk/1.9.1/rubygems/commands/install_command.rb:136:in `block in execute'
          /Users/kouji/local/lib/ruby19trunk/1.9.1/rubygems/commands/install_command.rb:133:in `each'
          /Users/kouji/local/lib/ruby19trunk/1.9.1/rubygems/commands/install_command.rb:133:in `execute'
          /Users/kouji/local/lib/ruby19trunk/1.9.1/rubygems/command.rb:136:in `invoke'
          /Users/kouji/local/lib/ruby19trunk/1.9.1/rubygems/command_manager.rb:105:in `process_args'
          /Users/kouji/local/lib/ruby19trunk/1.9.1/rubygems/command_manager.rb:75:in `run'
          /Users/kouji/local/lib/ruby19trunk/1.9.1/rubygems/gem_runner.rb:39:in `run'
          /Users/kouji/local/bin/gem19trunk:24:in `<main>'

原因の調査と対応

バックトレースから lib/rubygems/commands/install_command.rb の 136 行目付近で例外が発生していることが分かる。問題は以下の部分である。result は MiniTest::Unit のインスタンスである。MiniTest::Unit には passed? は存在しない。

        if result and not result.passed?

MiniTest::Unit#run の戻り値から、MiniTest::Unit の passed? としては以下がふさわしいと思う。

module MiniTest
  ...
  class Unit
    ...
    def passed?
      return (failures + errors) == 0
    end
    ...
  end
  ...
end

なお、この問題の対応方法として、RubyGems を修正し、MiniTest を修正しない方法もあるだろう。しかし、TestUnit で public だったメソッドは MiniTest に追加してもいいのではないかと考えた。
この問題の対象は、ruby 1.9.1-p0 と trunk の r21924。問題が修正されるまでは r21924 以降のリビジョンでも問題は発生する。

不具合の報告

これから Redmineruby-core ML に報告する。英語での報告は緊張する。
たぶん、以下の部分をうまく英語にできないだろう。Ryan が 「MiniTest は悪くない。RubyGems をなおせよ!!」って言ってきたらどうしよう。

なお、この問題の対応方法として、RubyGems を修正し、MiniTest を修正しない方法もあるだろう。しかし、TestUnit で public だったメソッドは MiniTest に追加してもいいのではないかと考えた。

まとめ

ruby 1.9.1-p0 と現在(r21924) の trunk において、gem のインストール時に test を行うと、以下のようなエラーメッセージを記録する。

ERROR: While executing gem ... (NoMethodError)
undefined method `passed?' for #

この問題は、以下のパッチで対応できる。

Index: unit.rb
===================================================================
--- unit.rb	(revision 21924)
+++ unit.rb	(working copy)
@@ -429,6 +429,10 @@
       [@test_count, @assertion_count]
     end
 
+    def passed?
+      return (failures + errors) == 0
+    end
+
     class TestCase
       attr_reader :name

早く対応されることを望む。