Homebrew 中的大部分程式碼都是用動態語言 Ruby 編寫的。為了利用靜態類型檢查的優點,我們在程式碼庫中設定了 Sorbet,它為 Ruby 等動態語言提供靜態類型檢查的優點。
如果您想深入了解 Sorbet 及其功能,Sorbet 文件 是個不錯的起點。
sig
方法用於註解方法簽章。以下是一個簡單的範例
class MyClass
sig { params(name: String).returns(String) }
def my_method(name)
"Hello, #{name}!"
end
end
使用 params
,我們指定有一個參數 name
,它必須是 String
,並使用 returns
指定此方法總是傳回 String
。
有關如何表達更複雜類型的更多資訊,請參閱官方文件
.rbi
)RBI 檔案 可幫助 Sorbet 瞭解常數、祖先和方法,這些方法的定義方式是它原生無法理解的。我們也可以建立一個 RBI 檔案,以幫助 Sorbet 瞭解動態定義。
有時需要明確包含 Kernel
模組,才能讓 Sorbet 知道 puts
等方法在特定內容中可用。這對於模組來說尤其必要,因為它們可以用於 BasicObject
(不包含 Kernel
)和 Object
(預設包含 Kernel
)。在此情況下,有必要建立一個 .rbi
檔案(範例),因為在實際程式碼中重新包含 Kernel
模組可能會造成問題。
Library/Homebrew/sorbet
目錄目錄 rbi
包含所有 Ruby Interface (.rbi
) 檔案,這些檔案會透過執行 brew typecheck --update
自動產生
srb rbi hidden-definitions
產生的。srb rbi todo
產生的。檔案 config
是傳遞給 srb tc
的引數清單,以換行符號分隔,就像在命令列中傳遞引數一樣。config 檔案中的引數總是優先傳遞,其次才是命令列中提供的引數。我們使用它來忽略不希望進行類型檢查的 Gem 目錄。
程式碼庫中的每個 Ruby 檔案最上方都有神奇的註解 # typed: <level>
,其中 <level>
是 Sorbet 的嚴格性等級 之一,通常是 false
、true
或 strict
。檔案 false
只會報告與語法、常數解析和方法簽章正確性相關的錯誤,但不會報告類型錯誤。我們的長期目標是將所有 false
檔案移至 true
,並開始在這些檔案中報告類型錯誤。因此,當新增檔案時,理想上您應該將其標記為 # typed: true
,並找出任何產生的類型錯誤。
brew typecheck
在沒有任何引數的情況下執行 brew typecheck
時,它將考慮 Homebrew 核心程式碼庫中每個 Ruby 檔案中設定的嚴格性等級。但是,當它在特定檔案或目錄上執行時,可能會出現更多錯誤,因為 Sorbet 無法解析在指定檔案範圍之外定義的常數。這些問題可以用 RBI 檔案解決。目前 brew typecheck
提供 --quiet
、--file
、--dir
和 --ignore
選項,但您可以使用 srb tc --help
探索更多選項,並使用 srb tc
傳遞這些選項。
Sorbet 會回報型別錯誤以及錯誤參考代碼,可使用這些代碼在 Sorbet 文件 中尋找更多關於如何偵錯錯誤或錯誤原因的資訊。以下是偵錯一些常見型別錯誤的方法
使用 T.reveal_type
:在 true
或更高版本的檔案中,透過將變數或方法呼叫包覆在 T.reveal_type
中,Sorbet 會在 srb tc
的輸出中顯示它認為該變數的型別。在撰寫 方法簽章 和偵錯時,這特別有用。請務必在提交變更之前從程式碼中移除這行,因為這只是一個偵錯工具。
我們遇到的最常見錯誤之一是 7003:方法不存在。
由於 Ruby 是一種非常動態的語言,因此 Sorbet 無法靜態看到方法的定義方式。在這種情況下,請檢查方法是否存在於執行階段;如果不存在,表示 Sorbet 已經捕捉到未來的錯誤!但是,即使方法存在於執行階段,Sorbet 也可能看不到它。在這種情況下,我們使用 .rbi
檔案。
由於 Sorbet 沒有自動假設 Kernel 要包含在模組中,因此我們在嘗試使用 puts
、ohai
、odebug
等方法時可能會遇到許多錯誤。一個簡單的解決方法是在相應的 RBI 檔案中新增一行 include Kernel
。
以上提示非常通用,適用於許多情況。有關使用 Sorbet 時常見的陷阱,請參閱 Sorbet 錯誤參考 和 常見問題。