On Tue, Apr 24, 2007 at 05:39:57PM +0900, Brian Candler wrote:
> I had rails_rcov working perfectly last week. Now when I try it again on the
> current iteration of the same project, it bombs out:

This turns out to be an extremely weird problem. Firstly I made the
following change to rails-1.2.3/lib/tasks/rails.rb

--- rails.rb.orig       2007-04-21 21:24:18.000000000 +0100
+++ rails.rb    2007-04-24 12:23:01.000000000 +0100
@@ -4,5 +4,10 @@
 Dir["#{File.dirname(__FILE__)}/*.rake"].each { |ext| load ext }

 # Load any custom rakefile extensions
+begin
 Dir["#{RAILS_ROOT}/lib/tasks/**/*.rake"].sort.each { |ext| load ext }
 Dir["#{RAILS_ROOT}/vendor/plugins/**/tasks/**/*.rake"].sort.each { |ext| load ext }
+rescue Exception => e
+STDERR.puts "XXX #{e.message}\n#{e.backtrace.join("\n")}"
+raise
+end

(ISTM that rake should not be hiding this exception when I give --trace)

This gives me the following error:

XXX undefined method `exclude' for nil:NilClass
/usr/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake/clean.rb:19
/usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
/home/candlerb/svn/dev/projects/deploy2/trunk/config/../vendor/plugins/rails_rcov/tasks/rails_rcov.rake:30
/usr/lib/ruby/gems/1.8/gems/rails-1.2.3/lib/tasks/rails.rb:9
/usr/lib/ruby/gems/1.8/gems/rails-1.2.3/lib/tasks/rails.rb:9
/usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
/home/candlerb/svn/dev/projects/deploy2/trunk/Rakefile:10
/usr/lib/ruby/1.8/rake.rb:1641:in `load_rakefile'
/usr/lib/ruby/1.8/rake.rb:1713:in `run'
/home/candlerb/svn/dev/projects/deploy2/trunk/vendor/plugins/rails_rcov/tasks/rails_rcov.rake:146
rake aborted!
undefined method `exclude' for nil:NilClass
/home/candlerb/svn/dev/projects/deploy2/trunk/Rakefile:10
(See full trace by running task with --trace)

Line 19 of rake/clean.rb is

CLEAN.clear_exclude.exclude { |fn|

So it looks like CLEAN.clear_exclude is returning nil.

This is where it gets interesting. I had gems for both rake-0.7.1 and
rake-0.7.3 installed. The code for clear_exclude in rake-0.7.3 is

    def clear_exclude
      @exclude_patterns = []
      @exclude_procs = []
      calculate_exclude_regexp if ! @pending
      self
    end

but in rake-0.7.1 it is

    def clear_exclude
      @exclude_patterns = []
      calculate_exclude_regexp if ! @pending
    end

and the latter clearly could return nil. I checked that nothing was
referring to rake version 0.7.1 explicitly, but just to be on the safe side
I uninstalled the rake-0.7.1 gem. However the problem remained.

Next I made the following changes to rake:

--- gems/rake-0.7.3/lib/rake.rb.orig    2007-04-24 12:47:03.000000000 +0100
+++ gems/rake-0.7.3/lib/rake.rb 2007-04-24 12:54:36.000000000 +0100
@@ -1084,10 +1084,12 @@

     # Clear all the exclude patterns so that we exclude nothing.
     def clear_exclude
+STDERR.puts "enter clear_exclude"
       @exclude_patterns = []
       @exclude_procs = []
       calculate_exclude_regexp if ! @pending
-      self
+STDERR.puts "exit clear_exclude"
+      return self
     end

     # Define equality.
--- gems/rake-0.7.3/lib/rake/clean.rb.orig      2007-04-24 12:49:15.000000000 +0100
+++ gems/rake-0.7.3/lib/rake/clean.rb   2007-04-24 12:57:38.000000000 +0100
@@ -16,9 +16,13 @@
 require 'rake'

 CLEAN = Rake::FileList["**/*~", "**/*.bak", "**/core"]
-CLEAN.clear_exclude.exclude { |fn|
+STDERR.puts "AAA CLEAN=#{CLEAN.inspect}"
+cce = CLEAN.clear_exclude
+STDERR.puts "cce = #{cce.inspect}"
+cce.exclude { |fn|
   fn.pathmap("%f") == 'core' && File.directory?(fn)
 }
+STDERR.puts "BBB"

 desc "Remove any temporary products."
 task :clean do

And here's the result:

$ rake test:units:rcov(in /home/candlerb/svn/dev/projects/deploy2/trunk)
AAA CLEAN=[]
enter clear_exclude
exit clear_exclude
cce = []
BBB
rm -rf ./coverage/units
/usr/bin/ruby1.8 "/home/candlerb/svn/dev/projects/deploy2/trunk/vendor/plugins/rails_rcov/tasks/rails_rcov.rake" --run-rake-task=test:units
(in /home/candlerb/svn/dev/projects/deploy2/trunk)
AAA CLEAN=[]
cce = /^$/
XXX undefined method `exclude' for /^$/:Regexp
/usr/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake/clean.rb:22
/usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
/home/candlerb/svn/dev/projects/deploy2/trunk/config/../vendor/plugins/rails_rcov/tasks/rails_rcov.rake:30
/usr/lib/ruby/gems/1.8/gems/rails-1.2.3/lib/tasks/rails.rb:9
/usr/lib/ruby/gems/1.8/gems/rails-1.2.3/lib/tasks/rails.rb:9
/usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
/home/candlerb/svn/dev/projects/deploy2/trunk/Rakefile:10
/usr/lib/ruby/1.8/rake.rb:1641:in `load_rakefile'
/usr/lib/ruby/1.8/rake.rb:1713:in `run'
/home/candlerb/svn/dev/projects/deploy2/trunk/vendor/plugins/rails_rcov/tasks/rails_rcov.rake:146
rake aborted!
undefined method `exclude' for /^$/:Regexp

This proves that the gem installation of rake-0.7.3 is being run, but it is
so weird that I cannot understand it at all. CLEAN.clear_exclude now appears
to be returning a regexp rather than nil. But look at the code - it can't
possibly be doing so!

So finally I undid all those changes and made just this one:

--- gems/rake-0.7.3/lib/rake/clean.rb.orig      2007-04-24 12:49:15.000000000 +0100
+++ gems/rake-0.7.3/lib/rake/clean.rb   2007-04-24 13:00:38.000000000 +0100
@@ -16,7 +16,8 @@
 require 'rake'

 CLEAN = Rake::FileList["**/*~", "**/*.bak", "**/core"]
-CLEAN.clear_exclude.exclude { |fn|
+CLEAN.clear_exclude
+CLEAN.exclude { |fn|
   fn.pathmap("%f") == 'core' && File.directory?(fn)
 }

and now everything works!

The only theory I have to work on is that rcov breaks the Ruby interpreter
in such a way that "return self" no longer works. However that's a very wild
theory, and I've not been able to replicate it in a small test case.

Can anyone else think of a mechanism which would cause it to behave this
way?

Environment is Ubuntu 6.06,

$ ruby -v
ruby 1.8.4 (2005-12-24) [i486-linux]

Regards,

Brian.