How is the default Ruby LOAD_PATH determined? - ruby

Assuming I compile my own fresh Ruby (MRI 1.9.3), what is the default LOAD_PATH, and how is that computed?

On my machine, the initial load path looks like this:
$ ruby -e 'puts $LOAD_PATH'
/Users/matt/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/site_ruby/1.9.1
/Users/matt/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/site_ruby/1.9.1/x86_64-darwin10.8.0
/Users/matt/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/site_ruby
/Users/matt/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/vendor_ruby/1.9.1
/Users/matt/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/vendor_ruby/1.9.1/x86_64-darwin10.8.0
/Users/matt/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/vendor_ruby
/Users/matt/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1
/Users/matt/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/x86_64-darwin10.8.0
Armed with grep, an investigation into the Ruby source leads to the definition of ruby_initial_load_paths[] in version.c (this is on Ruby 1.9.3). The first of these that apply (neither NO_INITIAL_LOAD_PATH or RUBY_SEARCH_PATH have been set) is RUBY_SITE_LIB2. Looking at the defines above that definition we see:
#define RUBY_SITE_LIB2 RUBY_SITE_LIB "/"RUBY_LIB_VERSION
and in turn:
#define RUBY_SITE_LIB RUBY_LIB_PREFIX"/site_ruby"
Following this chain of defines, it becomes clear that this corresponds to the first entry in my load path above. Similarly the other constants that go into this variable correspond to the other load path entries.
The ruby_initial_load_paths[] variable is used in ruby_init_loadpath_safe() in ruby.c, where the actual load path is set up for the process.
So the answer to your question is that the initial load path is set at compile time with some #defines, according to how the build has been configured.

Your compilation create a lib directory
on *nix based systems it is generally
/usr/lib/ruby/X.Y.Z
X.Y.Z represents version number of your ruby C api version.

Related

IRB require mongo fails cannot load such file -- mongo [duplicate]

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?
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 .
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.
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.
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
'.' 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.
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.
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.

What does it mean $: in Ruby

I was reading the following tutorial.
It talked about including files in a Ruby file like require :
require(string) => true or false
Ruby tries to load the library named string, returning true if
successful. If the filename does not resolve to an absolute path, it
will be searched for in the directories listed in $:. If the file has
the extension ".rb", it is loaded as a source file; if the extension
is ".so", ".o", or ".dll", or whatever the default shared library
extension is on the current platform, Ruby loads the shared library as
a Ruby extension. Otherwise, Ruby tries adding ".rb", ".so", and so on
to the name. The name of the loaded feature is added to the array in
$:.
I just want to know what is $: in Ruby and what does $: means.
The variable $: is one of the execution environment variables, which is an array of places to search for loaded files.
The initial value is the value of the arguments passed via the -I command-line option, followed by an installation-defined standard library location.
See Pre-defined variables, $LOAD_PATH is its alias.
Its the load path
Just open in irb terminal and type this $:
This is what you would get. Ofcourse that depends on the ruby ur using.
2.1.1 :009 > $:
=> ["/Users/mac/.rvm/rubies/ruby-2.1.1/lib/ruby/site_ruby/2.1.0", "/Users/mac/.rvm/rubies/ruby-2.1.1/lib/ruby/site_ruby/2.1.0/x86_64-darwin12.0", "/Users/mac/.rvm/rubies/ruby-2.1.1/lib/ruby/site_ruby", "/Users/mac/.rvm/rubies/ruby-2.1.1/lib/ruby/vendor_ruby/2.1.0", "/Users/mac/.rvm/rubies/ruby-2.1.1/lib/ruby/vendor_ruby/2.1.0/x86_64-darwin12.0", "/Users/mac/.rvm/rubies/ruby-2.1.1/lib/ruby/vendor_ruby", "/Users/mac/.rvm/rubies/ruby-2.1.1/lib/ruby/2.1.0", "/Users/mac/.rvm/rubies/ruby-2.1.1/lib/ruby/2.1.0/x86_64-darwin12.0"]
2.1.1 :010 >
In ruby $ refers to a predefined variable.
In this case, $: is short-hand for $LOAD_PATH. This is the list of directories you can require files from while giving a relative path. In other words, Ruby searches the directories listed in $:
Hope this helps.

Relative File Path in RSpec

I have a RSpec test for a class in /lib/classes which needs access to a zip file (no upload). The file is stored in /spec/fixtures/files/test.zip. How do I input the correct path so it's environment agnostic, i.e. without absolute path?
Rails.root will give you the app root, so
Rails.root.join "spec/fixtures/files/test.zip"
will give you the absolute path of your file, agnostic of the location of the app on your hard drive.
I've tackled this issue recently and here's what I came up with:
Define a constant in your spec_helper.rb (or equivalent) pointing to RSpec root:
RSPEC_ROOT = File.dirname __FILE__
Use this variable in your *_spec.rb (or equivalent) test files:
require 'spec_helper'
File.open("#{RSPEC_ROOT}/resources/example_data.json")
Why this solution?
It doesn't make use of the location of the test file which may be
subject to change (spec_helper is likely not)
It doesn't require any additions to test files other than the already existing
require 'spec_helper'
It doesn't depend on Rails (unlike Rails.root)
Here's a Gist: https://gist.github.com/thisismydesign/9dc142f89b82a07e413a45a5d2983b07
As far as I know (from looking every month or two) there is no better way that building something in spec_helper that uses the __FILE__ value to grab the path to a know bit of content, then build your own helpers on top of that.
You can obviously use a path relative to __FILE__ in the individual *_spec.rb file as well.

Ruby require 'file' doesn't work but require './file' does. Why?

I have a folder full of ruby files, and when I try and require one file in another that is in the same directory using require 'file' I get a LoadError but when I use require './file' everything works fine. Can somebody explain to me why this happens and if there is any way I can require a file without adding a ./ onto the file?
(Picture of directory):
If you want to require a file not from the system $LOAD_PATH but rather relative to the directory of the file you are requireing from, you should use require_relative. (Which, as you can see, isn't exactly extensively documented.)
You don't have current directory in your loadpath.
Check the contents of the $LOAD_PATH variable
Though it is very old post I think some extra information will be very useful to beginner.
The best way to think of require is in relation to the UNIX $PATH variable. Just by way of a refresher, the $PATH variable in UNIX is a list of directories where executables can be found. So when you type the name of a program on any UNIX terminal, your computer is looking through the executable files in the directories specified in your $PATH variable. require does something very similar. When, for example, you write require 'set' at the top of your Ruby file, you are telling Ruby to look through a bunch of directories for a library called set.rb (Ruby's set library).
So where does Ruby look for set.rb? Well, once again, Ruby has something very similar to UNIX's $PATH variable. It is the global variable $LOAD_PATH also sometimes known by it's ugly and undescriptive alias $: (which I don't suggest using by the way--short though it may be). It is an array of directory names where Ruby looks when it comes across a require.
There is nice informative post here where you can get more information about require, load and require_relative

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

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?
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 .
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.
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.
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
'.' 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.
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.
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.

Resources