load 与 Ruby 中的 require 有何不同?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3170638/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does load differ from require in Ruby?
提问by Arpit Vaishnav
Is there any major difference between loadand requirein the Ruby on Rails applications? Or do they both have the same functionality?
Ruby on Rails 应用程序之间load和其中有什么主要区别require吗?或者它们都具有相同的功能?
回答by Nikolaus Gradwohl
requiresearches for the library in all the defined search paths and also appends
.rb or .so to the file name you enter. It also makes sure that a library is only
included once. So if your application requires library A and B and library B requries library A too A would be loaded only once.
require在所有定义的搜索路径中搜索库,并将 .rb 或 .so 附加到您输入的文件名。它还确保一个库只包含一次。因此,如果您的应用程序需要库 A 和 B,而库 B 也需要库 A,则 A 将仅加载一次。
With loadyou need to add the full name of the library and it gets loaded every time you
call load- even if it already is in memory.
随着load您需要添加库的全名,它被载入每次通话时间load-即使它已经是在内存中。
回答by J?rg W Mittag
Another difference between Kernel#requireand Kernel#loadis that Kernel#loadtakes an optional second argument that allows you to wrap the loaded code into an anonymous empty module.
Kernel#requireand之间的另一个区别Kernel#load是它Kernel#load采用可选的第二个参数,允许您将加载的代码包装到匿名的空模块中。
Unfortunately, it's not very useful. First, it's easy for the loaded code to break out of the module, by just accessing the global namespace, i.e. they still can monkeypatch something like class ::String; def foo; end end. And second, loaddoesn't return the module it wraps the code into, so you basically have to fish it out of ObjectSpace::each_object(Module)by hand.
不幸的是,它不是很有用。首先,loaded 代码很容易脱离模块,只需访问全局命名空间,即它们仍然可以对类似class ::String; def foo; end end. 其次,load不返回将代码包装到的模块,因此您基本上必须ObjectSpace::each_object(Module)手动将其取出。
回答by Donato
I was running a Rails application and in Gemfile, I had a specific custom gem I created with the option "require: false". Now when I loaded up rails server or rails console, I was able to require the gem in the initializer and the gem was loaded. However, when I ran a spec feature test with rspec and capybara, I got a load error. And I was completely bewildered why the Gem was not found in $LOAD_PATH when running a test.
我正在运行一个 Rails 应用程序,在 Gemfile 中,我创建了一个特定的自定义 gem,使用选项“require: false”。现在,当我加载 rails 服务器或 rails 控制台时,我能够在初始化程序中要求 gem 并加载 gem。但是,当我使用 rspec 和 capybara 运行规范功能测试时,出现加载错误。我完全不明白为什么在运行测试时在 $LOAD_PATH 中没有找到 Gem。
So I reviewed all the different ways that load, require, rubygems and bundler interact. And these are a summary of my findings that helped me discover the solution to my particular problem:
所以我回顾了加载、需要、rubygems 和打包器交互的所有不同方式。这些是我的发现的总结,这些发现帮助我找到了解决我的特定问题的方法:
load
加载
1) You can pass it an absolute path to a ruby file and it will execute the code in that file.
1) 您可以将绝对路径传递给 ruby 文件,它会执行该文件中的代码。
load('/Users/myuser/foo.rb')
2) You can pass a relative path to load. If you are in same directory as file, it will find it:
2)您可以传递一个相对路径来加载。如果您与文件在同一目录中,它将找到它:
> load('./foo.rb')
foo.rb loaded!
=> true
But if you try to load a file from different directory with load(), it will not find it with a relative path based on current working directory (e.g. ./):
但是,如果您尝试使用 load() 从不同目录加载文件,它将无法通过基于当前工作目录的相对路径(例如 ./)找到它:
> load('./foo.rb')
LoadError: cannot load such file -- foo.rb
3) As shown above, load always returns true (if the file could not be loaded it raises a LoadError).
3) 如上所示, load 始终返回 true (如果无法加载文件,则引发 a LoadError)。
4) Global variables, classes, constants and methods are all imported, but not local variables.
4) 全局变量、类、常量和方法都是导入的,但不是局部变量。
5) Calling load twice on the same file will execute the code in that file twice. If the specified file defines a constant, it will define that constant twice, which produces a warning.
5) 在同一个文件上调用 load 两次将执行该文件中的代码两次。如果指定的文件定义了一个常量,它将定义该常量两次,从而产生警告。
6) $LOAD_PATH is an array of absolute paths. If you pass load just a file name, it will loop through $LOAD_PATH and search for the file in each directory.
6) $LOAD_PATH 是一个绝对路径数组。如果您只传递 load 一个文件名,它将遍历 $LOAD_PATH 并在每个目录中搜索该文件。
> $LOAD_PATH.push("/Users/myuser")
> load('foo.rb')
foo.rb loaded!
=> true
require
要求
1) Calling require on the same file twice will only execute it once. It's also smart enough not to load the same file twice if you refer to it once with a relative path and once with an absolute path.
1) 对同一个文件调用 require 两次只会执行一次。如果您使用相对路径引用一次并使用绝对路径引用一次,那么它也足够聪明,不会加载同一个文件两次。
2) require returns true if the file was executed and false if it wasn't.
2) 如果文件被执行,则 require 返回真,否则返回假。
3) require keeps track of which files have been loaded already in the global variable $LOADED_FEATURES.
3) require 在全局变量 $LOADED_FEATURES 中跟踪已经加载了哪些文件。
4) You don't need to include the file extension:
4)您不需要包含文件扩展名:
require 'foo'
5) require will look for foo.rb, but also dynamic library files, like foo.so, foo.o, or foo.dll. This is how you can call C code from ruby.
5) require 将查找 foo.rb,但也会查找动态库文件,例如 foo.so、foo.o 或 foo.dll。这是从 ruby 调用 C 代码的方式。
6) require does not check the current directory, since the current directory is by default not in $LOAD_PATH.
6) require 不检查当前目录,因为当前目录默认不在 $LOAD_PATH 中。
7) require_relative takes a path relative to the current file, not the working directory of the process.
7) require_relative 采用相对于当前文件的路径,而不是进程的工作目录。
Rubygems
红宝石
1) Rubygems is a package manager designed to easily manage the installation of Ruby libraries called gems.
1) Rubygems 是一个包管理器,旨在轻松管理名为 gems 的 Ruby 库的安装。
2) It packages its content as a zip file containing a bunch of ruby files and/or dynamic library files that can be imported by your code, along with some metadata.
2) 它将其内容打包为一个 zip 文件,其中包含一堆可以由您的代码导入的 ruby 文件和/或动态库文件,以及一些元数据。
3) Rubygems replaces the default require method with its own version. That version will look through your installed gems in addition to the directories in $LOAD_PATH. If Rubygems finds the file in your gems, it will add that gem to your $LOAD_PATH.
3) Rubygems 用自己的版本替换了默认的 require 方法。除了 $LOAD_PATH 中的目录外,该版本还将查看您安装的 gem。如果 Rubygems 在您的 gems 中找到该文件,它将将该 gem 添加到您的 $LOAD_PATH。
4) The gem install command figures out all of the dependencies of a gem and installs them. In fact, it installs all of a gem's dependencies before it installs the gem itself.
4) gem install 命令找出gem 的所有依赖项并安装它们。事实上,它会在安装 gem 本身之前安装 gem 的所有依赖项。
Bundler
捆绑器
1) Bundler lets you specify all the gems your project needs, and optionally what versions of those gems. Then the bundle command installs all those gems and their dependencies.
1) Bundler 允许您指定项目需要的所有 gem,以及这些 gem 的可选版本。然后 bundle 命令安装所有这些 gem 及其依赖项。
2) You specify which gems you need in a file called Gemfile.
2)您在名为 Gemfile 的文件中指定您需要哪些 gem。
3) The bundle command also installs all the gems listed in Gemfile.lock at the specific versions listed.
3) bundle 命令还会在列出的特定版本中安装 Gemfile.lock 中列出的所有 gem。
4) Putting bundle exec before a command, e.g. bundle exec rspec, ensures that require will load the version of a gem specified in your Gemfile.lock.
4) 将 bundle exec 放在命令之前,例如 bundle exec rspec,确保 require 将加载您的 Gemfile.lock 中指定的 gem 版本。
Rails and Bundler
Rails 和 Bundler
1) In config/boot.rb, require 'bundler/setup' is run. Bundler makes sure that Ruby can find all of the gems in the Gemfile (and all of their dependencies). require 'bundler/setup' will automatically discover your Gemfile, and make all of the gems in your Gemfile available to Ruby (in technical terms, it puts the gems “on the load path”). You can think of it as an adding some extra powers to require 'rubygems'.
1) 在 config/boot.rb 中,运行 require 'bundler/setup'。Bundler 确保 Ruby 可以找到 Gemfile 中的所有 gem(以及它们的所有依赖项)。require 'bundler/setup' 将自动发现您的 Gemfile,并使您的 Gemfile 中的所有 gem 可供 Ruby 使用(用技术术语来说,它会将 gem 放在“加载路径”上)。您可以将其视为需要“rubygems”的添加一些额外功能。
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
2) Now that your code is available to Ruby, you can require the gems that you need. For instance, you can require 'sinatra'. If you have a lot of dependencies, you might want to say “require all of the gems in my Gemfile”. To do this, put the following code immediately following require 'bundler/setup':
2) 现在您的代码可用于 Ruby,您可以要求您需要的 gem。例如,您可以要求“sinatra”。如果您有很多依赖项,您可能想说“需要我的 Gemfile 中的所有 gem”。为此,请将以下代码紧跟在 require 'bundler/setup' 之后:
Bundler.require(:default)
3) By default, calling Bundler.require will require each gem in your Gemfile. If the line in the Gemfile says gem 'foo', :require => false then it will make sure foo is installed, but it won't call require. You'll have to call require('foo') if you want to use the gem.
3) 默认情况下,调用 Bundler.require 将需要 Gemfile 中的每个 gem。如果 Gemfile 中的行显示 gem 'foo', :require => false 那么它将确保 foo 已安装,但它不会调用 require。如果你想使用 gem,你必须调用 require('foo') 。
So given this breadth of knowledge, I returned to the issue of my test and realized I had to explicitly require the gem in rails_helper.rb, since Bundler.setup added it to $LOAD_PATH but require: false precluded Bundler.require from requiring it explicitly. And then the issue was resolved.
因此,鉴于知识的广度,我回到了我的测试问题上,并意识到我必须在 rails_helper.rb 中明确要求 gem,因为 Bundler.setup 将它添加到 $LOAD_PATH 但 require: false 排除了 Bundler.require 明确要求它. 然后问题就解决了。

