2017-03-08 117 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?')