2013-02-13 85 views
0

我是Ruby編程新手,但我想或多或少地得到一個符號的點(一個不可變的值,佔用更少的空間,排序等等)。這是什麼令我困擾 - 從Rake測試在Hartl的Ruby on Rails的教程:Ruby Rake中變量和符號之間的連接是什麼?

describe "something" do 
    let(:user) { FactoryGirl.create(:user) } 
    before { sign_in user } 
... 
end 

這對我來說很有意義調用FactoryGirl.create(:user) - 在這裏我們傳遞一種標誌(:user)來FactoryGirl告訴它做什麼樣的對象(或,更準確地說,要設置什麼變量,因爲它只創建用戶對象)。但在let(user),user是一個變量,而不是一個符號(或至少應該是)。我只能假設let方法偷偷地將符號:user替換爲同名變量 - 但是爲什麼? let(user)是不是一個更直觀的語法?我在這裏錯過了什麼?

此外,還有其他地方,這種模式發生在Ruby?到目前爲止,我只在耙測試中見過它。

+1

我不確定它有任何幫助,但快速查看源代碼(https://github.com/rspec/rspec-core/blob/v2.12.2/lib/rspec/core/let。rb#L31)表明'let'將定義一個給定名稱的方法,所以在我看來,給它一個符號是有意義的,所以這個方法被正確命名而不是變量 – pjam 2013-02-13 01:53:38

回答

0

一些小的修改/澄清:

  1. 這是一個 'rspec的' 測試,而不是一個分離多徑檢測。 Rake是一個自動化工具(類似'make'),但rspec是一個測試工具。
  2. FactoryGirl可以創建許多不同類型的對象。如果您定義了多個工廠,則傳遞給#create的符號將告訴它使用哪個工廠。它沒有告訴它在你的程序中設置了什麼變量。 let()調用定義了由所提供的符號的名稱給出的幫助方法,例如, :用戶。該方法返回由傳遞給它的塊確定的值,例如FactoryGirl將創建的用戶對象。

我已經掩蓋了let()的一些細節。真正的文檔是在這裏:

https://www.relishapp.com/rspec/rspec-core/v/2-6/docs/helper-methods/let-and-let

就我個人的經驗,這種特殊的模式是NC,但單元測試往往是與普通的代碼不同,因爲與他們的想法是鍛鍊代碼,而不是解決一個實際的問題。要做到這一點,你傾向於一次改變一件事物,以便重複使用 - 但紅寶石提供了許多工具來減少打字並保持可讀性。

編輯:請參閱註釋示例使用此模式。它正好在我的鼻子之下...... :)

+0

將一個名稱傳遞給一個方法使用該名稱生成另一種方法當然不是RSpec特有的模式。例如,在覈心庫中有'Module#attr_reader','Module#attr_writer'和'Module#attr_accessor'。和'Module#alias_method'。 – 2013-02-13 02:48:13

+0

好點!這些都是很好的例子。 – 2013-02-13 15:40:03

2

像Dave已經提到的那樣,提供的代碼不是rake任務,而是RSpec規範。

但讓我專注於這裏真正的問題。

如果您從未接觸過任何具有類似功能的其他語言,符號有點難以理解。有些語言稱之爲Atom。

http://en.wikipedia.org/wiki/Symbol_(programming)

想法behing一個符號是提供一種基本類型是力所能及可讀但在計算上廉價。

在Ruby中,當編譯器/解釋器看到一個符號時,它會創建一個符號類型的對象並將其存儲在內存中。在ruby中,符號是單例,因此任何其他使用同一個符號的對象都會返回完全相同的對象,這使得它在空間方面非常便宜,而且比較起來也很便宜,因爲您可以比較內存地址而不是內容。

例如,如果你比較兩個符號,就像這樣:

:foo == :foo 

你幾乎比較同一個對象,這意味着只有內存地址,需要進行比較。

現在,當你比較兩個字符串:

"foo" == "foo" 

它創建的字符串的兩個實例具有相同的內容,並且需要串的每個字節進行比較,以確保它們是相等的。

此屬性使符號對於標識符或哈希中的鍵非常有用。

現在,RSpec。

讓我們來看看下面的例子:

describe Authenticator do 
    let(:user) { Factory.create(:user)) 

    it "authenticate" do 
    auth_user = subject.authenticate(user.login, user.password) 
    auth_user.should == user 
    end 
end 

Factory.create需要一個符號作爲工廠使用的標識符。你需要自己定義工廠,所以真的只是一個名字。你可以使用字符串,但使用符號更便宜,最好練習,但說實話,除非你打電話給Factory.create數百萬次,否則它不會有太大的區別。

的讓利不是定義一個變量,它的實際定義,做了幾件事情的方法:

  1. 第一次調用該方法的規範(IT塊)內,將執行該塊,緩存結果並返回
  2. 同一規範內的任何其他調用(該塊)將僅返回緩存結果
  3. 規範完成後,它會刪除緩存的結果,以便在下一次重新評估打電話,關於下一個規格

只有在需要時才允許延遲創建對象,並允許限制對當前規範的任何狀態更改。

因此,底線是:RSpec將使用該符號作爲方法名稱的標識符,該方法名稱將被生成以抽象出某些事物,使您的生活更輕鬆。 RSpec只不過是一種使用元編程構建測試套件的BDD領域特定語言。

同樣的行爲可以用下面的測試條件下可實現:

class AuthenticatorTest < Test::Unit::TestCase 
    def user 
    return @user if @user 
    @user = Factory.create(:user) 
    end 

    def subject 
    return @subject if @subject 
    @subject = Authenticator.new 
    end 

    def teardown 
    @subject = nil 
    @user = nil 
    end 

    def test_authenticate 
    auth_user = subject.authenticate(user.login, user.password) 
    assert_equal auth_user, user 
    end 
end 

請注意,你可能不應該寫測試用例是這樣,但它(大概)說明的RSpec做什麼。

我希望有所幫助。

相關問題