Ruby: require vs require_relative - best practice to workaround running in both Ruby <1.9.2 and >=1.9.2 Ruby: require vs require_relative - best practice to workaround running in both Ruby <1.9.2 and >=1.9.2 ruby ruby

Ruby: require vs require_relative - best practice to workaround running in both Ruby <1.9.2 and >=1.9.2


A workaround for this was just added to the 'aws' gem so thought I'd share as it was inspired by this post.

https://github.com/appoxy/aws/blob/master/lib/awsbase/require_relative.rb

unless Kernel.respond_to?(:require_relative)  module Kernel    def require_relative(path)      require File.join(File.dirname(caller[0]), path.to_str)    end  endend

This allows you to use require_relative as you would in ruby 1.9.2 in ruby 1.8 and 1.9.1.


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.


The Pickaxe has a snippet for this for 1.8. Here it is:

def require_relative(relative_feature)  c = caller.first  fail "Can't parse #{c}" unless c.rindex(/:\d+(:in `.*')?$/)  file = $`  if /\A\((.*)\)/ =~ file # eval, etc.    raise LoadError, "require_relative is called in #{$1}"  end  absolute = File.expand_path(relative_feature, File.dirname(file))  require absoluteend

It basically just uses what Theo answered, but so you can still use require_relative.