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

时间:2010-07-03 07:08:14

标签: ruby-on-rails ruby

Ruby on Rails应用程序中loadrequire之间是否有任何重大差异?或者它们都具有相同的功能?

3 个答案:

答案 0 :(得分:93)

require在所有已定义的搜索路径中搜索库,并附加 .rb或.so到您输入的文件名。它还确保只有一个库 包括一次。因此,如果您的应用程序需要库A和B以及库B请求库A,那么A只会加载一次。

使用load,您需要添加库的全名,并且每次都会加载它 调用load - 即使它已经在内存中。

答案 1 :(得分:39)

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

不幸的是,它不是很有用。首先,load ed代码很容易通过访问全局命名空间来打破模块,即它们仍然可以像class ::String; def foo; end end那样进行单一操作。第二,load不返回它包装代码的模块,所以你基本上必须手工将其从ObjectSpace::each_object(Module)中删除。

答案 2 :(得分:1)

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

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

加载

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)如上所示,加载始终返回true(如果无法加载文件,则会引发LoadError)。

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

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

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采用相对于当前文件的路径,而不是进程的工作目录。

Rubygems

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版本。

铁路和捆绑商

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中,但要求:false排除了Bundler.require明确要求它。然后问题解决了。