Ruby on Rails应用程序中load
和require
之间是否有任何重大差异?或者它们都具有相同的功能?
答案 0 :(得分:93)
require
在所有已定义的搜索路径中搜索库,并附加
.rb或.so到您输入的文件名。它还确保只有一个库
包括一次。因此,如果您的应用程序需要库A和B以及库B请求库A,那么A只会加载一次。
使用load
,您需要添加库的全名,并且每次都会加载它
调用load
- 即使它已经在内存中。
答案 1 :(得分:39)
Kernel#require
和Kernel#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置于“加载路径”上)。您可以将其视为需要“ rubygems”的额外功能。
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明确要求它。然后问题解决了。