天天看點

《Ruby程式員修煉之道》(第2版)—第1章1.3節Ruby擴充和程式設計庫

本節書摘來自異步社群《ruby程式員修煉之道》一書中的第1章,第1.3節ruby擴充和程式設計庫,作者【美】david a. black(戴維 a. 布萊克),更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

1.3 ruby擴充和程式設計庫

本節的要點并不是關于ruby标準庫的參考。曾在引言中解釋過,本書的目标不是編寫一本ruby語言的參考文檔,而是教會讀者使用ruby語言并掌握它,并最終拓寬視野。

相應地,本節的目标是講述擴充的工作方式,即如何使用ruby運作這些擴充、它們之間技術實作的不同,并最終能讓使用者自己編寫擴充和庫檔案的擴充架構。

随ruby釋出的擴充通常全部作為标準庫來引用。标準庫包括為不同項目和任務所提供的擴充,如資料庫管理、網絡、數學領域、xml處理等。标準庫精密的結構每次改變,哪怕隻有一點,也都要随着ruby新版本而釋出。使用最多、最廣泛的庫,已經證明了其存在的價值,是以通常都趨于穩定。

使用擴充和庫的關鍵是require方法,與之密切相關的是load方法。這些方法讓讀者可以在運作時加載擴充,包括自己編寫的擴充。我們将通過加載内置的擴充來學習它們并拓展我們的視野。

1.3.1 加載外部檔案和擴充

可以手動把程式存儲在單一檔案中,但如果有成百上千行或者成千上萬行的代碼,這将是一種負擔而不是優勢。盡管如此,可以将程式分解為能運作的不同檔案。在ruby中使用require和load方法将會使得這一過程變得容易。這裡先闡述load的使用,它是兩個方法中設計得最簡單的一個。

功能、擴充,還是庫?

使用者在運作時加載到程式中的程式代碼有許多不同的名稱。功能(feature)是最為抽象的,很少聽到過有人說“請求一個功能”(requiring a feature,這裡使用require)這樣特殊的使用方式。庫(library)是更為具體和通用的。它意味着存在一組真實的易于程式設計的代碼,并能夠被加載調用。擴充(extension)可以被任意可加載的附加庫所引用,但是在ruby中這通常意味着它們不是用ruby而是用c語言編寫而成的。如果要說正在編寫的是ruby擴充,就意味着已經假定那是用c語言編寫的。

要試一下這個例子,需要将程式分寫在兩個檔案中。第一個檔案,名為loaddemo.rb,應該包含如下代碼:

當它遇到load方法的調用時,ruby就會加載第二個檔案,這個檔案名為loadee.rb,包含如下代碼:

這兩個檔案應該放在同一個目錄下(假定存在示例代碼目錄)。在指令行中運作loaddemo.rb,可以看到如下輸出結果:

這個結果可以追溯到執行檔案的某一行,以及執行的順序。

為了在loaddemo.rb中加載名為loadee.rb的檔案,将它作為參數:

如果将要加載的檔案就在工作目錄中,ruby将能夠根據名稱找到它。如果不是,ruby将在加載路徑(load path)中查找它們。

1.3.2 加載位于預設加載路徑中的檔案

ruby解釋器的加載路徑是一系列目錄,請求加載時,ruby會在這些目錄中搜尋檔案。可以使用$:(美元符号及冒号)檢查加載目錄下的這些子目錄的名稱,看到的結果取決于使用者所使用的平台。在mac os x上,一個典型的加載目錄如下(這個示例包含了.rvm的路徑,它是ruby版本管理器所決定的ruby版本的路徑):

《Ruby程式員修煉之道》(第2版)—第1章1.3節Ruby擴充和程式設計庫

在你的電腦中,“ruby-2.1.0”左邊的部分可能會有所不同,如“/usr/local/lib/”,但是子目錄的基本模式都是一樣的。當加載一個檔案時,ruby将會自上而下地在每一個子目錄中搜尋。

**注意

