3

This SO post sort of answers the question by claiming that require will only search relative to the path that the script was run in. But this really does not appear to be true. I will elaborate.

I created a quick C extension and compiled it to mytest.so. Then, in the same directory I fired up irb.

irb(main):009:0> require 'mytest.so' LoadError: cannot load such file -- mytest.so 

This is expected because the claim in the other answer is that require is searching relative to where irb was run from. In my case that would be /usr/bin/irb. So I tried the required_relative solution from the other question:

irb(main):006:0> require_relative './mytest.so' LoadError: cannot infer basepath 

No luck. And FYI - mytest.so is tab-completing here so irb is clearly aware it is in the current working directory. Furthermore, I can easily prove this:

irb(main):004:0> system("pwd") /home/mike/Documents/ruby_test # => true irb(main):005:0> File.expand_path("./") # => "/home/mike/Documents/ruby_test" 

Okay final test, I will assume that irb is being executed in /usr/bin despite the evidence pointing against that.

irb(main):011:0> require '../../home/mike/Documents/ruby_test/mytest.so' LoadError: cannot load such file -- ../../home/mike/Documents/ruby_test/mytest.so 

I would greatly appreciate if anyone can shed some light on what is going on with require?

BTW, I am aware I can solve this issue by giving the exact file path. This question is about trying understand what is happening beneath the surface.

require '/home/mike/Documents/ruby_test/mytest.so' # this works 
3
  • I am speculating, but I am thinking that you got a close vote because of the statement and opinion that it is "so baffling" but if you remove that or change it to baffling you, as opposed to generally baffling, then it is no longer an opinion... :) Commented Jul 7, 2015 at 1:01
  • @vgoff thanks for the advice, i removed that part Commented Jul 7, 2015 at 2:39
  • I'm curious if require './mytest.so works? This usually works for me from irb. Commented Jul 7, 2015 at 2:52

2 Answers 2

3

tl;dr: IRB is special and has some odd rules. Ruby in general works just fine with relative paths.

require will search the load path (which you can see by inspecting $: or $LOAD_PATH). This will not include the directory that you launched IRB from:

> $: => ["/usr/local/rvm/rubies/jruby-head/lib/ruby/2.2/site_ruby", "/usr/local/rvm/rubies/jruby-head/lib/ruby/stdlib"] 

So there's no joy there, unless you explicitly add your directory to the load path. This is what Rubygems and Bundler spends most of their time doing - they manage the load paths for gems so you don't have to worry about it. However, this doesn't help you with single files.

Additionally, require_relative will search from the directory that __FILE__ is in, but in IRB, this is a non-directory (irb) value! This is why you get the "can't infer basepath" issue when trying require_relative from IRB; since the currently executing file, __FILE__, isn't a proper path, require_relative can't figure out where to start from.

When you are not running from IRB, this isn't really an issue; require_relative 'mytest.so' should work just fine when you execute it in a script, since the currently-executing script will populate __FILE__. That is, if you have loader.rb and mytest.so and execute loader via ruby loader.rb, require_relative should work just fine.

If you want to run this in IRB, consider something like:

require "#{__dir__}/mytest.so" 

which will expand out to the current working directory, which should by default be the directory you've launched it from. I would recommend that you not do this in a script, though, since it depends on __dir__ not having been changed, and that may be difficult to guarantee.

Sign up to request clarification or add additional context in comments.

Comments

0

From the documentation:

Loads the given name, returning true if successful and false if the feature is already loaded.

If the filename does not resolve to an absolute path, it will be searched for in the directories listed in $LOAD_PATH ($:).

If the filename has the extension “.rb”, it is loaded as a source file; if the extension is “.so”, “.o”, or “.dll”, or the default shared library extension 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 until found. If the file named cannot be found, a LoadError will be raised.

For Ruby extensions the filename given may use any shared library extension. For example, on Linux the socket extension is “socket.so” and require 'socket.dll' will load the socket extension.

The absolute path of the loaded file is added to $LOADED_FEATURES ($"). A file will not be loaded again if its path already appears in $". For example, require 'a'; require './a' will not load a.rb again.


The answer to your question is that it simply isn't designed to.

You could use require_relative if you want to require files relative to your files' path.

You could add your projects library folder to the $LOAD_PATH to get the functionality you are asking for, that is, require 'my_library'

In IRB for loading local files, you may want to use load instead, as it gives you the ability to load file/library multiple times, where require will load the file/library only once. The __FILE__ variable works in IRB just like it should. It is the identification of the file (in this case the open process) in which the variable is invoked.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.