I'm fairly new to ruby and am practicing it.
However in this exercise I'm doing it creates two bank accounts using the same method and same values, and the program expects both to be equal.
RSpec returns this to me:
Failure/Error: expect(conta1).to eql conta2
expected: #<Conta:0x3161bc8 #numero="2303-2", #nome="Jose da Silva", #saldo=1000.1, #limite=500>
got: #<Conta:0x31615f8 #numero="2303-2", #nome="Jose da Silva", #saldo=1000.1, #limite=500>
(compared using eql?)
Diff:
## -1,4 +1,4 ##
-#<Conta:0x3161bc8
+#<Conta:0x31615f8
#limite=500,
#nome="Jose da Silva",
#numero="2303-2",
The content of both the accounts are the same, but there's a conflict on the object_id, how do I resolve this?
Here is the code:
it "Two accounts with the same data should be equal" do
conta1 = cria_conta
conta2 = cria_conta
expect(conta1).to eql conta2
end
def cria_conta(numero="2303-2", nome="Jose da Silva", saldo=1000.10, limite=500)
Conta.new(numero: numero, nome: nome, saldo: saldo, limite: limite)
end
Also:
class Conta
attr_accessor :numero, :nome, :saldo, :limite
def initialize(arr)
#numero = arr[:numero]
#nome = arr[:nome]
#saldo = arr[:saldo]
#limite = arr[:limite]
end
def sacar(valor)
possibilidade = false
##valor = valor
if valor < #saldo
#saldo -= valor
possibilidade = true
elsif valor > #limite
#saldo -= valor
##saldo = #saldo
possibilidade
end
end
def no_limite?()
if ##valor > #limite
return true
elsif ##valor < #limite
return false
end
end
def depositar(valor)
#saldo += valor
end
def ==(outra_conta)
self.conta == outra_conta
end
end
I tried to define a a diffrent method for == but I was unsuccessful.
If you wants to only compare the attributes, not the object itself, here is the example code you might start with.
class Person
attr_accessor :name, :id
def initialize(id, name)
#id = id
#name = name
end
def ==(other_person)
self.instance_variables.each do |method|
method = method.to_s.gsub('#', '')
return false if self.send(method) != other_person.send(method)
end
return true
end
end
p1 = Person.new(1, 'alice')
p2 = Person.new(1, 'alice')
p3 = Person.new(1, 'tim')
puts p1 == p2 # true
puts p1 == p3 # false
Related
Learning oop in Ruby and encountering some unexpected behavior in a class i've written. Here is my Radio class, I can change the volume attribute, but when I change the freq attribute, the band attribute is changed from fm to true. I cannot figure out why this is happening.
my file init.rb that's calling the Radio class:
require_relative 'classes/radio'
fm_radio = Radio.fm
fm_radio.volume = 10
puts fm_radio.status
#volume: 10 band: fm frequency: 88.0
fm_radio.freq = 99.0
puts fm_radio.status
#volume: 10 band: true frequency: 99.0
puts fm_radio.band
# true
my file radio.rb that contains the Radio class:
class Radio
attr_accessor :volume, :freq
attr_reader :band
def initialize(band)
#band = band
if band == 'am'
#freq = 540.0
else
#freq = 88.0
end
#volume = 1
end
def volume=(value)
return if value < 1 || value > 10
#volume = value
end
def freq=(value)
if #band = 'am' && (540.0..1600).include?(value)
#freq = value
elsif #band = 'fm' && (88.0..108.0).include?(value)
#freq = value
else
puts 'out of range'
end
end
def crank_it_up
#volume = 11
end
def status
"volume: #{#volume} band: #{#band} frequency: #{#freq}"
end
def self.am
Radio.new('am')
end
def self.fm
Radio.new('fm')
end
end
Your error is in these two lines:
if #band = 'am' && (540.0..1600).include?(value)
elsif #band = 'fm' && (88.0..108.0).include?(value)
Using a single =, you're assigning to #band what is evaluated from 'am' && (540.0..1600).include?(value), which eventually will be a boolean value.
You must use == to compare #band with another string.
I write a multiplayer game(snake) with backend based on Ruby. This function must receive commands for frontend and send the current state of the game. But throw NoMethod error on the four line of my function for the changeside method and I don't know why because of that class method is present.
Class method example
def changeside(nump,newSide)
opp = {'R':'L','U':'D','D':'U','L':'R'}
cx = {'L':-1,'R':1,'U':0,'D':0}
cx = {'L':0,'R':0,'U':-1,'D':1}
if newSide!=opposite[players[nump]['side']] && ['R','L','U','D'].count( newSide)==1
players[nump]['side']['cx'] = cx[newSide]
players[nump]['side']['cy'] = cy[newSide]
end
end
Error example
2020-10-07 18:01:23 - NoMethodError - undefined method `[]' for nil:NilClass:
The function I'm run
def getStatus(game)
ans = {"opStatus"=>TRUE}
puts game
$games[game['gid'.to_i]]['game'].changeside(2,game['side'])
$games[game['gid'.to_i]]['game'].move(($games[game['gid']]['fid']==game['pid']?1:2))
ans["gameStatus"] = $games[game['id']]['game'].run
ans['timer'] = $games[game['id']]['game'].timer
ans['snake'] = $games[game['id']][($games[game['id']]['fid']==game['pid']?1:2)].snake
ans['enemy'] = $games[game['id']][($games[game['id']]['fid']==game['pid']?2:1)].snake
ans['food'] = $games[game['id']]['game'].food
end
Here is JSON sent to the function
{"gid"=>"1", "side"=>"R", "pid"=>"1"}
To fix that, I debugged that moment, but I couldn't go inside a class method.
Here is the full code of the class game.
It located in another file and called by
`require_relative 'game.rb'`
Full code of the class.
class Game
attr_accessor :players, :food, :walls, :timer, :run,:winner
def initialize()
#players = {}
#winner = -1
#players[1] = {'snake'=>[[9,2],[8,2],[7,2]]}
#players[1]['cx'] = 0
#players[1]['cy'] = -1
#players[1]['side'] = 'U'
#players[2] = {'snake'=>[[2,9],[2,8],[2,7]]}
#players[2]['cx'] = -1
#players[2]['cy'] = 0
#players[2]['side'] = 'L'
#timer = 0
#run = FALSE
genFood
end
def genFood()
#food = [rand(10)+1,rand(10)+1]
while players[1]['snake'].include?(food) || players[2]['snake'].include?(food)
#food = [rand(10)+1,rand(10)+1]
end
end
def move(nump)
if #run
#timer+=0.25
#players[nump]['snake'].shift
#players[nump]['snake'].push([#players[id]['snake'][0]+#players[id]['cx'],#players[id]['snake'][1]+#players[id]['cy']])
if #players[nump]['snake'][0] == food
#players[nump]['snake'][0].unshift(food)
#food = [rand(10)+1,rand(10)+1]
while players[nump]['snake'].include(food) or players[1]['snake'].include(food)
#food = [rand(10)+1,rand(10)+1]
end
end
if #player[nump]['snake'].count(#player[nump]['snake'][-1])==2 ||
#winner = ((nump==1)?2:1)
elsif #players[((nump==1)?2:1)]['snake'].count(#player[nump]['snake'][-1])==1
#winner = 0
else
if #timer==60
if #players[1]['snake'].length()>#players[2]['snake'].length()
#winner = 1
elsif #players[1]['snake'].length()<#players[2]['snake'].length()
winner = 2
else
winner = 0
end
end
end
end
end
def changeside(nump,newSide)
opp = {'R':'L','U':'D','D':'U','L':'R'}
cx = {'L':-1,'R':1,'U':0,'D':0}
cx = {'L':0,'R':0,'U':-1,'D':1}
if newSide!=opposite[players[nump]['side']] && ['R','L','U','D'].count( newSide)==1
players[nump]['side']['cx'] = cx[newSide]
players[nump]['side']['cy'] = cy[newSide]
end
end
end
Open-uri and nokogiri are slow to scrape the site I want hence the Net::OpenTimeout execution expired error. I attempted to code a custom error with rescue however I do not know what condition I can look for to raise that custom error.
I attempted to few if else statements however I really just guessed how to check if I was gonna get that error. I hard coded a condition that failed and thus rescued the error. I am very new to ruby and custom errors. In fact this is my first.
class Scrape
Base = 'http://www.wine.com'
##menu = []
##pages = []
def self.index
index_url = Base + "/list/wine/7155?sortBy=savings&pricemax=90"
#below is where I need to check for the condition to
raise the error
if doc = Nokogiri::HTML(open(index_url))
container = doc.css('.prodList')
wines = container.css('.prodItem')
wines.each do |wine|
##menu << {
:link => wine.css('.prodItemInfo_link').attribute('href').value,
:name => wine.css('.prodItemInfo_name').text,
:rating => (wine.css('.averageRating_average').text.to_i) > 0 ?
(wine.css('.averageRating_average').text) : 'no rating',
:price => wine.css('.productPrice_price-saleWhole').text.strip
}
end
##menu.each do |item|
Bottle.new.create(item)
end
else
begin
raise Custom_error
rescue Custom_error => error
puts error.message
end
end
end
def self.scrape_page(wine_obj)
wine_link = wine_obj.link
individual_page = Base + wine_link
docu = Nokogiri::HTML(open(individual_page))
y = docu.css('.viewMoreModule_text')
more = docu.css('.viewMoreModule_text')
##pages << {
:obj => wine_obj,
:name => docu.css('.pipName').text,
:alcohol_percent => y
x = docu.css('.mobileProdAttrs').css('.prodAlcoholPercent')
y = x.css('.prodAlcoholPercent_percent').text,
:price => docu.css('span.productPrice_price-saleWhole').text,
:origin => docu.css('span.prodItemInfo_originText a').text,
:winemaker_notes => docu.css('.viewMoreModule_text').first.text,
:more => y[2].text,
:rating => docu.css('span.averageRating_average').first.text
}
Page.create_find_by_name( ##pages.last )
end
def self.pages
##pages
end
end
class Cli
def run
puts 'loading from cyberspace'
Scrape.index
Bottle.make_list
controller
end
def controller
input = ''
response = ''
puts ' '
view
while input != 11
response = gets.chomp.to_i
input = "#{response}11".to_i
if input == 111
menu
elsif input == 11
exit
elsif input > 0 && input < 26
find_by_input(input)
elsif input != 0 && input != 111
error_1
end
end
end
def view
puts "welcome to the wine bar"
puts "================="
puts " W I N E "
puts " B A R "
puts "================="
puts " "
puts "type 1 for list of wine"
puts " "
puts "type 0 to exit "
end
def menu
wines = Bottle.list
second_input = ''
while second_input != 0
puts "<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>"
puts "type the corresponding number to view more wine info"
puts
"__________________________________________________________________"
wines.each do |wine|
puts "#{wine.index}) #{wine.name} #{wine.price}"
end
second_input = gets.chomp.to_i
if second_input > 0 && second_input < 26
find_by_input(second_input)
elsif second_input == 0
exit
second_input = 0
elsif second_input > 25 && second_input != 101
error_1
end
end
puts <<-DOC
the the wine number again
for winemaker notes
DOC
end
def find_by_input(input)
while input != 0
selection = Bottle.find_by_input(input)
puts "NAME: #{selection.name}"
puts "PRICE: $#{selection.price}"
puts "RATING: #{selection.rating}"
puts "________________________________________"
puts " type #{input} again "
puts " for more info "
puts " provided by the winemaker "
# reseting input and extending user control functionality
third_input = ''
third_input = gets.chomp.to_i
if third_input == selection.index
response = Scrape.scrape_page(selection)
view_2(response, third_input)
elsif input == 0
exit
end
end
end
def view_2(response, old_input)
next_input = ''
while next_input != 0
puts "Alcohol Percent: #{response.alcohol_percent}"
puts "Winemaker Notes: #{response.winemaker_notes}"
puts " "
puts "Type #{old_input} again for more!!"
next_input = gets.chomp.to_i
if next_input == old_input
input = 0
next_input = 0
# refacort as it puts out 88 again and should not. Also 0 is not
exiting with correct behavior
# refactor so looking for "#{input}"1 to prevent the recall of
input
more(response)
end
end
end
def more(response)
puts response.more
puts menu
end
def error_1
puts " WHOA coder "
puts "type a better number!"
end
def exit
puts <<-DOC
well that was fun
Thank you for checking out
my first cli program
DOC
end
end ```
```class Page
attr_accessor :alcohol_percent, :price, :name, :origin, :winemaker_notes,
:rating, :more, :obj
##web_pages = []
def self.create_find_by_name(hash)
if answer = ##web_pages.find{ |obj| obj.name == hash[:name]}
answer
else
self.new.create(hash)
end
end
def create(hash)
hash.each do |key, value|
self.send(("#{key}="), value)
end
save
view_more
end
def view_more
##web_pages.last
end
def save
##web_pages << self
end
end
attr_accessor :link, :name, :price, :rating, :index
##bottles = []
def create(hash)
hash.each do |key, words|
self.send(("#{key}="), words )
end
save
end
def save
##bottles << self
end
def self.make_list
##numbered_list = ##bottles.sort{ |x,y| x.price <=>
y.price}.map.with_index(1) do
|w,i| w.index = i
w
end
end
def self.list
##numbered_list
end
def self.find_by_input(input)
a = ##numbered_list.find{ |wine| wine.index == input}
# puts "#{a.name} $#{a.price} rating: #{a.rating}"
# puts "type #{input} again for winemaker notes"
# more = ''
# while more != 0
# more = gets.chomp.to_i
# (input == more) ? (Scrape.scrape_page(a.link)) : (self.list)
# end
end
end
class Scrape
Base = 'http://www.wine.com'
##menu = []
##pages = []
def self.index
index_url = Base + "/list/wine/7155?sortBy=savings&pricemax=90"
if doc = Nokogiri::HTML(open(index_url))
container = doc.css('.prodList')
wines = container.css('.prodItem')
wines.each do |wine|
##menu << {
:link => wine.css('.prodItemInfo_link').attribute('href').value,
:name => wine.css('.prodItemInfo_name').text,
:rating => (wine.css('.averageRating_average').text.to_i) > 0 ?
(wine.css('.averageRating_average').text) : 'no rating',
:price => wine.css('.productPrice_price-saleWhole').text.strip
}
end
##menu.each do |item|
Bottle.new.create(item)
end
else
begin
raise Custom_error
rescue Custom_error => error
puts error.message
end
end
end
def self.scrape_page(wine_obj)
wine_link = wine_obj.link
individual_page = Base + wine_link
docu = Nokogiri::HTML(open(individual_page))
y = docu.css('.viewMoreModule_text')
more = docu.css('.viewMoreModule_text')
##pages << {
:obj => wine_obj,
:name => docu.css('.pipName').text,
alcholo = docu.css('.mobileProdAttrs').css('.prodAlcoholPercent'),
:alcohol_percent => alcholo.css('.prodAlcoholPercent_percent').text,
:price => docu.css('span.productPrice_price-saleWhole').text,
:origin => docu.css('span.prodItemInfo_originText a').text,
:winemaker_notes => docu.css('.viewMoreModule_text').first.text,
:more => y[2].text,
:rating => docu.css('span.averageRating_average').first.text
}
Page.create_find_by_name( ##pages.last )
end
def self.pages
##pages
end
end
When the internet connection is down/too slow the custom error is raised.
When an exception is thrown, the program stops its normal flow. You need to surround the part of the code that can throw an exception with a begin..rescue clause, and attempt to handle it, re-raise it, or raise another exception instead.
In your example, that would be:
begin
Nokogiri::HTML(open(url))
rescue Net::OpenTimeoutError => e
# log the error message if needed, raise your CustomError instead
raise CustomError, e.message
end
You can omit the begin, and put a rescue clause at the end of the method, ruby will interpret this as if the entire method body was wrapped in a begin..rescue block, something like this:
def open_page(url)
return Nokogiri::HTML(open(url))
rescue Net::OpenTimeoutError => e
raise CustomError, e.message
end
Hello I am new at ruby programming.
Ran rubocop inspection in my project and it says:
Method has too many lines. [13/10] def refresh_status
Here is my methods:
def refresh_status
lost = false
in_progress = false
won = false
#bets.each do |bet|
lost = true if bet.result == :lost
if bet.result == :canceled
#to_return /= bet.odd
won = true
end
in_progress = true if bet.result == :in_progress
won = true if bet.result == :won
end
def_result_after_refresh(lost, in_progress, won)
end
def def_result_after_refresh(lost, in_progress, won)
if lost
#result = :lost
elsif in_progress
#result = :in_progress
elsif won
#result = :won
end
end
Can't find a way to make that method shorter, maybe you could help?
You can use some the Enumerable methods.
def refresh_status
#to_return /= #bets.select { |bet| bet.result == :canceled }.map(&:odd).reduce(1, :*)
results = #bets.map { |bet| bet.result == :cancelled ? :won : bet.result }.uniq
#result = case
when results.include?(:lost) then :lost
when results.include?(:in_progress ) then :in_progress
when results.include?(:won) then :won
end
end
I'm new to programming in Ruby and I decided to learn to build a hangman game, but I have a problem when comparing two strings, one that comes from a gets (If I do it for me code works normal) and one that is defined.
this is my codes:
this is my 'main':
require_relative("Ahorcado")
juego = Ahorcado.new()
juego.decirPalabra
while juego.hayVidas?
juego.imprimir
lectura = gets
lectura = lectura.to_s;
juego.preguntar lectura
end
puts juego.resultado
And the Ahorcado.rb
class Ahorcado
def loadVariables
#palabras = ["java","ruby","python","go"]
#adivinados = []
#gano = false
#vidas = 7
end
def initialize
loadVariables();
#palabra = #palabras[rand(#palabras.length)].split("")
puts "Se ha iniciado un juego"
#tamano = #palabra.length
puts "Existen #{#tamano} letras"
iniciar
end
def decirPalabra
puts #palabra
end
def preguntar letra
#vidas -= 1
letra = letra.to_s
temp = #palabra.join
puts temp.eql?(letra) # -> Allways false
if letra == #palabra.join then
#gano = true
puts "gano"
else
for i in 0...#tamano
if letra.eql?(#palabra[i]) then #Allways false
#adivinados[i] = true
#vidas += 1
else
puts "Incorrecto intente otra vez"
end
end
end
end
def comparar letra
#temp = letra;
puts #temp == #palabra[0]
end
def iniciar
for i in (0...#tamano)
#adivinados[i] = false;
end
end
def hayVidas?
return #vidas > 0
end
def resultado
#gano;
end
def imprimir
for i in (0...#tamano)
if #adivinados[i] then
print #palabra[i]+" "
else
print "_ "
end
end
puts
end
end
Thanks for yours answers, and sorry if i wrote bad some sentences, i don't speak english
When you do a "gets", lectura contains newline character in the end. Trying doing a "chomp" on lectura :-
lectura = lectura.chomp
and try again. So that all the newline characters are removed. You can also use "bytes" to see the exact characters in your string for debugging purposes.
puts lectura.bytes
Refer:- http://ruby-doc.org/core-2.0/String.html#method-i-chomp