What is the best practice if I want to require
a relative file in Ruby and I want it to work in both 1.8.x and >=1.9.2?
I see a few options:
Ruby on Rails way:
config_path = File.expand_path("../config.yml", __FILE__)
One issue I've not seen pointed out with the solutions based on __FILE__ is that they break with regards to symlinks. For example say I have:
~/Projects/MyProject/foo.rb
~/Projects/MyProject/lib/someinclude.rb
The main script, the entry point, the application is foo.rb. This file is linked to ~/Scripts/foo which is in my $PATH. This require statement is broken when I execute 'foo':
require File.join(File.dirname(__FILE__), "lib/someinclude")
Because __FILE__ is ~/Scripts/foo so the require statement above looks for ~/Scripts/foo/lib/someinclude.rb which obviously doesn't exist. The solution is simple. If __FILE__ is a symbolic link it needs to be dereferenced. Pathname#realpath will help us with this situation:
require "pathname" require File.join(File.dirname(Pathname.new(__FILE__).realpath), "lib/someinclude")
Before I made the jump to 1.9.2 I used the following for relative requires:
require File.expand_path('../relative/path', __FILE__)
It's a bit weird the first time you see it, because it looks like there's an extra '..' at the start. The reason is that expand_path
will expand a path relative to the second argument, and the second argument will be interpreted as if it were a directory. __FILE__
obviously isn't a directory, but that doesn't matter since expand_path
doesn't care if the files exist or not, it will just apply some rules to expand things like ..
, .
and ~
. If you can get over the initial "waitaminute isn't there an extra ..
there?" I think that the line above works quite well.
Assuming that __FILE__
is /absolute/path/to/file.rb
, what happens is that expand_path
will construct the string /absolute/path/to/file.rb/../relative/path
, and then apply a rule that says that ..
should remove the path component before it (file.rb
in this case), returning /absolute/path/to/relative/path
.
Is this best practice? Depends on what you mean by that, but it seems like it's all over the Rails code base, so I'd say it's at least a common enough idiom.
I'm a fan of using the rbx-require-relative gem (source). It was originally written for Rubinius, but it also supports MRI 1.8.7 and does nothing in 1.9.2. Requiring a gem is simple, and I don't have to throw code snippets into my project.
Add it to your Gemfile:
gem "rbx-require-relative"
Then require 'require_relative'
before you require_relative
.
For example, one of my test files looks like this:
require 'rubygems'
require 'bundler/setup'
require 'minitest/autorun'
require 'require_relative'
require_relative '../lib/foo'
This is the cleanest solution out of any of these IMO, and the gem isn't as heavy as backports.
I would define my own relative_require
if it doesn't exist (i.e. under 1.8) and then use the same syntax everywhere.