require、require_relative是什麼意思?差在哪?
雖然Ruby本身已經有非常多的功能,但還是常常在Ruby檔案中看到require 'something'
,例如要使用JSON.parse
就必須先require 'json'
,如果不require就無法使用這些功能。到底這些在檔案最開頭的玩意兒代表什麼意思呢?如果不require又會怎麼樣?
require最常見的意義
Ruby內建有許多library,在執行.rb
檔案時就已經包含在程式內,包括常用的File
、Date
等等三不五時就會出現的class,這些因為大家常用,就直接在開始執行.rb
程式時包含在Ruby內。但如果載入Ruby時就把所有libraries都放進去,啟動時間會太久,因此Ruby將許多比較沒那麼常用到的class抽出,需另外require。很常見的例子是require 'digest'
,是一個專門產生亂數、轉碼的工具:
Digest::SHA256.hexdigest("HelloWorld")
# => NameError: uninitialized constant Digest
require 'digest'
Digest::SHA256.hexdigest("HelloWorld")
#=> "872e4e50ce9990d8b041330c47c9ddd11bec6b503ae9386a99da8584e9bb12c4"
由於平常不一定會使用到digest
的功能,因此要使用必須要require,以節省資源。
使用require的理由
require
之所以會用來載入ruby的libraries,是基於兩個原因:
1. require
的預設載入路徑會讀取各式ruby gems及libraries,接著才是載入檔案
在官方文件中可以看到,require會預先搜尋$ LOAD_PATH
,這個東西是定義在Ruby的設定當中,在任何環境下輸入$ LOAD_PATH
就會看到目前的設定內容:
$ LOAD_PATH
#=> ["/Library/Ruby/Site/2.0.0",
# "/Library/Ruby/Site/2.0.0/x86_64-darwin13",
# "/Library/Ruby/Site/2.0.0/universal-darwin13",
# "/Library/Ruby/Site",
# ...(省略)]
以Mac OSX 10.9內建的Ruby為例,會從最上方開始搜尋到最下方,可以看出都是針對系統library進行搜尋。
2. require
在同一個環境下只會載入一次,如果出現第二次require
就不會載入。
若在同一個環境下require兩次相同的內容,則不會重複載入,節省資源。
require 'digest'
#=> true
require 'digest'
#=> false
使用require讀取檔案
只要在require
後方加上絕對路徑,require也可以用於讀取檔案,例如:
require File.expand_path("../another_file", __FILE__)
# 或
require "#{Rails.root}/app/models/another_file"
看似有點麻煩,但必須如此。因為如果只寫檔案名稱例如require 'another_file'
他並不會搜尋我目前的資料夾,也不會搜尋該檔案所處的資料夾。一定要用檔案的絕對路徑,才可以用require的方式來讀取其他檔案。
另外一種作法是加上"./"代表是相對於你目前執行檔案的資料夾。例如require './file'
也可以載入目前資料夾內的檔案。但這種作法有一個壞處,就是跟你執行檔案的地點會有關係,例如:
# ~/folder/file_1.rb
puts "success"
# ~/file_2.rb
require './folder/file_a'
看似完美的對比,假如我在使用者根目錄資料夾~/
底下執行$ ruby file_2.rb
會皆大歡喜的看到"success"訊息。但如果我移動到folder
資料夾內,從內部執行$ ruby ../file_2.rb
就會發生無法require的慘劇,因為在file2.rb當中是根據我目前的位置來進行require,會試圖在我所處的"folder"資料夾內搜尋"file1.rb"這個檔案,當然結果就是找不到。
讀取檔案別忘了require_relative
假如我們非常確定要require檔案的相對關係,那可以直接用乾淨漂亮的require_relative
來處理。就以剛剛的例子來說,可以寫成:
require_relative '../file_1.rb'
基本上require_relative
並不會搜尋library,也完全不建議這樣做,寫起來很醜。在這樣方便的方法之下,我個人都是用require
來讀取library和gem,而用require_relative
來讀取其他檔案,比較不容易搞混。