目前的工作目錄,通常使用一個點(.)表示,這不會包含在加載目錄中。加載指令的作用如前面所介紹,這隻是一個特例。**

可以在load指令中使用代表上級目錄的雙點(..)符号導航到相對目錄:

注意,如果在程式運作中改變目前的目錄,相對目錄的引用也将會改變。

**注意:

記住load是一個方法,在程式檔案中,隻有ruby遇到它的時候才會執行。ruby不會搜尋整個檔案去執行load指令。也就是說,當ruby解釋器遇到它的時候,它才會去尋找它要加載的檔案。這意味着需要加載的檔案名可以在運作時動态地決定。甚至可以在條件語句中包含一個load指令的調用,讓它隻有在條件為true的時候才會被執行。**

同時也可以強制指定load搜尋一個完全限定的檔案路徑,而不管加載路徑的内容。

當然,這比起使用加載目錄或者相對路徑來說相容性會差一些,但是這可能會很有用處,尤其是如果擁有一個字元串變量,其中包含一段絕對路徑并想要加載它的時候。

load指令總是會加載所請求的檔案,不論這個檔案是否已經加載過。假如一個檔案在幾次加載過程中發生改變,那麼最新版本的檔案将優先使用并覆寫之前加載的版本。尤其是在irb會話中,當在編輯器中修改一個檔案時,想要立刻測試修改的效果,這将非常有用。

另一個加載檔案的方法是require,它同樣也搜尋預設的加載路徑中的目錄。但是require有一些load不具有的特點。

1.3.3 請求功能

load和require最大的不同在于,require就算調用多次也不會重新加載已經加載過的檔案。ruby會持續追蹤已經被請求的那些檔案而不會重複加載它們。

require比起load來說更為抽象。嚴格來說是不能請求一個檔案的,而隻能請求一個功能。一般來說,做到這一點甚至不用指定檔案的擴充名。為了驗證之前所述,将loaddemo.rb中的這一行進行修改,從

當運作loaddemo.rb時,即使提供了需要加載的檔案的完整檔案名,得到的結果也可能與之前相同。

通過把loadee看作一個“功能”而不是一個檔案,require對用ruby編寫的擴充和使用c語言寫成的擴充都用一樣的方式。另外,.rb擴充名的檔案與其他擴充名為.so、.dll或者.bundle的檔案使用方式也是一樣的。

指定工作目錄

require不能辨識出目前的工作目錄(.)。使用者可以顯式地指定它,例如:

或者可以使用數組添加運算符(<<),把目前目錄添加到加載路徑當中。

這樣,就不必在調用require的時候顯式地指定工作目錄了。

也可以給require指定完全限定的路徑,和使用load一樣,把檔案或者功能加載進來。讀者也可以混合使用該規則,例如,即使是将靜态路徑與路徑末端更為抽象的文法功能混合使用,以下文法也是可以正常運作的,例如:

盡管load很有用,尤其是當加載多于一個檔案的時候,但是require是一個日常使用的技術,用于請求ruby擴充和庫,不論是标準庫還是第三方庫。與加載loadee檔案相比,請求标準庫的功能要簡單得多,隻使用require就可以請求想要的任何庫檔案。之後,擴充中新的類和方法都可以使用了。下面的例子中,給出了請求前後在irb會話中的不同。

第一次調用scanf的時候失敗并報錯。但是在調用了require之後,沒有程式設計人員的介入,"david black"這個字元串對象也響應了scanf消息。(在這個例子中,使用空格為隐式分隔符,用于把原字元串抽取為兩個連續的字元串)

1.3.4 require_relative指令

require_relative是第三種加載檔案的方式。這個指令會搜尋相對于所在檔案的目錄來加載功能。是以在前一個例子中,可以這樣:

這樣就可以不用把目前目錄加入加載路徑中。當需要導航到某個本地目錄結構中的時候,require_relative是一個便捷的方式,例如:

接下來将對随ruby釋出的指令行工具進行一次測驗,以此總結這一章所學到的知識。

繼續閱讀