How can i use gems-in-a-jar with embedded JRuby?
Asked Answered
M

1

6

I would like to use the excellent Sass as part of my build process. My build process is managed by Gradle. That means writing a plugin to run Sass. Sass is Ruby, and Gradle is in Groovy, but since Groovy runs on the JVM, i can use JRuby to run it, using the Java scripting API. Gradle scripts get dependencies in the form of jar files; i can get JRuby from Maven Central, but i will need to package Sass as a jar myself.

I've tried to follow Nick Sieger's gems-in-a-jar procedure for doing this, but have had no success. No matter what i do, i just can't get JRuby to pick up the Sass gem.

To isolate the problem, i have written a minimal Java (not Gradle) program which tries to use Sass via JRuby - i inventively call it JSass:

There are two or three interesting bits. The first is the script generate-gem-jar.sh, which builds the gem jar:

gem install -i build/gems sass --no-rdoc --no-ri
jar cf lib/gemsass.jar -C build/gems .

The second is the so.demo.JSass class, which runs JRuby:

ScriptEngine rubyEngine = new ScriptEngineManager().getEngineByName("jruby");
ScriptContext context = rubyEngine.getContext();
context.setAttribute("inputFile", inputFile, ScriptContext.ENGINE_SCOPE);
String script = IOUtils.toString(JSass.class.getResourceAsStream("sassdriver.rb"));
rubyEngine.eval(script, context);

The third is the Ruby script which the main class tries to use to operate Sass:

require 'sass'
template = File.load(inputFile)
sass_engine = Sass::Engine.new(template)
output = sass_engine.render
puts output

The program is able to load the JRuby engine and execute the script, but it fails at require 'sass', saying:

LoadError: no such file to load -- sass
  require at org/jruby/RubyKernel.java:1033
   (root) at <script>:1
org.jruby.embed.EvalFailedException: (LoadError) no such file to load -- sass
    at org.jruby.embed.internal.EmbedEvalUnitImpl.run(EmbedEvalUnitImpl.java:132)
    at org.jruby.embed.jsr223.JRubyEngine.eval(JRubyEngine.java:90)
    at so.demo.JSass.main(JSass.java:24)
Caused by: org.jruby.exceptions.RaiseException: (LoadError) no such file to load -- sass
Exception in thread "main" javax.script.ScriptException: org.jruby.exceptions.RaiseException: (LoadError) no such file to load -- sass
    at org.jruby.embed.jsr223.JRubyEngine.wrapException(JRubyEngine.java:115)
    at org.jruby.embed.jsr223.JRubyEngine.eval(JRubyEngine.java:93)
    at so.demo.JSass.main(JSass.java:24)
Caused by: org.jruby.exceptions.RaiseException: (LoadError) no such file to load -- sass

What am i doing wrong?

Missend answered 23/3, 2012 at 18:32 Comment(10)
Did you ever get this working with the answer from Kares or alternate solution?Traitorous
@nopuck4you: No. Kares's approach requires that (a) i launch the program with via the rgems runnable jar, which i can't, and (b) that the gem is an unpacked directory, which i really don't want. I haven't had time to really attack the problem myself since posting this question, sadly.Missend
I got sass working in my code using a similar approach. I ran into the exact same error that stumped me for 3 days. It turned out that the way I was repackaging the sass-lang.gem into a JAR was dropping the gem files so that JAR was invalid. I've got a working project for repackaging the gem to a JAR here: github.com/dmitrye/sass-gems. and here is an example of how I'm consuming it: github.com/dmitrye/wro4j/blob/1.4.x/wro4j-extensions/src/main/…. Let me know if this helps.Traitorous
@nopuck4you: You're a hero. I went through our two implementations with a fine-toothed comb, and it came down to one significant difference: you are using jruby-complete, and i was using jruby-core. The core version doesn't include gem support. Changing it to complete made my own SASS jar work fine (although my Ruby code was also broken, but that's another problem). If you want to write an answer recapitulating your comment and emphasising the point about the version of JRuby, i will happily accept it!Missend
I highly encourage you to publish a Gradle plugin out on github or something (if you can do so) and let Gradle know of its existence. A SaSS gradle plugin would be a great addition to their library, and something I was looking for today.Disequilibrium
You mean like github.com/youdevise/SassPlugin ? It's not quite ready for primetime yet, so i haven't publicised it. I hadn't thought of telling the Gradle guys about it, but i will do so. I'd really like to get an artefact into Maven Central too, or at least posted somewhere public, but that's going to take quite a bit more work.Missend
Glad to hear you already have some things committed. If you would like to get your artifacts (e.g. gem JAR) into Maven Central, you can check out the OSS initiative by Sonatype. I do believe it syncs with Maven Central automatically.Disequilibrium
Yes, i'm aware of that, and it looks like the easiest route available. What i'll have to do is get the project building inside my company, and publishing artefacts to our internal repository, then collect together all our open-source projects and set up a publishing process to push their artefacts somewhere separate to our proprietary code, then build a way to push artefacts from that into Sonatype OSS, then work out a sane versioning scheme for them (which we don't currently have!). That is mildly complicated, but it's what it will take to make it sustainable. So, don't hold your breath!Missend
I am not, take your time :) In the mean time I'm following what you have done here to get my stuff working. Thanks =)Disequilibrium
Do you know github.com/robfletcher/gradle-compass ?Oestradiol
S
2

seems to me that it will only work as long as it is executed as a java -jar -rgems.jar you can make this work, you do not need to package it up in a .jar just take the sass-x.x.x directory (result of gem install sass) and store it in a known place and add it's lib directory to the $LOAD_PATH ... since you've built the jar already I would assume it being in a current working directory :

rubyEngine.eval("$LOAD_PATH << 'file://gemsass.jar!/gems/sass-3.1.15/lib'", context);

this needs to happen prior to your last line rubyEngine.eval(script, context);

if it's not in the jar it should be the same just specify the path e.g.

rubyEngine.eval("$LOAD_PATH << 'file:/home/42/gems/sass-3.1.15/lib'", context);

please note that this will only work if sass gems does not depend on other gems !

Staurolite answered 23/3, 2012 at 20:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.