引言
在Ruby中,當(dāng)我們想引用某些庫或者其它文件中定義的類和方法時候,會使用 require 或者require_relative,load,include
那么,它們兩個有什么區(qū)別? Ruby怎么知道要去哪里搜索,也就是,Ruby的require的默認(rèn)搜索路徑是什么?
require
require是Ruby中用的最多的,它通常用來導(dǎo)入系統(tǒng)庫,還有我們用gem安裝的三方庫.我們自己工程中的文件之間的相互引用,也是用的它.
require的用法
require 'commander/import'
require 'terminal-table'
require 'term/ansicolor'
require 'csv'
require 'cupertino'
Ruby會在ruby所對應(yīng)的gem庫的搜索路徑去尋找指定的文件,什么意思呢,就是說,如果你系統(tǒng)上有多個ruby,那么你用的哪個ruby來跑,那么其搜索使用的就是對應(yīng)版本的ruby的gem的搜索庫
ruquire的搜索路徑在全局變量 :,帶冒號的)中,
LOAD_PATH.
當(dāng)我們在ruby中,想使用另外一個ruby中的內(nèi)容,需要用require關(guān)鍵字來加載另外的ruby文件中的內(nèi)容 require會在預(yù)設(shè)的 LOAD_PATH)中去查找對應(yīng)的文件
例如,在我的電腦上,默認(rèn)的全局$:的路徑是
? testRuby ruby -e 'puts $:'
/Users/yohunl/.rvm/rubies/ruby-2.6.0/lib/ruby/gems/2.6.0/gems/did_you_mean-1.3.0/lib
/Users/yohunl/.rvm/rubies/ruby-2.6.0/lib/ruby/site_ruby/2.6.0
/Users/yohunl/.rvm/rubies/ruby-2.6.0/lib/ruby/site_ruby/2.6.0/x86_64-darwin18
/Users/yohunl/.rvm/rubies/ruby-2.6.0/lib/ruby/site_ruby
/Users/yohunl/.rvm/rubies/ruby-2.6.0/lib/ruby/vendor_ruby/2.6.0
/Users/yohunl/.rvm/rubies/ruby-2.6.0/lib/ruby/vendor_ruby/2.6.0/x86_64-darwin18
/Users/yohunl/.rvm/rubies/ruby-2.6.0/lib/ruby/vendor_ruby
/Users/yohunl/.rvm/rubies/ruby-2.6.0/lib/ruby/2.6.0
/Users/yohunl/.rvm/rubies/ruby-2.6.0/lib/ruby/2.6.0/x86_64-darwin18
可能你會覺得奇怪,上面輸出的路徑似乎并沒有包含我們使用gem install安裝的三方庫.我們用命令輸出下gem的安裝目錄
? gem env | grep -A2 'GEM PATHS'
- GEM PATHS:
- /Users/yohunl/.rvm/gems/ruby-2.6.0
- /Users/yohunl/.rvm/rubies/ruby-2.6.0/lib/ruby/gems/2.6.0
其實(shí)這是因?yàn)?用戶gem的安裝目錄,是在require執(zhí)行的時候,動態(tài)先添加到$:中去的.
我們可以打開irb來驗(yàn)證一下
old_load_path = $LOAD_PATH.dup
require 'cocoapods'
new_load_path = $LOAD_PATH.dup
從輸出的結(jié)果可以看出來,當(dāng)執(zhí)行了一個require后,$:的結(jié)果增加了很多,差不多增加了20個....
這也就驗(yàn)證了,在第一次執(zhí)行到require的時候,require內(nèi)部會先添加路徑.
目前,require已經(jīng)支持相對路徑了!!!!很多文章中說的不支持,已經(jīng)是過去式了.
例如 在我們目錄下下有兩個文件 a.rb 和b.rb
.
├── a.rb
└── b.rb
由于require的搜索路徑并沒有當(dāng)前目錄,所以直接 require "b"是不行的.
有以下幾種方式:
require "./b" #采用相對路徑
或者
$: << File.dirname(__FILE__)
require "b"
或者
$LOAD_PATH.push File.dirname(__FILE__)
require "b"
或者
$LOAD_PATH.unshift(File.dirname(__FILE__)) unless $LOAD_PATH.include?(File.dirname(__FILE__))
require "b"
或者
require File.dirname(__FILE__) + '/b.rb'
或者
require File.expand_path('../b.rb', __FILE__)
那么,如果我們想包含一個文件夾下有所的文件呢?
最好的方法是將目錄添加到加載路徑,然后require每個文件的基本名稱.當(dāng)然你也可以用如下的命令來加載文件夾下所有的文件
Dir["/path/to/directory/*.rb"].each {|file| require file }
另外,有人寫了一個簡單的require_all來實(shí)現(xiàn)這個功能,可以用
gem install require_all
來安裝它
require_relative
require_relative的調(diào)用是相對路徑。如當(dāng)前文件夾下存在一個名為foo.rb的文件時氧吐,調(diào)用的方式為require_relative 'foo'盏袄。它不能調(diào)用$LOAD_PATH中的包
load
load也是加載一個文件仪媒,它與require_relative的區(qū)別是:
require_relative多次加載同一文件時戚啥,只會加載一次祠斧;load每一次調(diào)用都會重加載該文件吞琐。
include
我們平時用的很少
Ruby Require VS Load VS Include VS Extend 有詳細(xì)的介紹,這里摘錄關(guān)鍵的部分
在一個模塊中,可能會有很多膠水代碼,也就是說類A中有一些函數(shù),和類B中一些函數(shù)的實(shí)現(xiàn)是 一模一樣的,這個時候,就可以把 那部分一樣的函數(shù)提取出來,寫在module中,然后在每個類用include這個module
就很簡便在這個類中插入了module中的這幾個方法了,避免了拷貝型的重復(fù)工作
module Log
def class_type
"This class is of type: #{self.class}"
end
end
class TestClass
include Log
end
tc = TestClass.new.class_type
puts tc #This class is of type: TestClass