Finding relative libraries when using symlinks to ruby executables
Asked Answered
B

3

5

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?

Bona answered 27/11, 2008 at 2:6 Comment(0)
R
12

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

require 'pathname'
APP_ROOT = File.join(File.dirname(Pathname.new(__FILE__).realpath),'..')
Resound answered 20/4, 2009 at 20:7 Comment(1)
That's definitely better, at least it's just two lines. Still unfortunate that there is not a single line solution.Bona
P
2

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__)
Pournaras answered 27/11, 2008 at 10:50 Comment(1)
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.Bona
M
1

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"
Mage answered 20/4, 2010 at 9:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.