2017-03-08 112 views
0

我正在使用一個小方法來檢查租戶是否啓用了功能。每個租戶都有一個TenantPlan存儲標誌。 Tenant模型上還有一些標誌可用於覆蓋特定於計劃的標誌。一個小功能檢測方法是這樣的租戶模型:ruby​​方法如何不能repond_方法,而是調用方法?

def has_feature?(feature, feature_default = false) 
    if tenant_plan 
    feature = "#{feature}_enabled?".to_sym 
    return tenant_plan.send(feature) || (respond_to?(feature) and send(feature)) 
    end 
    feature_default 
end 

我對這個問題最感興趣的部分是這樣的:

(respond_to?(feature) and send(feature)) 

我檢查,如果的一個領域Tenant模型中存在相同的名稱,如果存在,則會得到相同的名稱。

如果我使用控制檯來檢查了這一點:

[1] pry(main)> false and tenant.send(:free_courses_enabled?) 
=> false 

[2] pry(main)> true and tenant.send(:free_courses_enabled?) 
NoMethodError: undefined method `free_courses_enabled?' for #<Tenant:0x007f8f7171d6c8> 
from /Users/typeoneerror/.rvm/gems/[email protected]/gems/activemodel-4.2.7.1/lib/active_model/attribute_methods.rb:433:in `method_missing' 

我期望send到甚至沒有被調用,如果承租人沒有respond_to?的功能方法,它是什麼樣子的控制檯測試正在發生,但我在測試中發現,即使respond_to?返回false,發送也會被調用,但不會引發NoMethodError

expect(tenant).not_to receive(:free_courses_enabled?) 

結果:

expected no Exception, got #<RSpec::Mocks::MockExpectationError: (#<Tenant:0x007fdfd908a2a8>).free_courses_enabled?(no args) 
      expected: 0 times with any arguments 
      received: 1 time> with backtrace: 

有點歡快的,當我想到正好相反:

expect(tenant).to receive(:free_courses_enabled?).and_call_original 

我們得到

NoMethodError: 
    undefined method `free_courses_enabled?' for #<Tenant:0x007f8254bfedd8> 

我不知所措。

在這種情況下,由於表達式的第一部分返回false,在調用該方法時,ruby是否會吞下NoMethodError異常?希望得到解釋,並樂意聽取關於重寫的任何建議。

它在我看來像一個與ActiveModel的RSpec錯誤。當我不添加期望,並且在開發中運行代碼時,它會按預期行事。

+1

因此,在這一點上,我會仔細檢查所有小的基本假設......即使您知道它們應該保留。在您的控制檯中...你可以試試'tenant.respond_to?(:free_courses_enabled?)'也可以嘗試'tenant.respond_to?(「free_courses_enabled?」)'(你知道你可以使用一個字符串,你不需要to_sym吧?) 'has_feature?'方法我會嘗試* not * to_symming它...我也會嘗試不要重載變量名稱'feature'(萬一它是一些奇怪的範圍錯誤)例如:'feature_method =「#{feature} _enabled?''和'respond_to?(feature_method)&& send(feature_method)' –

+0

也嘗試'puts「我是否迴應方法:#{feature_method.inspect}?#{respond_to?(feature_method)}''檢查你'重新嘗試你認爲你正在嘗試,並得到你認爲你的迴應... –

+3

但終於...是的... ruby​​定義了「respond_to?」設置與方法集略有不同如果你嘗試向他們發送'',實際上不會發生爆炸......所以你有可能得到不同的結果(大多數情況下,如果你使用'method_missing'定義方法) –

回答

0

我想我是在將自己的腦袋跑進各種圖書館之後想到的。 Tenant沒有定義一個名爲payment_options_features?方法,所以當我去到控制檯,並做:

tenant.respond_to?(:payment_options_features?) # false 

不過,我相信我的期望租戶不應該接受的方法在我的RSpec測試...

expect(tenant).not_to receive(:payment_options_features?) 

實際上創建租戶對象上的功能的模擬,所以當測試運行:

tenant.respond_to?(:payment_options_features?) # true 

因爲它是「嘲弄」的。另一種方法是這樣做,因爲我們知道send是一種應該始終存在的方法。

expect(tenant).not_to receive(:send).with('payment_options_features?')