Guilherme Luiz
Guilherme Luiz

Reputation: 127

How to make an object with a default value with it's not passed to the class?

I'm trying to make an object within the class Produto with a default value of "Geral" when there's no input for the variable categoria, but I'm having some trouble understanding what is wrong with this challenge, I've been searching for a more in depth class about object oriented but got no clues about what I should change for it to work, I'm really sorry if it's a dumb question.

categoria.rb

require 'produto'
class Categoria 
  attr_accessor :nome
  def initialize(nome: 'Geral')
    @nome = nome
  end
end
class Produto 
  attr_accessor :nome, :categoria, :preco, :estoque
  def initialize(nome: 'Sem nome', categoria: categoria , preco: '0', estoque: '0')
    @nome = nome
    @preco = preco
    @categoria = categoria
    @estoque = estoque
  end

  def adiciona_estoque(quantidade)
    @estoque += quantidade
  end

  def remove_estoque(quantidade)
    @estoque -= quantidade
  end
end
spec.rb

  it "deveria criar um objeto de categoria Geral por padrão" do
    nome = 'Teclado'
    preco = 100
    estoque = 3
    produto = Produto.new(nome: nome, preco: preco, estoque: estoque)

    expect(produto.nome).to eq 'Teclado'
    expect(produto.categoria.nome).to eq 'Geral'
    expect(produto.preco).to eq 100
    expect(produto.estoque).to eq 3
  end

rspec output


Produto deveria criar um objeto de categoria Geral por padrão
    Failure/Error: expect(produto.categoria.nome).to eq 'Geral'

    NoMethodError:
      undefined method `nome' for nil:NilClass
    # ./spec/1_produto_spec.rb:25:in `block (2 levels) in <top (required)>'


Upvotes: 2

Views: 792

Answers (2)

Jayson Virissimo
Jayson Virissimo

Reputation: 158

If you try to run the code verbatim in your class definition of Produto you'll notice the output

warning: circular argument reference - categoria

This is the first clue. Also, you'll notice that Categoria#nome is an instance method. That means you'll have to be dealing with an instance of that class to successfully make that method call.

Try modifying your Produto initializer parameters to make sure you are actually defaulting to giving it an instance of Categoria (instead of categoria which, unless you pass in a value, will be nil). For example:

class Categoria
  ...
  def initialize(nome: 'Sem nome', categoria: Categoria.new , preco: '0', estoque: '0')
    @nome = nome
    @preco = preco
    @categoria = categoria
    @estoque = estoque
  end
  ...
end

After making that change, you should see that (within your test block) produto.categoria.nome returns "Geral".

Upvotes: 1

Oleksandr Holubenko
Oleksandr Holubenko

Reputation: 4440

Short answer: You need to change

def initialize(nome: 'Sem nome', categoria: categoria , preco: '0', estoque: '0')
  @nome = nome
  @preco = preco
  @categoria = categoria
  @estoque = estoque
end

to

def initialize(nome: 'Sem nome', categoria: categoria , preco: '0', estoque: '0')
  @nome = nome
  @preco = preco
  @categoria = categoria || Categoria.new
  @estoque = estoque
end

Long answer: Problem that attr_accessor :categoria is the same as

def categoria
  @categoria
end

def categoria=(val)
  @categoria = val
end

it mean that when you not setting categoria in Produto.new it takes @categoria that is equal to nil.

Upvotes: 1

Related Questions