What is the difference between require_relative and require in Ruby?

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

What is the difference between require_relative and require in Ruby?

相关标签:
7条回答
  • 2020-11-22 10:50

    I want to add that when using Windows you can use require './1.rb' if the script is run local or from a mapped network drive but when run from an UNC \\servername\sharename\folder path you need to use require_relative './1.rb'.

    I don't mingle in the discussion which to use for other reasons.

    0 讨论(0)
  • 2020-11-22 10:54

    The top answers are correct, but deeply technical. For those newer to Ruby:

    • require_relative will most likely be used to bring in code from another file that you wrote.

    for example, what if you have data in ~/my-project/data.rb and you want to include that in ~/my-project/solution.rb? in solution.rb you would add require_relative 'data'.

    it is important to note these files do not need to be in the same directory. require_relative '../../folder1/folder2/data' is also valid.

    • require will most likely be used to bring in code from a library someone else wrote.

    for example, what if you want to use one of the helper functions provided in the active_support library? you'll need to install the gem with gem install activesupport and then in the file require 'active_support'.

    require 'active_support/all'
    "FooBar".underscore
    

    Said differently--

    • require_relative requires a file specifically pointed to relative to the file that calls it.

    • require requires a file included in the $LOAD_PATH.

    0 讨论(0)
  • 2020-11-22 10:59

    Summary

    Use require for installed gems

    Use require_relative for local files

    require uses your $LOAD_PATH to find the files.
    require_relative uses the current location of the file using the statement


    require

    Require relies on you having installed (e.g. gem install [package]) a package somewhere on your system for that functionality.

    When using require you can use the "./" format for a file in the current directory, e.g. require "./my_file" but that is not a common or recommended practice and you should use require_relative instead.

    require_relative

    This simply means include the file 'relative to the location of the file with the require_relative statement'. I generally recommend that files should be "within" the current directory tree as opposed to "up", e.g. don't use

    require_relative '../../../filename'
    

    (up 3 directory levels) within the file system because that tends to create unnecessary and brittle dependencies. However in some cases if you are already 'deep' within a directory tree then "up and down" another directory tree branch may be necessary. More simply perhaps, don't use require_relative for files outside of this repository (assuming you are using git which is largely a de-facto standard at this point, late 2018).

    Note that require_relative uses the current directory of the file with the require_relative statement (so not necessarily your current directory that you are using the command from). This keeps the require_relative path "stable" as it always be relative to the file requiring it in the same way.

    0 讨论(0)
  • 2020-11-22 11:04

    I just saw the RSpec's code has some comment on require_relative being O(1) constant and require being O(N) linear. So probably the difference is that require_relative is the preferred one than require.

    0 讨论(0)
  • 2020-11-22 11:10

    Just look at the docs:

    require_relative complements the builtin method require by allowing you to load a file that is relative to the file containing the require_relative statement.

    For example, if you have unit test classes in the "test" directory, and data for them under the test "test/data" directory, then you might use a line like this in a test case:

    require_relative "data/customer_data_1"
    
    0 讨论(0)
  • 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__
    
    0 讨论(0)
提交回复
热议问题