views:

342

answers:

3

Imagine you have an executable foo.rb, with libraries bar.rb layed out in the following manner:

<root>/bin/foo.rb
<root>/lib/bar.rb

In the header of foo.rb you place the following require to bring in functionality in bar.rb:

require File.dirname(__FILE__)+"../lib/bar.rb"

This works fine so long as all calls to foo.rb are direct. If you put as say $HOME/project, and symlink foo.rb into $HOME/usr/bin, then __FILE__ resolves to $HOME/usr/bin/foo.rb, and is thus unable to locate bar.rb in relation to the dirname for foo.rb.

I realize that packaging systems such as rubygems fix this by creating a namespace to search for the library, and that it is also possible to adjust the load_path using $: to include $HOME/project/lib, but it seems as if a more simple solution should exist. Has anyone had experience with this problem and found a useful solution or recipe?

+2  A: 

You can use this function to follow any symlinks and return the full path of the real file:

def follow_link(file)
  file = File.expand_path(file)

  while File.symlink?(file)
    file = File.expand_path(File.readlink(file), File.dirname(file))
  end

  file
end

puts follow_link(__FILE__)
Phil Ross
I suppose that works. Not really a happy solution for something that is supposed to be the first require in the file. I'm not happy with a solution that include that snippet in every file in order to find our where it was called from.
dgtized
+3  A: 

I know this is ages old, but I just found this:

require 'pathname'
APP_ROOT = File.join(File.dirname(Pathname.new(__FILE__).realpath),'..')
Burke
That's definitely better, at least it's just two lines. Still unfortunate that there is not a single line solution.
dgtized
A: 

Probably worth mentioning that + works nicely with Pathname objects and also there is Kernel.Pathname method, so @Burke's original code could be made even shorter:

require 'pathname'
APP_ROOT = Pathname.new(__FILE__).realpath + "../../lib"
dolzenko