Undefined method '+' for nil: NilClass - Ruby error

1

I have the following Ruby codes in three different files. Follow them:

programa.rb

require_relative "product"
require_relative "store"

cd = Product.new("CD",20.5)
pinico = Product.new("Pinico",30.6)

store = [cd,pinico]
test = Store.new(store)
puts test

product.rb

class Product
  attr_accessor :name, :price

  def initialize(name,price)
    @name = name
    @price = price
  end

  def to_s
    "name: #{@name} - price: #{@price}"
  end
end

store.rb

class Store
  attr_accessor :product, :total

  def initialize(product)
    @product = product
  end

  total = 0
  def to_s
    product.each do |product|
      puts product.price
      total += product.price
    end
    "Soma total dos produtos: #{@total}"
  end
end

From the store.rb file, I would like to sum the total value of the products and return them to the program.rb file, where I build the class. When I run the same file on the terminal, it returns me the following error:

/home/cabox/workspace/test/store.rb:12:in 'block in to_s': undefined method '+' for nil:NilClass (NoMethodError)
        from /home/cabox/workspace/test/store.rb:10:in 'each'
        from /home/cabox/workspace/test/store.rb:10:in 'to_s'
        from programa.rb:9:in 'puts'
        from programa.rb:9:in 'puts'
        from programa.rb:9:in '<main>'

I'd like to know how to proceed to fix the error.

    
asked by anonymous 03.04.2018 / 14:15

1 answer

1

In your store.rb class, the total variable is set outside the def to_s method, so it is inaccessible to instance methods.

The correct code for it would be as follows:

class Store
  attr_accessor :products

  def initialize(products)
    @products = products
  end

  def to_s
    total = 0
    products.each do |product|
      total += product.price
    end

    "Soma total dos produtos: #{total}"
  end
end

Note that I

  • fix variable name @product to @products ,
  • I removed the instance variable @total and used a temporary variable within the scope of to_s
  • I removed the puts I had inside .each .
  • If you use Ruby > 2.4 want to further improve your code you can leave def to_s as follows:

    def to_s
      "Soma total dos produtos: #{@products.sum(&:price)}"
    end
    

    See the documentation for the Array # sum method. And the use of &:price is an abbreviation when the block is of type @products.sum { |product| product.price } .

    For versions < 2.4 You can use @products.map(&:price).reduce(&:+)

    Give a quick search on the internet about the scope of variables in Ruby ( found this one ), it helps a lot who is getting started and it is very simple. Good Luck:)

        
    03.04.2018 / 21:14