creating a class object array inside another object? - arrays

I've got these three classes
class Totalizavel
def retorna (qnt, valor)
total = qnt * valor
return total
end
end
class Venda < Totalizavel
def initialize (num, data, cliente, itens)
#venda_num = num #int
#venda_data = data #tipo Date
#venda_cliente = cliente #tipo Cliente
#venda_itens = itens #tipo Item_Venda
end
def get_num
return #venda_num
end
def get_data
return #venda_data
end
def get_cliente
return #venda_cliente
end
def get_item
return #venda_itens
end
def set_num (numero)
#venda_num = numero
end
def set_data (data)
#venda_data = data
end
def set_cliente (cliente)
#venda_cliente = cliente
end
def set_item (item)
#venda_itens = item
end
end
class ItemVenda < Totalizavel
def initialize (produto, valor, quantidade)
#item_produto = produto
#item_valor = valor
#item_qnt = quantidade
end
def get_produto
return #item_produto
end
def get_valor
return #item_valor
end
def get_qnt
return #item_qnt
end
def set_produto (produto)
#item_produto = produto
end
def set_valor (valor)
#item_valor = valor
end
def set_qnt (qnt)
#item_qnt = qnt
end
end
And this attribute "#venda_itens" should to be an array of "ItemVenda", how is the best way to initialize it ? I've tried creating an auxiliar array and then "pass" it to the class like this:
remind that's only part of the code
def manipvendas
while true
puts "\n1- Add sell"
puts "2- show sells"
puts "0- get back to previous menu"
print "Insert the desired option: "
escolha = gets.chomp
return if escolha == "0"
if escolha == "1" #add sell
print "\nInsert the number: "
numvend = gets.chomp
numvend = numvend.to_i
print "\nInsert the date (Year, month, day): "
ano = gets.chomp
mes = gets.chomp
dia = gets.chomp
data = Time.new(ano.to_i, mes.to_i, dia.to_i)
print "\nInsert the client: "
clientenum = gets.chomp
vendai = Venda.new(numvend,data,clientenum,selecproduto)
#vendas.push(vendai)
end
if escolha == "2" #show sells
if #vendas.size == 0
puts "\nThere are no sells"
else
puts "\nPrinting sells database: \n\n"
i = 0
for a in 1..#vendas.size do
puts "Code: " + #vendas[i].get_num.to_s
puts "Date: " + #vendas[i].get_data.day.to_s + "/" + #vendas[i].get_data.month.to_s + "/" + #vendas[i].get_data.year.to_s + "\n"
puts "Client: " + #vendas[i].get_cliente.to_s
puts "Itens: "
if #vendas[i].get_item.size == 0
puts "\nThere are no itens"
else
j = 0
for a in 1..#vendas[i].get_item.size do
puts "Number: " + #vendas[i].get_item[j].get_produto.to_s
puts "Unity value: " + #vendas[i].get_item[j].get_valor.to_s
puts "Sold: " + #vendas[i].get_item[j].get_qnt.to_s
puts "Total value: " + #vendas[i].get_item[j].retorna(#vendas[i].get_item[j].get_valor.to_f, #vendas[i].get_item[j].get_qnt.to_i).to_s
j = j+1
end
end
i = i+1
end
end
end
end
end
def selecproduto
while true
#itemvenda.clear
puts "\nInsert the product number: "
print "Insert -1 to return: "
produtonum = gets.chomp
return if produtonum == "-1"
produtonum = produtonum.to_i
print "\nInsert the amount sold: "
produtoqnt = gets.chomp
produtoqnt = produtoqnt.to_i
valor = produtoqnt.to_i
vendaitem = ItemVenda.new(produtonum, #produtos[produtonum].get_valor, valor)
#itemvenda.push(vendaitem)
return vendaitem
end
end
It's returning correctly until I try to add another "product", when I do this then select to show the registered sells, it returns me the amount of sells I created but with the parameters of the last sell multiplied for the number os registered sells
What's wrong with my code ?

We can refactor some methods. Let's go!
When you instantiate a new object Venda, you can pass the array of ItemVenda, like this:
itens = [item1, item2, item3]
cliente = Cliente.new("João", "flow#stackoverflow.com")
venda = Venda.new(1, DateTime.now, cliente, itens)
venda.total(itens)
require 'date'
class Venda
attr_accessor :num, :data, :cliente, :itens
def initialize(num, data, cliente, itens)
#num = num #int
#total = total #int
#data = data #tipo Date
#cliente = cliente #tipo Cliente
#itens = itens #tipo Item_Venda
end
def total(itens)
itens.map { |item| item.quantidade * item.valor }.sum
end
def add_item(item)
#itens << item
end
end
class ItemVenda < Venda
attr_accessor :produto, :valor, :quantidade
def initialize (produto, valor, quantidade)
#produto = produto
#valor = valor
#quantidade = quantidade
end
end
class Cliente
attr_accessor :nome, :email
def initialize(nome, email)
#nome = nome
#email = email
end
end

Related

Output display as null (Ruby)

Here when we print array elements it display null value all time like "[nil, nil, nil, nil]"
Values are not getting stored in array.
class Flight
def initilize(flight_id, flight_num, flight_orgin, flight_destination)
#id= flight_id
#number = flight_number
#origin = flight_origin
#destination = flight_destination
end
def read_flight()
puts "enter flight id"
flight_id = gets.chomp
puts "enter flight number"
flight_number = gets.chomp
puts "enter flight origin location"
flight_origin = gets.chomp
puts "enter destination"
flight_destination = gets.chomp
end
def print_flight(id, number, orgin, destination)
puts "_____Flight details______"
puts "Flight_id :#{id}"
puts "Flight_number :#{number}"
puts "Flight_orgin :#{orgin}"
puts "Flight_destination:#{destination}"
end
def read_flights(id, number, orgin, destination)
puts "_______Array of flights______"
flightid = Array.new
flightid.push(id, number, orgin, destination)
puts "#{flightid}"
end
end
input_flight = Flight.new
input_flight.read_flight
input_flight.print_flight(#id, #num, #orgin, #destination)
input_flight.read_flights(#id, #num, #orgin, #destination)
Without using a class or instance variable we want to do it
User input
enter flight id
2
enter flight number
2342
enter flight origin location
cochin
enter destination
tvm
output
Flight details_
Flight_id :
Flight_number :
Flight_orgin :
Flight_destination:
_Array of flights
[nil, nil, nil, nil]
The #id, #num, #orgin, #destination parameters will be nil if you don't set them anywhere.
So when you make these two calls:
input_flight.print_flight(#id, #num, #orgin, #destination)
input_flight.read_flights(#id, #num, #orgin, #destination)
You basically just send nils into the function:
input_flight.print_flight(nil, nil, nil, nil)
input_flight.read_flights(nil, nil, nil, nil)
If you want to access the variables read from the input:
First, you need to store them somewhere. For ex: store them inside the instance variables when read_flight function is called.
Then, refer the instance variable when you want to push values in the array.
Ex:
def read_flight
puts "enter flight id"
#id = gets.chomp # store inside instance variable
puts "enter flight number"
#number = gets.chomp
puts "enter flight origin location"
#origin = gets.chomp
puts "enter destination"
#destination = gets.chomp
end
def read_flights
...
flightid.push(#id, #number, #origin, #destination) # access instance variables here
...
end
You can learn more about Ruby's variable scoping (instance variables, global variables, etc) here: https://www.techotopia.com/index.php/Ruby_Variable_Scope
Here is my version of adjustion:
class Flight
attr_reader :id, :number, :origin, :destination
def read_flight
puts "enter flight id"
#id = gets.chomp
puts "enter flight number"
#number = gets.chomp
puts "enter flight origin location"
#origin = gets.chomp
puts "enter destination"
#destination = gets.chomp
end
def print_flight
puts "_____Flight details______"
puts "Flight_id :#{id}"
puts "Flight_number :#{number}"
puts "Flight_orgin :#{origin}"
puts "Flight_destination:#{destination}"
end
def read_flights
puts "_______Array of flights______"
flightid = [id, number, origin, destination]
puts "#{flightid}"
end
end
input_flight = Flight.new
input_flight.read_flight
input_flight.print_flight
input_flight.read_flights
Explanation:
Each instance of ruby class can have as many instance variables (which begin with #) as possible. Those instance variables live in an instance so they keep their value across the methods.
So you should assign the value you want to instance variables, for example:
#id = gets.chomp
then use it in another method:
def print_flight
puts "_____Flight details______"
puts "Flight_id :#{#id}"
end
However, add # everytime we want to use the instance variables is pretty tedious. That's why attr_reader comes in. When you write attr_reader:
attr_reader :id, :number, :origin, :destination
You actually declare 4 methods inside Flight:
def id
#id
end
def number
#number
end
def origin
#origin
end
def destination
#destination
end
Then you can just use id, number, origin, destination without the leading #`
You're initializing with nil values in your constructor (def initialize), to fix that you can pass the values to the .new or change the read_flight as follows:
def read_flight()
puts "enter flight id"
#flight_id = gets.chomp
puts "enter flight number"
#flight_number = gets.chomp
puts "enter flight origin location"
#flight_origin = gets.chomp
puts "enter destination"
#flight_destination = gets.chomp
end
This will modify the class-scoped variables.
Or alternatively you can have default values in the constructor (not recommended) using the || operator:
def initilize(flight_id, flight_num, flight_orgin, flight_destination)
#id= flight_id || 0
#number = flight_number || 0
#origin = flight_origin || ""
#destination = flight_destination || ""
end
First of all, be careful, because you did a lot of little but important mistakes. It's ok, we all started like that)
For example, your 'initialize' method name is not correct!
Your: 'initilize'
Correct: 'initialize'
It's important to name default methods correct.
Also, when you initialize variables with method arguments:
def initilize(flight_id, flight_num, flight_orgin, flight_destination)
#id= flight_id
#number = flight_num #you have to name it just like argument in method not flight_number, because it does not exist at all
#origin = flight_origin #same here, you forgot one letter
#destination = flight_destination
end
If you want user to initialize your instances then don't initialize them by yourself, delete arguments in initialize method.
Also, you can use instance variables in entire class, it's really helpful!
So, i corrected a little:
class Flight
def read_flight
puts "enter flight id"
#id = gets.chomp
puts "enter flight number"
#number = gets.chomp
puts "enter flight origin location"
#origin = gets.chomp
puts "enter destination"
#destination = gets.chomp
end
def print_flight
puts "_____Flight details______"
puts "Flight_id : " + #id.to_s
puts "Flight_number : " + #number.to_s
puts "Flight_origin : " + #origin
puts "Flight_destination: " + #destination
end
def read_flights
puts "_______Array of flights______"
flightid = Array.new
flightid.push({ #id,#number,#origin,#destination })
puts "#{flightid}"
end
end
Check:
input_flight = Flight.new
input_flight.read_flight
input_flight.print_flight
input_flight.read_flights

Ruby, how can i compare a string with a specific element of array?

I create an array from a text file which contains the english irregular verbs. I want the code to ask me the verbs in random order letting me proceed only if I respond correctly. I need to compare a string with an element of array. I wrote this:
a = []
File.open('documents/programmi_test/verbi.txt') do |f|
f.lines.each do |line|
a <<line.split.map(&:to_s)
end
end
puts ''
b = rand(3)
puts a[b][0]
puts 'infinitive'
infinitive = gets.chomp
if infinitive = a[b][1] #--> write like this, I receive alway "true"
puts 'simple past'
else
puts 'retry'
end
pastsimple = gets.chomp
if pastsimple == a[b][2] #--> write like this, I receive alway "false"
puts 'past participle'
else
puts 'retry'
end
pastpart = gets.chomp
if pastpart == a[b][3]
puts 'compliments'
else
puts 'oh, no'
end
can somebody help me?
if infinitive = a[b][1] is assigning to inifinitive the value of a[b][1], unlike pastsimple == a[b][2] that's a comparation between both values.
You could try replacing the = for ==.
a = []
File.open('documents/programmi_test/verbi.txt') do |file|
file.lines.each do |line|
a << line.split.map(&:to_s)
end
end
puts ''
b = rand(3)
puts a[b][0]
puts 'infinitive'
infinitive = gets.chomp
puts infinitive == a[b][1] ? 'simple past' : 'retry'
pastsimple = gets.chomp
puts pastsimple == a[b][2] ? 'past participle' : 'retry'
pastpart = gets.chomp
puts pastpart == a[b][3] ? 'compliments' : 'oh, no'

I pass an array to a ruby method I wrote but ruby sees a fixnum?

everyone, I'm a super Ruby n00b having problems getting my first Ruby program to work. I have found Q and A here on Stack Overflow that are closely related to the problem that I am having but no matter what I try, I just can't get rid of this error.
I have written two classes, Checkout and Register. Here's the full Register class:
<code>
load 'Register.rb'
class Checkout
def initialize
#register = Register.new
#itemCount = Hash['CH1', 0, 'AP1', 0, 'CF1', 0, 'MK1', 0]
##inventory = Hash['CH1', 3.11, 'AP1', 6.00, 'CF1', 11.23, 'MK1', 4.75]
##discount = Hash['CF1', ['BOGO', '#itemCount["CF1"]%2==0', -11.23, '#register.findLast("CF1")'], 'AP1', ['APPL', '#itemCount["AP1"]>=3', -1.50, '#itemCount["AP1"]==3 ? #register.findAll("AP1") : #register.findLast("AP1")'], 'MK1', ['CHMK', '#itemCount["MK1"]==1 && #itemCount["CH1"]==1', -4.75, '#register.findAll("MK1")']]
end
def scan(item)
#get price of item from inventory
price = ##inventory[item]
#add item and price to register
#register.ringUp(item, price)
#itemCount[item]+=1
#find and apply any applicable special
discountCheck = ##discount[item]
unless discountCheck == nil
nameOfDiscount = ##discount[item][0]
discountCondition = ##discount[item][1]
moneyOff = ##discount[item][2]
howToGetItemIndex = ##discount[item][3]
if(eval(discountCondition))
ind = eval(howToGetItemIndex)
if(ind.class == "Array")
#register.applyDiscount(ind, moneyOff, nameOfDiscount)
else #it's a Fixnum so we want to put it in an array first
indArray = [ind]
#register.applyDiscount(indArray, moneyOff, nameOfDiscount)
end
end
end
end
end
</code>
Here is the Register class:
<code>
class Register
def initialize
#itemsInOrderOfScan = Array.new
#itemInfoInOrderOfScan = Array.new
end
def ringUp(item, price)
#itemsInOrderOfScan.push(item)
#itemInfoInOrderOfScan.push(['', price])
end
def applyDiscount(indices, moneyOff, nameOfDiscount)
for i in 0..indices.length-1
ind = indices[i]
newInd = ind + 1
#itemsInOrderOfScan.insert(newInd, '')
#itemInfoInOrderOfScan.insert(newInd, [nameOfDiscount, moneyOff])
end
end
def findLast(item)
arr = Array.new
ind = #itemsInOrderOfScan.rindex(item)
arr.push(ind)
arr
end
def findAll(item)
indexOfFirstInstanceOfItem = #itemsInOrderOfScan.index(item)
arr = findLast(item)
indexOfLastInstanceOfItem = arr.at(0)
for i in indexOfFirstInstanceOfItem..indexOfLastInstanceOfItem
if(#itemsInOrderOfScan.at(i) == item)
arr.push(i)
end
end
arr
end
def printReceipt
puts "Item\t\t\tPrice"
puts "----\t\t\t-----"
total = 0
for i in 0..#itemsInOrderOfScan.length-1
currentItem = #itemsInOrderOfScan.at(i)
currentDiscountName = #itemInfoInOrderOfScan.at(i)[0]
currentPrice = #itemInfoInOrderOfScan.at(i)[1]
total += currentPrice
puts "#{currentItem}\t#{currentDiscountName}\t\t#{currentPrice}"
end
puts "-----------------------------------\n\t\t\t#{total}"
end
end
</code>
The way these classes should work when I try to run them is as follows: I feed Checkout various items and the two classes work together to create a receipt showing what has been purchased and any discounts that could be applied whenever I call the printReceipt method.
The test that I am using to debug looks like this:
<code>
load 'Checkout.rb'
basket = ['CH1', 'AP1', 'AP1', 'AP1', 'MK1']
co = Checkout.new
for i in 0..basket.length
puts basket.at(i)
co.scan(basket[i])
end
co.register.print()
</code>
The output when I run the test looks like this:
<code>
CH1
AP1
AP1
AP1
Register.rb:16:in `+': no implicit conversion of Fixnum into Array (TypeError)
from Register.rb:16:in `block in applyDiscount'
from Register.rb:14:in `each'
from Register.rb:14:in `applyDiscount'
from Checkout.rb:33:in `scan'
from main.rb:9:in `block in <main>'
from main.rb:7:in `each'
from main.rb:7:in `<main>'
</code>
Please help!
Thank you in advance.
you need to fix at 4 places,
In Checkout.rb, if(ind.class == "Array") is wrong comparison
use if(ind.class.to_s == "Array") or better use if(ind.instance_of? Array)
In you main.rb, use for i in 0...basket.length instead of for i in 0..basket.length because 1..2 => [1,2] but 1...3 => [1,2]
In Checkout.rb, after Class first line should be attr_accessor :register because you are access register in main.rb
In main.rb, co.register.printReceipt instead of co.register.print()
main.rb :
load 'Checkout.rb'
basket = ['CH1', 'AP1', 'AP1', 'AP1', 'MK1']
co = Checkout.new
for i in 0...basket.length
puts basket.at(i)
co.scan(basket[i])
end
co.register.printReceipt
Checkout.rb :
load 'Register.rb'
class Checkout
attr_accessor :register
def initialize
#register = Register.new
#itemCount = Hash['CH1', 0, 'AP1', 0, 'CF1', 0, 'MK1', 0]
##inventory = Hash['CH1', 3.11, 'AP1', 6.00, 'CF1', 11.23, 'MK1', 4.75]
##discount = Hash['CF1', ['BOGO', '#itemCount["CF1"]%2==0', -11.23, '#register.findLast("CF1")'], 'AP1', ['APPL', '#itemCount["AP1"]>=3', -1.50, '#itemCount["AP1"]==3 ? #register.findAll("AP1") : #register.findLast("AP1")'], 'MK1', ['CHMK', '#itemCount["MK1"]==1 && #itemCount["CH1"]==1', -4.75, '#register.findAll("MK1")']]
end
def scan(item)
#get price of item from inventory
price = ##inventory[item]
#add item and price to register
#register.ringUp(item, price)
p item
p #itemCount[item]
#itemCount[item]+=1
#find and apply any applicable special
discountCheck = ##discount[item]
unless discountCheck == nil
nameOfDiscount = ##discount[item][0]
discountCondition = ##discount[item][1]
moneyOff = ##discount[item][2]
howToGetItemIndex = ##discount[item][3]
if(eval(discountCondition))
ind = eval(howToGetItemIndex)
if(ind.class.to_s == "Array")
#register.applyDiscount(ind, moneyOff, nameOfDiscount)
else #it's a Fixnum so we want to put it in an array first
indArray = [ind]
#register.applyDiscount(indArray, moneyOff, nameOfDiscount)
end
end
end
end
end

How to have upper case methods in ruby

I got a chatbot in ruby that if a character is repeated five times or more in the chat, in the first and second attempt, it warns the user, at the third attempt it kicks the user and the fourth one bans the user for two hours, and it's currently working
require_relative '../plugin'
class Flood
include Chatbot::Plugin
match /(.*)/, :method => :check_swear, :use_prefix => false
def initialize(bot)
super(bot)
#data = {}
end
def check_swear(user, message)
message = message.downcase
array = ["aaaaa", "ñññññ", "bbbbb", "ccccc", "ddddd", "eeeee", "fffff", "ggggg", "hhhhh", "iiiii", "jjjjj", "mmmmm", ".....", "*****", "?????", "!!!!!", "zzzzz", "kkkkkk", "ooooo", "nnnnn", "ppppp", "qqqqq", "rrrrr", "-----", "_____", "¨¨¨¨¨¨¨¨", "{{{{{", "}}}}}", "#####"]
array.each do |e|
if message.include? e
if(#data[user.name] and #data[user.name] == 3)
#client.send_msg "%s: [[Wiki_Freddy_Fazbear's_Pizza:Reglas_y_Lineamientos|Has sido advertido. Tendrás un ban de 2 horas.]] 4/3" % user.name
#client.ban user.name, "7200", "Ban automático por exceso de carácteres - Si crees que esto fué un error, contacta con un [[Wiki_Freddy_Fazbear%27s_Pizza:Administradores|moderador u Admin en su muro de mensajes]]."
#client.send_msg "!mods por si acaso consideran necesario más tiempo de ban."
#client.kick user.name
#data[user.name] = 0
elsif(#data[user.name] and #data[user.name] == 2)
#data[user.name] ||= 0
#data[user.name] += 1
#client.send_msg "%s: [[Wiki_Freddy_Fazbear's_Pizza:Reglas_y_Lineamientos|Por favor, no repitas carácteres, última advertencia antes de un ban.]] 3/3" % user.name
#client.kick user.name
elsif(#data[user.name] and #data[user.name] == 1)
#data[user.name] ||= 0
#data[user.name] += 1
#client.send_msg "%s: [[Wiki_Freddy_Fazbear's_Pizza:Reglas_y_Lineamientos|Por favor, no repitas carácteres, última advertencia antes de un kick]], 2/3" % user.name
else
#data[user.name] ||= 0
#data[user.name] += 1
#client.send_msg "%s: [[Wiki_Freddy_Fazbear's_Pizza:Reglas_y_Lineamientos|Por favor, no repitas carácteres]], 1/3" % user.name
end
end
end
end
end
Now, I need to change it, being all the same except for that it does not trigger with 5 characters or more, but if 5 or more words in a message are in capital letters, can someone help me?
Edit: By the way, if someone can also help me to make it trigger not just with the characters in the array list but any character, it would be awesome
Something like the following will return true if a message has 5 or more uppercase words.
def is_message_shouting?(message)
shouted_words = 0
message.split(' ').each do |word|
shouted_words += 1 if word.upcase == word
end
shouted_words >= 5
end
puts is_message_shouting? 'THIS IS A VERY SHOUTY MESSAGE'
puts is_message_shouting? 'this is not a shouty message'
puts is_message_shouting? 'THIS IS ALSO not a shouty message'
Outputs:
true
false
false
def shouting?(message)
message.split.count { |word| word == word.upcase } >= 5
end
Nothing original to add, just a cleaner implementation of the same.
Something like
class String
def is_upper?
self == self.upcase
end
end
def shouting?(msg)
count = 0
0.upto(msg.size) { |i| count += 1 if msg[i].is_upper? }
count >= 5
end

Text file over written and not appended

So far I have this program doing what i want. However when running through it will overwrite the last employee record instead of just adding to the file. I'm new to prgramming and have been staring at this for hours and i can't get it yet. Just need a little nudge in the right direction.
# Define Employee Class
# Common Base Class for all Employees
class EmployeeClass:
def Employee(fullName, age, salary):
fullName = fullName
age = age
salary = salary
def displayEmployee():
print("\n")
print("Name: " + fullName)
print("Age: " + age)
print("Salary: " + salary)
print("\n")
EmployeeArray = []
Continue = True
print ("Employee Information V2.0")
while Continue == True:
print ("Welcome to Employee Information")
print ("1: Add New Record")
print ("2: List Records")
print ("3: Quit")
choice = input("Pick an option: ")
if choice == "1":
fullName = input ("Enter Full Name: ")
if fullName == "":
blankName = input ("Please enter a name or quit: ")
if blankName == "quit":
print ("Goodbye!")
print ("Hope to see you again.")
Continue = False
break
age = input ("Enter Age: ")
salary = input ("Enter Salary: ")
EmployeeRecords = open ('EmployeeRecords.txt' , 'w')
EmployeeRecords.write("Full Name: " + fullName + '\n')
EmployeeRecords.write("Age: " + age + '\n')
EmployeeRecords.write("Salary: " + salary + '\n')
EmployeeRecords.close()
elif choice == "2":
EmployeeRecords = open ('EmployeeRecords.txt', 'r')
data = EmployeeRecords.read()
print ("\n")
print (data)
EmployeeRecords.close
elif choice == "3":
answer = input ("Are you sure you want to quit? " "yes/no: ")
if answer == "yes" or "y":
print ("Bye!")
Continue = False
else:
Continue
else:
print ("Please choose a valid option")
print ("\n")
You are opening the file to be rewritten each time, based on the control string passed to open. Change open ('EmployeeRecords.txt, 'w')to open ('EmployeeRecords.txt', 'a+'). and the records will be appended to the end of the file.
Append mode should work.
EmployeeRecords = open('EmployeeRecords.txt', 'a')

Resources