负载与Ruby中的require有何不同?


Answers:


98

require在所有定义的搜索路径中搜索库,并在输入的文件名后附加.rb或.so。它还可以确保一个库仅包含一次。因此,如果您的应用程序需要库A和B,而库B又需要库A,则库A也只会被加载一次。

随着load您需要添加库的全名,它被载入每次通话时间load-即使它已经是在内存中。


谢谢您,先生,所以我们可以说.rb在加载中不是必需的。而且“ require”不会一直调用,如果它在内存中呢?
Arpit Vaishnav'7年

4
require跟踪已通过$LOADED_FEATURES$")全局数组加载的内容,该数组将load忽略。
Ciro Santilli郝海东冠状病六四事件法轮功

39

Kernel#require和之间的另一个区别Kernel#load是,它Kernel#load需要一个可选的第二个参数,该参数允许您将加载的代码包装到一个匿名的空模块中。

不幸的是,它不是很有用。首先,load通过访问全局名称空间,ed代码很容易从模块中脱颖而出,即,它们仍然可以猴子补丁如class ::String; def foo; end end。其次,load不返回将代码包装到其中的模块,因此,您基本上必须ObjectSpace::each_object(Module)手动将其删除。


很高兴知道!不知道Kernel#load有另一个说法
乔什·波达

不幸的是,它不是很有用。首先,load通过访问全局名称空间,ed代码很容易从模块中脱离出来,即,它们仍然可以猴子补丁如class ::String; def foo; end end。其次,load不返回将代码包装到其中的模块,因此,您基本上必须ObjectSpace::each_object(Module)手动将其删除。
约尔格W¯¯米塔格

4

我正在运行Rails应用程序,并且在Gemfile中,我创建了一个特定的自定义gem,并使用“ require:false”选项进行了创建。现在,当我加载Rails服务器或Rails控制台时,我能够在初始化程序中要求gem,并且gem也会被加载。但是,当我使用rspec和capybara运行规格功能测试时,出现加载错误。而且我完全困惑为什么在运行测试时在$ LOAD_PATH中找不到Gem。

因此,我回顾了加载,需求,红宝石和捆绑程序交互的所有不同方式。这些是我的发现的总结,有助于我发现特定问题的解决方案:

加载

1)您可以将其传递到ruby文件的绝对路径,它将执行该文件中的代码。

load('/Users/myuser/foo.rb')

2)您可以传递相对路径进行加载。如果与文件位于同一目录中,它将找到它:

> load('./foo.rb')
foo.rb loaded!
=> true

但是,如果您尝试使用load()从不同目录加载文件,它将不会找到基于当前工作目录(例如./)的相对路径的文件:

> load('./foo.rb')
LoadError: cannot load such file -- foo.rb

3)如上所示,load始终返回true(如果无法加载文件,则会引发 LoadError)。

4)全局变量,类,常量和方法均已导入,但局部变量未导入。

5)在同一文件上调用两次load将在该文件中执行两次代码。如果指定的文件定义了一个常数,它将两次定义该常数,这将产生警告。

6)$ LOAD_PATH是绝对路径的数组。如果仅将文件名传递给load,它将在$ LOAD_PATH中循环并在每个目录中搜索该文件。

> $LOAD_PATH.push("/Users/myuser")
> load('foo.rb')
foo.rb loaded!
 => true

要求

1)在同一文件上两次调用require只会执行一次。如果您使用相对路径引用一次,并且使用绝对路径引用一次,它也足够聪明,不会加载相同的文件两次。

2)如果文件已执行,则require返回true;否则,则返回false。

3)require跟踪全局变量$ LOADED_FEATURES中已经加载了哪些文件。

4)您不需要包括文件扩展名:

require 'foo'

5)require将查找foo.rb,还会查找动态库文件,例如foo.so,foo.o或foo.dll。这就是从ruby调用C代码的方法。

6)require不会检查当前目录,因为默认情况下当前目录不在$ LOAD_PATH中。

7)require_relative采用相对于当前文件的路径,而不是进程的工作目录。

红宝石

1)Rubygems是一个软件包管理器,旨在轻松管理称为gems的Ruby库的安装。

2)它的内容打包为一个zip文件,其中包含一堆可以由您的代码导入的ruby文件和/或动态库文件,以及一些元数据。

3)Rubygems用其自己的版本替换了默认的require方法。除了$ LOAD_PATH中的目录外,该版本还将浏览您已安装的gem。如果Rubygems在您的gems中找到文件,它将把该gem添加到$ LOAD_PATH中。

4)gem install命令会找出gem的所有依赖项并进行安装。实际上,它在安装gem本身之前先安装了gem的所有依赖项。

邦德勒

1)Bundler使您可以指定项目需要的所有gem,以及(可选)这些gem的版本。然后,bundle命令将安装所有这些gem及其依赖项。

2)在名为Gemfile的文件中指定所需的宝石。

3)bundle命令还会以列出的特定版本安装Gemfile.lock中列出的所有gem。

4)将bundle exec放在命令之前,例如bundle exec rspec,可确保require将加载您Gemfile.lock中指定的gem版本。

Rails和Bundler

1)在config / boot.rb中,要求运行“ bundler / setup”。Bundler确保Ruby可以找到Gemfile中的所有gem(及其所有依赖项)。require'bundler / setup'将自动发现您的Gemfile,并使Gemfile中的所有gem对Ruby可用(从技术上讲,它将gem置于“加载路径”上)。您可以将其视为需要“ ruby​​gems”的额外功能。

ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])

2)现在您的代码可用于Ruby,您可以需要所需的gem。例如,您可以要求使用“ sinatra”。如果您有很多依赖关系,则可能要说“需要我Gemfile中的所有gems”。为此,将以下代码紧随要求“ bundler / setup”放置:

Bundler.require(:default)

3)默认情况下,调用Bundler.require将需要Gemfile中的每个gem。如果Gemfile中的行显示gem'foo',:require => false,那么它将确保已安装foo,但不会调用require。如果要使用gem,则必须调用require('foo')。

因此,鉴于此知识的广度,我回到了测试的问题,意识到我必须明确要求rails_helper.rb中的gem,因为Bundler.setup将其添加到$ LOAD_PATH中,但要求:错误排除了Bundler.require明确要求它。然后问题解决了。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.