2016-07-31 38 views
0

这是我在编程几年中看到的最奇怪的错误。请忽略我使用下面的我使用开拓者的怪成语,为Rails编程框架:如预期变量在rspec测试中既不是零也不是零

下面的代码

let (:app) { App::Create.(app: {name: "Half-Life", steam_id: "70"}).model } 

it 'gets app details from Steam' do 
    VCR.use_cassette('app/get') do 
    p app.id 
    app_id = app.id 
    app = App::Get.(id: app_id).model 
    end 

    expect(app.app_type).to eq('game') 
end 

作品。

下面

let (:app) { App::Create.(app: {name: "Half-Life", steam_id: "70"}).model } 

it 'gets app details from Steam' do 
    VCR.use_cassette('app/get') do 
    p app.id 
    app = App::Get.(id: app.id).model 
    end 

    expect(app.app_type).to eq('game') 
end 

的代码抛出一个未定义的方法`ID”的零:NilClass在线路

app = App::Get.(id: app.id).model 

然而线

p app.id 

其是之前刚刚违规行显示正确的ID。

可能会发生什么?

回答

1

这条线:

let (:app) { App::Create.(app: {name: "Half-Life", steam_id: "70"}).model } 

创建一个名为app方法调用时,它返回一个App。 (它memoizes的结果,因此初始调用之后它总是返回相同的App

这条线:

app = App::Get.(id: app.id).model 

创建新的局部变量称为app是暧昧与方法app 。根据the Ruby docs on assignment

在Ruby中,局部变量名称和方法名称几乎相同。如果 你还没有分配到这些模棱两可的名字之一,那么ruby将假定你想调用一个方法,即 。一旦你分配了名字ruby 将假定你想引用一个局部变量。

当解析器遇到 分配,而不是当分配发生时创建的本地变量:

因此,在这一刻,当你试图给app,创建一个新的局部变量。当评估赋值的右侧时,app.id尝试在本地变量app(迄今为nil)上调用id

这是我能想到的,再现的问题最简单的代码:

def a 
    "Hello" 
end 

p a.upcase # "HELLO" 
a = a.upcase # undefined method `upcase' for nil:NilClass (NoMethodError) 

有几个方法可以解决你的代码。我认为最好的办法是迄今为止为:

app2 = App::Get.(id: app.id).model 

名称app已经使用的方法...不要通过创建具有相同名称的本地变量来隐藏它。

你也可以这样做:

app = App::Get.(id: app().id).model # the parens disambiguate 

或解决方案,您已经有了:

app_id = app.id # capture the ID before the local variable gets created 
app = App::Get.(id: app_id).model 

但我认为这两个是不是根本就没有创建摆在首位的命名冲突恶化。

+0

谢谢,这很有道理。 –

相关问题