I’ve been working on my first Ruby project, and in the process of trying to organize my files into different directories, I’ve run into trouble with having .rb files load non-ruby files (e.g. .txt files) local to themselves.
For example, suppose a project has the following structure:
myproject/
bin/
runner.rb
lib/
foo.rb
fooinfo.txt
test/
testfoo.rb
And the file contents are as follows:
runner.rb
require_relative '../lib/foo.rb'
foo.rb
File.open('./fooinfo.txt') do |file|
while line = file.gets
puts line
end
end
If I cd to lib and run foo.rb, it has no trouble finding fooinfo.txt in its own directory and printing its contents.
However, if I cd to bin and run runner.rb, I get
in `initialize': No such file or directory - ./fooinfo.txt (Errno::ENOENT)
I assume this is because File.open searches relative to whatever directory the top level program is run from.
Is there a way to ensure that foo.rb can find fooinfo.rb regardless of where it is run/required from (assuming that foo.rb and fooinfo.rb always maintain the same location relative to eachother)?
I’d like to be able to run foo.rb from bin/runner.rb, and a test file in test/, and have it be able to find fooinfo.txt in both cases.
Ideally, I’d like to have a solution that would work even if the entire myproject directory were moved.
Is there something like require_relative that can locate a non-ruby file?
In this case, the simplest thing is to just change
to
That will work from from any project subdirectory directly under your project root (including
lib/).The more robust solution, useful in larger projects, is to have a
PROJECT_ROOTconstant that you can use from anywhere. If you havelib/const.rb:Then (assuming you’ve
requireed that file) you can use: