Ruby error: `calcular_valor_final': undefined method `*' - ruby

I am learning Ruby and when I try to create a function a problem happened.
I have 4 files: vendas.rb, pagamento.rb, frete.rb and init.rb
frete.rb
module Frete
TABELA_FRETE = {"BA": 1.95, "SP": 3.87, "PE": 2.59}
def imprimir_tabela_frete
puts "--- Tabela de Frete ---"
TABELA_FRETE.each do |k,v|
puts "#{k} - #{v}"
end
puts "-------------------------"
end
def calcular_valor_final(valor_produto, uf)
puts TABELA_FRETE[uf]
valor_produto * TABELA_FRETE[uf]
end
end
pagamento.rb
module Pagamento
SIMBOLO_MOEDA = "R$"
def pagar(valor_final)
puts "Deseja pagar com cartão? (S/N)"
opcao = gets.chomp.upcase
if opcao == "S"
puts "Pagando com cartão..."
else
puts "Pagando com dinhero..."
end
end
class Pagseguro
def initializer
puts "Usando Pagseguro..."
end
end
end
venda.rb
require_relative "frete.rb"
require_relative "pagamento"
class Venda
include Pagamento
include Frete
PRODUTOS = {"PS3": 900.00, "PS4": 1600.00}
def imprimir_produtos
puts "--- Produtos ---"
PRODUTOS.each do |k,v|
puts "#{k} - #{Pagamento::SIMBOLO_MOEDA} #{v}"
end
puts "--------------------"
end
def vender
puts "Olá! Seja Bem-vindo!"
puts "O que deseja comprar? "
imprimir_produtos
puts "> Digite o nome do produto... "
produto = gets.chomp.upcase
puts "> Para onde deseja enviar?"
imprimir_tabela_frete
puts "> Digite o estado... "
uf = gets.chomp.upcase
puts "Calculando... "
valor_final = calcular_valor_final(PRODUTOS[produto], uf)
puts "Você deve pagar #{Pagamento::SIMBOLO_MOEDA} #{valor_final} do produto + frete."
puts "Deseja pagar? (S/N)"
opcao = gets.chomp.upcase
if opcao == "S"
pagseguro = Pagamento::Pagseguro.new
pagar(valor_final)
else
puts "Ok! Fica para a próxima! :("
end
end
end
init.rb
require_relative "venda"
v = Venda.new
v.vender
When I run init.rb my code should get the function "calcular_valor_final" and multiply "product" by the "freight value"
def calcular_valor_final(valor_produto, uf)
valor_produto * TABELA_FRETE[uf]
end
However, the error below is showned:
Traceback (most recent call last):
2: from init.rb:4:in `<main>'
1: from /mnt/d/Credere/Treinamento_Ruby/aula19/venda.rb:37:in `vender'
/mnt/d/Credere/Treinamento_Ruby/aula19/frete.rb:15:in `calcular_valor_final': undefined method `*' for nil:NilClass (NoMethodError)
I can't find on the web some errors like this!
Someone may help me to show me why this error occurs, please?

The error:
undefined method `*' for nil:NilClass
means that the object you're trying to call the * method on is nil, and therefore it's not possible, because no such method exists for NilClass. (You can multiply a number by something, but it makes no sense to "multiply nil by something"!)
In other words, in your scenario, it means that valor_produto == nil.
Which means that PRODUTOS[produto] must be nil.
And this is happening because you've defined PRODUCTOS like this:
PRODUTOS = {"PS3": 900.00, "PS4": 1600.00}
Which is equivalent to defining it like this:
PRODUTOS = {:PS3 => 900.00, :PS4 => 1600.00}
...where the hash keys are Symbols, not Strings.
In ruby, a Symbol and a String are different objects:
"this" != :this
...Because "this" is a String, and :this is a Symbol.
tl;dr: What you intended to do was either define the constant like this instead:
PRODUTOS = {"PS3" => 900.00, "PS4" => 1600.00}
Or, alternatively, convert the user input into a Symbol:
produto = gets.chomp.upcase.to_sym

Related

What is the correct way to call a class instance inside another class's method?

I am trying to make a simple library app, and I am trying to implement a method where a person gets to borrow a book. I have so far 2 classes one for the said person and the other is for books/documents.
The person(adherant) class (which includes a test case):
require_relative 'document'
class Adherant
attr_reader :id,:nom, :prenom,:emprunt
def initialize(id,nom, prenom)
#id=id
#nom = nom
#prenom = prenom
end
def emprunt
#emprunt =0
end
def to_s
"Adherant N°: #{#id}- #{#nom} #{#prenom}"
end
def emprunter(other)
if other.empruntable==true && #emprunt <5
puts "Vous avez emprunter: #{other.titre}"
other.empruntable==false #there was a trailing `=` causing problems too
#emprunt+=1
else
puts "#{#emprunt.inspect} #{other.empruntable.inspect}"
puts "#{other.titre} est deja emprunter!"
end
end
end
livr= Document.new("Harry Potter And The Goblet Of Fire",12345,"J.K Rowling","livre")
test = Adherant.new(123,"Doe","John")
test.emprunter(livr)
The document class:
class Document
attr_accessor :titre, :isbn, :auteur,:type,:empruntable
def initialize(titre, isbn, auteur,type)
#titre = titre
#isbn = isbn
#auteur = auteur
#type = type
end
def self.empruntable
#empruntable = true
end
def to_s
"#{#type.capitalize}:#{#titre.capitalize}- #{#auteur.capitalize} #ISBN: #{#isbn.to_s.capitalize}"
end
end
The output:
nil nil
Harry Potter And The Goblet Of Fire est deja emprunter!
I don't understand why the adherant #emprunt and document #empruntable have nil values whilst I made sure to give them a value.
After a few tests and looking the problem up, I found a way to make it work.
I used flexible initialization, by giving the #emprunt and #empruntable attributes a default value in the initialize method.
The person(adherant) class (which includes a test case):
require_relative 'document'
class Adherant
attr_reader :id,:nom, :prenom,:emprunt
def initialize(id,nom, prenom, emprunt=0)
#id=id
#nom = nom
#prenom = prenom
#emprunt = emprunt
end
#def emprunt
# #emprunt =0
#end
def to_s
"Adherant N°: #{#id}- #{#nom} #{#prenom}"
end
def emprunter(other)
if other.empruntable==true && #emprunt <5
puts "Vous avez emprunter: #{other.titre}"
other.empruntable=false
#emprunt+=1
else
puts "#{other.titre} est deja emprunter!"
end
end
end
livr= Document.new("Harry Potter And The Goblet Of Fire",12345,"J.K Rowling","livre")
puts livr.empruntable
test = Adherant.new(123,"Doe","John")
test.emprunter(livr)
puts livr.empruntable
The document class:
class Document
attr_accessor :titre, :isbn, :auteur,:type,:empruntable
def initialize(titre, isbn, auteur,type,empruntable=true)
#titre = titre
#isbn = isbn
#auteur = auteur
#type = type
#empruntable = empruntable
end
#def self.empruntable
# #empruntable = true
#end
def to_s
"#{#type.capitalize}:#{#titre.capitalize}- #{#auteur.capitalize} #ISBN: #{#isbn.to_s.capitalize}"
end
end
The new output:
true
Vous avez emprunter: Harry Potter And The Goblet Of Fire!
false

unexpected ',' syntax error ruby

I'm learning ruby and have looked the internet to see whats wrong with this. I have tried adding spacing and removing it between the variables I'm passing but i keep getting this error:
25: syntax error, unexpected ',', expecting ')'
student1.grades =(60,70,80)
Here is the code:
class Student
attr_accessor :name, :age
def initialize(name,age)
#name = name
#age = age
end
def grades(math,english,science)
#math = math
#english = english
#science = science
average_grade = (math.to_i + english.to_i + science.to_i) / 3
return average_grade
end
def to_s
puts "Name = #{name}"
puts "Age = #{age}"
puts self.grades
end
end
student1 = Student.new("Tom","23")
student1.grades = (60,70,80)
puts student1
grades receives three parameters. You don't do that with assignment. So change
student1.grades = (60,70,80)
to
student1.grades(60,70,80)
You can assign the grades for student object as
student1.grades(60,70,80)
Also minor edits.You can add the method for computing average
def grades_details
average_grade = (#math.to_i + #english.to_i + #science.to_i) / 3
return average_grade
end
So when you override to string u call it instead of self.grades
def to_s
puts "Name = #{name}"
puts "Age = #{age}"
puts grades_details
end

uninitialized constant Die (NameError)

I'm receiving an Uninitialized constant error from my code. I have searched around with no luck. Any help would be highly appreciated.
Class Die
def initialize
roll
end
def roll
#num_showing = 1 + rand(6)
end
def showing
#num_showing
end
def cheat
puts "Enter the die # (1-6)"
#num_showing = gets.chomp
while #numshowing > 6 and #numshowing < 0
puts "Enter the die # (1-6)"
#num_showing = gets.chomp
end
end
puts Die.new.cheat
Change Class to class
Add an extra end at the end of the class definition. Looks like you're not closing the while loop.

Assigning return value to variable in Ruby in Learn Ruby the Hard Way, exercise 21

In Zed Shaw's Learn Ruby the Hard Way, exercise 21:
def add(a, b)
puts "ADDING #{a} + #{b}"
a + b
end
age = add(30, 5)
puts "Age: #{age}"
This prints Age: 35.
I tried doing this with the previous exercise (ex20):
def print_all(f)
puts f.read()
end
current_file = File.open(input_file)
sausage = print_all(current_file)
puts "Sausage: #{sausage}"
But when I run it, #{sausage} does not print, even after I move the file pointer back to 0:
def print_all(f)
puts f.read()
end
def rewind(f)
f.seek(0, IO::SEEK_SET)
end
current_file = File.open(input_file)
sausage = print_all(current_file)
rewind(current_file)
puts "Sausage: #{sausage}"
I assigned the return value from method add(a, b) to age, why can't I do the same with print_all(current_file)?
def print_all(f)
puts f.read()
end
The return value of print_all is the return value of puts f.read(), which is the return value of puts, not the return value of f.read(). puts always returns nil. Therefore, print_all always returns nil.
Perhaps you intended:
def print_all(f)
f.read()
end
Or if you need to print it in your function/method:
def print_all(f)
foo = f.read()
puts foo
foo
end

Ruby - how can I deal with a variable if it doesn't exist

I want do puts blob
but if the blob variable doesn't exist, I get
NameError: undefined local variable or method `blob' for main:Object
I've tried
blob?
blob.is_a?('String')
puts "g" if blob
puts "g" catch NameError
puts "g" catch 'NameError'
but none work.
I can get around it by using an #instance variable but that feels like cheating as I should know about and deal with the issue of no value accordingly.
In this case, you should do:
puts blob if defined?(blob)
Or, if you want to check for nil too:
puts blob if defined?(blob) && blob
The defined? method returns a string representing the type of the argument if it is defined, or nil otherwise. For example:
defined?(a)
=> nil
a = "some text"
=> "some text"
defined?(a)
=> "local-variable"
The typical way of using it is with conditional expressions:
puts "something" if defined?(some_var)
More about defined? on this question.
class Object
def try(*args, &block)
if args.empty? and block_given?
begin
instance_eval &block
rescue NameError => e
puts e.message + ' ' + e.backtrace.first
end
elsif respond_to?(args.first)
send(*args, &block)
end
end
end
blob = "this is blob"
try { puts blob }
#=> "this is blob"
try { puts something_else } # prints the service message, doesn't raise an error
#=> NameError: undefined local variable or method `something_else' for main:Object

Resources