有没有之间的主要差异load
,并require
在Ruby on Rails应用?还是它们具有相同的功能?
Answers:
require
在所有定义的搜索路径中搜索库,并在输入的文件名后附加.rb或.so。它还可以确保一个库仅包含一次。因此,如果您的应用程序需要库A和B,而库B又需要库A,则库A也只会被加载一次。
随着load
您需要添加库的全名,它被载入每次通话时间load
-即使它已经是在内存中。
require
跟踪已通过$LOADED_FEATURES
($"
)全局数组加载的内容,该数组将load
忽略。
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)
手动将其删除。
我正在运行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置于“加载路径”上)。您可以将其视为需要“ 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中,但要求:错误排除了Bundler.require明确要求它。然后问题解决了。
require
,load
或者autoload
在Ruby中使用?