What is the difference between require_relative and require in Ruby?

后端 未结 7 1874
深忆病人
深忆病人 2020-11-22 10:15

What is the difference between require_relative and require in Ruby?

7条回答
  •  春和景丽
    2020-11-22 11:11

    require_relative is a convenient subset of require

    require_relative('path')
    

    equals:

    require(File.expand_path('path', File.dirname(__FILE__)))
    

    if __FILE__ is defined, or it raises LoadError otherwise.

    This implies that:

    • require_relative 'a' and require_relative './a' require relative to the current file (__FILE__).

      This is what you want to use when requiring inside your library, since you don't want the result to depend on the current directory of the caller.

    • eval('require_relative("a.rb")') raises LoadError because __FILE__ is not defined inside eval.

      This is why you can't use require_relative in RSpec tests, which get evaled.

    The following operations are only possible with require:

    • require './a.rb' requires relative to the current directory

    • require 'a.rb' uses the search path ($LOAD_PATH) to require. It does not find files relative to current directory or path.

      This is not possible with require_relative because the docs say that path search only happens when "the filename does not resolve to an absolute path" (i.e. starts with / or ./ or ../), which is always the case for File.expand_path.

    The following operation is possible with both, but you will want to use require as it is shorter and more efficient:

    • require '/a.rb' and require_relative '/a.rb' both require the absolute path.

    Reading the source

    When the docs are not clear, I recommend that you take a look at the sources (toggle source in the docs). In some cases, it helps to understand what is going on.

    require:

    VALUE rb_f_require(VALUE obj, VALUE fname) {
      return rb_require_safe(fname, rb_safe_level());
    }
    

    require_relative:

    VALUE rb_f_require_relative(VALUE obj, VALUE fname) {
        VALUE base = rb_current_realfilepath();
        if (NIL_P(base)) {
            rb_loaderror("cannot infer basepath");
        }
        base = rb_file_dirname(base);
        return rb_require_safe(rb_file_absolute_path(fname, base), rb_safe_level());
    }
    

    This allows us to conclude that

    require_relative('path')
    

    is the same as:

    require(File.expand_path('path', File.dirname(__FILE__)))
    

    because:

    rb_file_absolute_path   =~ File.expand_path
    rb_file_dirname1        =~ File.dirname
    rb_current_realfilepath =~ __FILE__
    

提交回复
热议问题