本節書摘來自華章出版社《effective ruby:改善ruby程式的48條建議》一書中的第1章,第1.5節,作者[美]彼得 j.瓊斯(peter j. jones),更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視
ruby程式員喜歡在書寫、執行以及測試代碼時使用短周期的回報模式。ruby中使用解釋執行的方式運作代碼,是以并不存在編譯階段。否則怎樣?假如你仔細想想,ruby一定會做些和編譯器所做的相同的事情,比如解析你的源代碼。當你的代碼交給解釋器時,它不得不做些編譯,比如執行代碼之前的一些任務。思考ruby執行代碼的兩個步驟是有幫助的:編譯階段和運作階段。
解析和了解代碼發生在編譯階段,執行代碼發生在運作階段。在你思考ruby産生的各類警告時,兩個階段的差别尤其重要。編譯階段産生的警告往往和要使ruby正常運作所需的文法問題有關。而運作時的警告則能指出粗糙的程式中可能潛藏的錯誤。留意運作時的警告可以幫助我們在錯誤的代碼變成真正的問題之前将其修複。在談論如何啟用ruby的各種警告之前,讓我們先探索一下常見的警告消息以及産生它們的原因。
特别需要留意編譯階段産生的警告。它們中的多數是由于ruby遇到含混不清的文法和多種可能的解釋時産生的。你顯然不想讓ruby猜到你真的想要做什麼。如果ruby的一個未來的版本改變了對模糊代碼的了解模式,想象一下會發生什麼呢?你的代碼會表現出完全不同的行為。既然如此,你完全可以留意這些類型的警告,做出必要的更改,進而在開始處就避免模糊的代碼。這裡有個例子,可以說明ruby遇到不清晰的代碼并産生警告:

當ruby解析器遇到第一處反斜杠時,它需要确定這是一個正規表達式文法的開始還是一個除号。在本例中,将其假設為正規表達式的開始是非常合理的,它應該作為split方法的第一個參數。不過也很容易看出,它可以被解釋為除号,split指令的輸出作為左操作數。警告本身很普通,并且隻有一半是有用的。但是修複這個問題足夠容易——使用括号:
假如你交給ruby代碼時啟用了警告選項,那麼你可能看到其他和操作數以及括号相關的警告。原因幾乎都是相同的:ruby不能完全肯定你的意圖并選擇最合理的解釋。不過再問一次,你真的希望ruby猜出你的意圖或者說在一開始你就完全清楚你的意圖嗎?下面兩個例子可以說明通過為參數增加括号來修複不清晰的方法調用。
其他在編譯階段有用的警告就和變量有關了。比如,如果你為變量指派卻沒有使用它,ruby就會警告你。這可能意味着你浪費了一些記憶體,但更可能意味着你在計算中忘了包含它的值。如果你在同一作用域建立了兩個命名相同的變量,你也會收到警告,這種警告被稱為變量隐藏(ariable shadowing)。當你定義一個塊變量時,而在同一作用域中已經定義了相同名字的變量,這種警告就會産生。這兩種變量警告都可以在下面的例子中看到:
如你所見,這些編譯階段的警告并非真意味着你做錯了什麼,但是有這種可能性。
是以最好的行動就是檢查這些警告并相應地對源代碼進行更改。對代碼執行或者說運作時産生的警告我會說同樣的話。這些警告僅會在代碼執行一些可疑操作之後被檢測到,比如,通路未初始化的執行個體變量或者重定義已存在的方法。這兩種情況都可能是故意或意外出現的。如其他警告一樣,這些都很容易修複。
我想你已經明白了,是以我不再枚舉更多的、描述性的、容易修複的運作時警告。作為替代,我想講講如何在開始就啟用這些警告。再說一次,差別編譯階段和運作階段的警告很有必要。如果你希望ruby在你的代碼被解析時産生警告,你需要確定啟用解析器警告标記。這非常容易,隻需要運作ruby時加上“-w”指令行選項。
但對有些應用程式并非如此簡單。也許你的ruby程式是通過web伺服器或背景運作的任務自動啟動的,或者更普遍,你希望使用rake這樣的工具在運作測試時啟動警告。當你不能通過使用指令行選項“-w”告訴解釋器你希望啟用警告選項時,你可以直接通過設定環境變量rubyopt來實作它。如何設定環境變量則取決于你的作業系統以及程式啟動方式。最重要的是,在你的應用程式運作環境中,設定環境變量rubyopt為“-w”這個事件必須發生在ruby啟動之前。
(我也得提一下,如果你正使用rake來運作測試,你還有一種方式來啟用警告選項。第36條包含了一個rakef?ile的例子,示範了這種方式。)
現在,還有最後一種方式來啟用警告。文檔很少提及,是以經常引起很多困惑。在你的程式中,你能夠檢視和操作全局變量$verbose(它的别名是$-w)。如果你想看到所有可能的警告消息,你應該将其設為true。将其值設為false會減少顯示的資訊(産生更少的警告),而設為nil則會禁用警告。你可能會想,“嘿,如果我把$verbose設定為true,那我就不需要浪費時間在‘-w’的事情上了。”這是編譯階段和運作階段的差別真正給我們的幫助。
假如你運作ruby解釋器時不加“-w”選項,而是使用變量$verbose,那你将看不到編譯時警告。因為全局變量$verbose隻到程式運作時才會被設定。那時,解析階段已經結束了,你當然就錯過了編譯階段的警告。是以,可以遵循以下兩條指導方針。其一,啟用編譯階段的警告可以通過在運作ruby解釋器時使用指令行選項“-w”,或通過設定環境變量rubyopt為“-w”。其二,控制運作時的警告可以使用全局變量$verbose。
我的建議是,在應用程式的開發階段始終啟用編譯時和運作時的警告。如果必須禁用運作時警告,那麼可以臨時将全局變量$verbose設定為nil。
很遺憾,啟用警告消息本身會觸發一個警告。讓人失望的還有,啟用警告這件事情并不是常見的做法。是以,如果你使用了rubygems并啟用了警告,可能會收到很多源于它們的警告。這将很可能導緻你禁用警告。還好,ruby列印警告到指令視窗時會包含警告相應的檔案名和行号,是以寫點腳本來過濾掉這些無關警告是很容易的。你甚至可以做得更好,以一個優秀的開源代碼貢獻者的身份,送出代碼去修複這種有點粗糙又存在警告的gems。
要點回顧
使用指令行選項“-w”來運作ruby解釋器以啟用編譯時和運作時的警告。設定環境變量rubyopt為“-w”也可以達到相同目的。
如果必須禁用運作時的警告,可以臨時将全局變量$verbose設定為nil。