I have created a gem on my local system for text mining which relies on
external Java libraries for classification tasks. I'm trying to harness
the power of Java through JRuby here. Directory structure is as follows:
- classifier/
* classifier.gemspec
* Gemfile
* Gemfile.lock
* lib/
* classifier/
* version.rb
* sample_classifier.rb
* classifier.rb
* java/
* sample_lib.jar
* another_sample_lib.jar
* yet_another_sample_lib.jar
* Rakefile
I'm loading these jars in lib/classifier.rb
as
Dir["java/*.jar"].each{|jar| require jar}
I have added this gem to a Git repository and referenced it in the
Gemfile of my Rails 3.0.9 project. However, my sample_classifier.rb
fails to locate any classes 'import'ed from any of the jars under
lib/java
.
Things work if I copy lib/java
to my Rails application
lib/ directory
and add the following in sample_classifier.rb
:
Dir["lib/java/*.jar"].each{|jar| require jar}
However, I don't think it's a good practice to spill the gem's
dependencies in my Rails app. Is there a better way to achieve this? I
looked around for bundling jar files with a gem but I found results for
exactly the opposite i.e. bundling gems within a jar file. Can I add
these jars to Rails' config.autoload_path or similar to load them when
the application starts? Is it a good practice to bundle jar dependencies
with the gem?
I'm sure there's a cleaner way to do this.
Might I suggest that managing your Jars with LockJar would be easier. Just install the gem
gem install lock_jar
Create a Jarfile
Create a Jarfile that contains a list of your Jar dependencies:
jar "com.tobedevoured:example1:0.0.1"
jar "com.tobedevoured:example2:0.0.2"
jar "com.tobedevoured:example3:0.0.3"
The simplest jar notation is groupId:artifactId:version. Other supported variations are groupId:artifactId:type:version and groupId:artifactId:type:classifier:version.
Generating a Jarfile.lock
The transitive dependencies are resolved, download, and generate to a Jarfile.lock with the command line:
lockjar lock
(You can also run it from Ruby as LockJar.lock)
Accessing your Jars
The Jarfile.lock contains all the Jar dependency information. Now you can load your jars from the Jarfile.lock to the classpath with:
LockJar.load
When packaging with a Gem, you will need to ensure the Jars from Jarfile.lock have been downloaded with:
LockJar.install
Make sure you request the Jarfile.lock is relative to the Gem's installed dir. Here is an example helper:
module Example
def self.installHelper
# get jarfile relative the gem dir from lib/example.rb
lockfile = File.expand_path( "../../Jarfile.lock", __FILE__ )
LockJar.install( :lockfile => lockfile )
end
def self.loadHelper
# get jarfile relative the gem dir from lib/example.rb
lockfile = File.expand_path( "../../Jarfile.lock", __FILE__ )
LockJar.load( :lockfile => lockfile )
end
end
You can also setup your Gem to download the Jar dependencies when the Gem installs, removing the need to call LockJar.install
.
Use absolute paths like so:
jars_dir = File.join(File.dirname(__FILE__), 'java')
for jar in Dir["#{jars_dir}/*.jar"]
require jar
end