JRuby, Rake and RSpec not happily ever after?

Hi all,

I’m having a strange problem where running my spec task in Rake doesn’t
work
when I have to specify a specific classpath. Here’s my rake task
(assume
that the ENV[‘CLASSPATH’] variable is set appropriately):

task :spec do
opts = []
spec_files = FileList[File.join(Dir.getwd, “spec/spec_*.rb”)].to_a
opts.push *spec_files
#0: ruby “-Ilib/linkedin”, “-S”, “spec”, *opts
#1: system(jruby -J-cp #{ENV[‘CLASSPATH’]} -Ilib/linkedin -S rspec
–format d #{opts.join(’ ')})
#2: ruby %{-J-Xmx1024m -e “puts ‘hello’”}

#3: ruby “-J-cp #{ENV[‘CLASSPATH’]}”, “-Ilib/linkedin”, “-S”, “spec”,
*opts
#4: ruby “-cp #{ENV[‘CLASSPATH’]}”, “-Ilib/linkedin”, “-S”, “spec”,
*opts
#5: system(%{java -cp #{ENV[‘CLASSPATH’]} -jar
…/…/lib/jruby-complete-1.5.3.jar -Ilib/linkedin -S spec #{opts.join(’
')}})

end

I’ve commented out each attempt I’ve made to pass the classpath to the
spec
script. I originally assumed that by setting ENV[‘CLASSPATH’] the
classpath
would just be passed on to the environment making the spec call. That’s
what #0 tries to do. However that returns a ClassNotFound error because
it
can’t find my Java class dependencies. #2, #3, #4 are all differing
attempts to pass a Java option along, but instead I get an error saying
'jruby: unknown option: -J-#{variable}". #5 returns a ‘method_missing’
NameError upon attempting to load my Java class.

I’ve peaked inside the rake and jruby code and can’t seem to find what
exactly is going on here–is JRuby attempting to start a new thread in
the
same VM (which is why the java options aren’t being honored?) to run the
spec task but with a completely different class loader, which is why the
original environment classpath isn’t being honored? Or am I just a
moron
missing something completely obvious? (The latter happens pretty often,
so
don’t be afraid to call me on it).

System: JRuby 1.5.3, RSpec 1.3.0, Rake 0.8.7, Java 1.6 running on Fedora

Thanks,
Baq

On Mon, Nov 1, 2010 at 11:11 PM, Baq H. [email protected] wrote:

–format d #{opts.join(’ ')})
#2: ruby %{-J-Xmx1024m -e “puts ‘hello’”}

#3: ruby “-J-cp #{ENV[‘CLASSPATH’]}”, “-Ilib/linkedin”, “-S”, “spec”,
*opts
#4: ruby “-cp #{ENV[‘CLASSPATH’]}”, “-Ilib/linkedin”, “-S”, “spec”,
*opts

All of these (0-4) are going to run in process by default, so the -J
flags are not going to have any effect, nor will ENV[‘CLASSPATH’]. Try
adding elements to the $CLASSPATH array which will modify the current
process classpath.

#5: system(%{java -cp #{ENV[‘CLASSPATH’]} -jar
…/…/lib/jruby-complete-1.5.3.jar -Ilib/linkedin -S spec #{opts.join(’
')}})

Here you’re hitting the well-known issue that java ignores any
classpath argument or environment when using the “-jar” parameter.

/Nick

Thanks Nick, I appended my dependencies onto the global $CLASSPATH
variable
and that did the trick. And your explanation about -J flags makes
perfect
sense.

For anybody else that’s curious, I found this post by Charles Nutter
about
JRuby’s implementation of Kernel.system and Kernel.exec (see the ‘Avoid
spawning sub-rubies’ section) that explains how these calls typically
create
a new Ruby runtime within the same VM (I’m assuming with a completely
different class context/loader?).