Why does Ruby 1.9.2 remove "." from LOAD_PATH, and what's the alternative?
Asked Answered
C

7

156

The latest changesets to Ruby 1.9.2 no longer make the current directory . part of your LOAD_PATH. I have a non-trivial number of Rakefiles that assume that . is part of the LOAD_PATH, so this broke them (they reported "no such file to load" for all require statements that based off the project path). Was there a particular justification for doing this?

As for a fix, adding $: << "." everywhere works, but seems incredibly hacky and I don't want to do that. What's the preferred way to make my Rakefiles 1.9.2+ compatible?

Caldwell answered 24/5, 2010 at 21:12 Comment(0)
T
143

It was deemed a "security" risk.

You can get around it by using absolute paths

File.expand_path(__FILE__) et al

or doing

require './filename' (ironically).

or by using

require_relative 'filename'

or adding an "include" directory

ruby -I . ...

or the same, using irb;

$irb -I .
Theressathereto answered 24/5, 2010 at 21:44 Comment(3)
I wound up using require_relative. Thanks.Caldwell
Is this akin to most unixes not including the current directory in the path for running executables?Schizo
require './filename' only works if your script is executed with the working directory set to the same directory that the script resides. This is often not the case in multi-directory projects.Osuna
Z
34

There's two reasons:

  • robustness and
  • security

Both are based on the same underlying principle: in general, you simply cannot know what the current directory is, when your code is run. Which means that, when you require a file and depend on it being in the current directory, you have no way of controlling whether that file will even be there, or whether it is the file that you actually expect to be there.

Zealot answered 25/5, 2010 at 7:17 Comment(7)
I don't think that enforcing that two files be in the same location relative to each other is necessarily a bad requirement. If that were true, then we would have no use for directories.Caldwell
@John Feminella: what does this have to do with putting files in paths relative to each other? The question is about putting them relative to ., i.e. the current working directory. If the user cd s into a different directory, the current working directory changes, and you now require completely different files depending on what directory the user happened to be in when he called your script. I don't think that's a good idea.Kindness
So to maintain a decent interface, you should do this? $: << File.dirname(__FILE__)Towle
@Joshua Cheek: Personally, I don't like that. (But please don't look at my older code, because it is littered with that kind of stuff :-) ). I simply pretend that the lib directory is on the $LOAD_PATH and then require all files relative to lib. In other words: I leave it to the administrator to figure out how to set up the $LOAD_PATH correctly. If you use RubyGems, that is trivial, because RubyGems automatically does it for you, and if you use Debian packages, then it's the package maintainer's job. All in all, it seems to work out quite nicely.Kindness
@Joshua Cheek: Also, as a sort-of counterbalance to removing . from $LOAD_PATH, Ruby 1.9.2 introduces require_relative which ... surprise ... require s a file relative to the location of the currently executing file (i.e. relative to File.dirname(__FILE__) ).Kindness
Hey there all. I was following this with some 'confusion' and I think I've made the right cognitive leap in understanding now. Either by accident or design, Ruby was behaving in a truly dynamic way; in that when there was a dynamically evoked require some other file with similar name would get loaded. Most of the time with say a *Nix command the load context would be relative to the script or executable (per require_relative). As far as I can tell though, isn't this only a problem when a Ruby program loads code dynamically?Cortez
Just to clarify: "current directory" is the directory the user is in, not the directory the require-ing file is in?Schizo
E
16

As others answers point out, it's a security risk because . in your load path refers to the present working directory Dir.pwd, not the directory of the current file being loaded. So whoever is executing your script can change this simply by cding to another directory. Not good!

I've been using full paths constructed from __FILE__ as an alternative.

require File.expand_path(File.join(File.dirname(__FILE__), 'filename'))

Unlike require_relative, this is backward compatible with Ruby 1.8.7.

Ear answered 18/3, 2011 at 6:50 Comment(1)
There's also this variation (which I personally find more readable): require Pathname.new(__FILE__).dirname + 'filename'Wiebmer
C
8

Use require_relative 'file_to_require'

Throw this in your code to make require_relative work in 1.8.7:

unless Kernel.respond_to?(:require_relative)
  module Kernel
    def require_relative(path)
      require File.join(File.dirname(caller.first), path.to_str)
    end
  end
end
Cupreous answered 25/1, 2013 at 13:50 Comment(0)
U
6

'.' in your path has long been considered a bad thing in the Unix world (see, for example, http://www.faqs.org/faqs/unix-faq/faq/part2/section-13.html). I assume the Ruby folks have been persuaded of the wisdom of not doing that.

Unlimber answered 25/5, 2010 at 7:32 Comment(0)
L
3

As Jörg W Mittag pointed out, I think what you want to be using is require_relative so the file you require is relative to the source file of the require declaration and not the current working dir.

Your dependencies should be relative to your rake build file.

Lenticel answered 1/2, 2011 at 11:15 Comment(0)
C
3

I found this to be a confounding change until I realized a couple of things.

You can set RUBYLIB in your .profile (Unix) and go on with life as you did before:

export RUBYLIB="."

But as mentioned above, it's long been considered unsafe to do so.

For the vast majority of cases you can avoid problems by simply calling your Ruby scripts with a prepended '.' e.g. ./scripts/server.

Cila answered 1/4, 2011 at 21:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.