2016-07-31 4 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 

который непосредственно перед тем, строка нарушения отображает правильный идентификатор.

Что может быть?

ответ

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 пытается вызвать id по локальной переменной app (которая до сих пор равна nil).

Вот простейший код, который я могу думать о том, что воспроизводит вопрос:

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

Спасибо, это имеет большой смысл. –

 Смежные вопросы

  • Нет связанных вопросов^_^