Tuesday, November 21, 2006

RubyGems: Absolute Paths

In a previous post about RubyGems I mentioned that I prefer to unpack gems locally to remove dependency issues. While this does provide a code sharing solution it also relies on the developers of the RubyGems to provide compatible solutions. Unfortunately, absolute paths seems to be something many RubyGem creators are overlooking.

I'm not picking on postgres-pr, but I will use it as an example. Below the current implementation of postgres.rb is shown.
require 'postgres.so'
rescue LoadError
require 'postgres-pr/postgres-compat'
The above implementation works when installed; however, when unpacked and uninstalled it raises the following error.
MissingSourceFile: no such file to load Â— postgres-pr/postgres-compat
To fix this issue you can manually change all the require statements to use absolute paths or you can add the directory where the gem is unpacked to the load path. I'm not a big fan of making changes to an unpacked gem since I will lose my changes when a new gem version comes out; therefore, adding another directory to the load path seems to be the lesser of two evils. Adding a directory to the load path in Ruby is easy enough.
$:.unshift [path]
But, I really don't think this should be necessary. Instead RubyGem developers should make the effort to use absolute paths.
require File.dirname(__FILE__) + [relative path]


  1. As a gem developer (SafariWatir) this is something I hadn't considered. Thanks for mentioning it.

  2. Jano Svitok12:03 PM

    require File.dirname(__FILE__) + [relative path]

    can cause the file to be required more times - the require checks by the exact phrase IIRC. Now imagine file1 contain: require File.dirname(..) + 'file2' and require File.dirname(..) + 'sub/file3'
    if sub/file3 contained require ... + '../file2'
    then file2 would be required twice.

    It's possible to fix it with wrapping everything with File.expand_path, but I'm not sure if it's worth it.

  3. Jay, I believe that if you make sure the directory containing your unpacked gem is on the load path, then you shouldn't have to use absolute file paths. Or am I missing something? -- Jim Weirich

  4. Anonymous10:25 AM

    I'm not sure exactly what you mean. For the standard rails project (where I unpack everything under vendor) would I add vendor to the load path? Using that assumption I tried this (which should be logically the same):

    focus:~/work/spikes jay$ gem unpack mocha
    Unpacked gem: 'mocha-0.3.2'

    focus:~/work/spikes jay$ ls -l
    total 0
    drwxr-xr-x 9 jay jay 306 Nov 23 10:12 mocha-0.3.2

    focus:~/work/spikes jay$ irb
    irb(main):001:0> $: << File.expand_path(".")
    => ["/opt/local/lib/ruby/site_ruby/1.8", "/opt/local/lib/ruby/site_ruby/1.8/i686-darwin8.6.1", "/opt/local/lib/ruby/site_ruby", "/opt/local/lib/ruby/vendor_ruby/1.8", "/opt/local/lib/ruby/vendor_ruby/1.8/i686-darwin8.6.1", "/opt/local/lib/ruby/vendor_ruby", "/opt/local/lib/ruby/1.8", "/opt/local/lib/ruby/1.8/i686-darwin8.6.1", ".", "/Users/jay/work/spikes"]
    irb(main):002:0> require 'mocha'
    LoadError: no such file to load -- mocha
    from (irb):2:in `require'
    from (irb):2

  5. csirac210:49 PM

    Nothing like leaving a comment on a post over a year old, but I believe Jim means something like this:

    $LOAD_PATH.push 'mocha-0.3.2/'
    require 'mocha'

