Ruby if else statement refactoring - ruby

The current code works:
def launched_city(country, city, city_link)
return 'current' if country == 'Malaysia' && ('Kuala Lumpur' == city_link)
return 'current' if country == 'Philippines' && ('Manila' == city_link)
if country == 'Australia'
return 'current' if city == 'Melbourne' && ('Melbourne' == city_link)
return 'current' if city == 'Sydney' && ('Sydney' == city_link)
return 'current' if city == 'Perth' && ('Perth' == city_link)
end
nil
end
but I think it's ugly. Any help?
I tried with case block. It failed with the case statement because I need to check the second statement. I also tried with if elsif else block. It's the same in this case.

COUNTRY_LINKS = { 'Malaysia'=>['Kuala Lumpur'],
'Philippines'=>['Manila'],
'Australia'=>['Melbourne', 'Sydney', 'Perth'] }
def launched_city(country, city, city_link)
if COUNTRY_LINKS.has_key?(country) && COUNTRY_LINKS[country].include? city_link) &&
(country != 'Australia' || city == city_link)
'current'
end
end

Related

Rock paper scissors in Ruby

I have to implement a small part of a Rock, Paper, Scissors game for an assignment. Here is my code:
class RockPaperScissors
# Exceptions this class can raise:
class NoSuchStrategyError < StandardError ; end
def self.winner(player1, player2)
# YOUR CODE HERE
puts "player1 = " + player1[1]
if (player1[1] || player2[1] != 'R') || (player1[1] || player[2] != 'P') || (player1[1] || player2[1] != 'S')
raise NoSuchStrategyError.new("Strategy must be one of 'R','S','P'")
else
if player1[1] == player2[1]
return player1
elsif (player1[1] == 'R' && player2[1] == 'P') || (player1[1] == 'P' && player2[1] == 'S') || (player1[1] == 'S' && player2[1] == 'R')
return player2
else
return player1
end
end
end
def self.tournament_winner(tournament)
# YOUR CODE HERE
end
end
I am using rspec to test out the code and it breaks in both of the below cases. I am assuming that it has to do with where I check to make sure that the input is valid, and even though the input is valid, for whatever reason, the way I am doing the line if (player1[1] || player2[1] != 'R') || (player1[1] || player[2] != 'P') || (player1[1] || player2[1] != 'S') is making the input fail on every case. How can I fix that line so that if the input is valid, then it doesn't raise an error?
Failures:
1) RockPaperScissors game rock breaks scissors [10 points]
Failure/Error: raise NoSuchStrategyError.new("Strategy must be one of 'R','S','P'")
RockPaperScissors::NoSuchStrategyError:
Strategy must be one of 'R','S','P'
# ./lib/rock_paper_scissors.rb:11:in `winner'
# ./spec/rock_paper_scissors_spec.rb:10:in `block (3 levels) in <top (required)>'
EDIT: player1 and player2 are arrays with format ["playername", "move"] with the move being either R,S or P for rock, scissors or paper

How do I write a complex multi-line if condition in Ruby?

How do I write this multi-line, complex condition if statement in Ruby?
if ( (aa != nil && self.prop1 == aa.decrypt)
|| (bb != nil && self.prop2 == bb.decrypt)
) && (self.id.nil? || self.id != id)
return true
end
I'm getting Syntax error; unexpected tOROP.
In Java, I could write
if (
( (aa != null && aa.prop1.equals(aa.decrypt()))
|| (bb != null && bb.prop2.equals(bb.decrypt()))
)
&& (this.id != id)
) {
return true;
}
The short answer is the operator needs to be at the end of the line in order to tell Ruby to continue reading the next line as part of the statement, so this would work:
if ( (aa != nil && self.prop1 == aa.decrypt) ||
(bb != nil && self.prop2 == bb.decrypt) ) &&
(self.id.nil? || self.id != id)
return true
end
That being said, you can probably reduce the logic by throwing exceptions based on input values, and removing some redundant checks (I'm making some jumps here about what your variables will look like, but you get the idea.)
raise 'aa must support decrypt' unless aa.respond_to? :decrypt
raise 'bb must support decrypt' unless bb.respond_to? :decrypt
if prop1 == aa.decrypt || prop2 == bb.decrypt
if self.id != id
return true
end
end
You need to escape whitespace with the backslash character, it's ugly but you need it if you want to split conditions to multiple lines. Either that or leave the boolean operator on the previous line. So either of these will work:
if ( (aa != nil && self.prop1 == aa.decrypt)\
|| (bb != nil && self.prop2 == bb.decrypt)\
) && (self.id.nil? || self.id != id)
return true
end
or:
if ( (aa != nil && self.prop1 == aa.decrypt) ||
(bb != nil && self.prop2 == bb.decrypt)) &&
(self.id.nil? || self.id != id)
return true
end
Personally I usually decide to put each or all conditions in a method that self documents what's being decided:
def everythings_cool?
( (aa != nil && self.prop1 == aa.decrypt) ||
(bb != nil && self.prop2 == bb.decrypt)) &&
(self.id.nil? || self.id != id)
end
then:
if everythings_cool?
# do stuff

Paper, Scissor, Rock game in Ruby. When an array changes data, it changes the data of another array (¿?)

This is my code:
class RockPaperScissors
# Exceptions this class can raise:
class NoSuchStrategyError < StandardError
end
def self.winner(player1, player2)
if ((player1[1] == 'R') && (player2[1] == 'S') ||
(player1[1] == 'S') && (player2[1] == 'P') ||
(player1[1] == 'P') && (player2[1] == 'R'))
return player1
elsif ((player1[1] == 'R') && (player2[1] == 'P') ||
(player1[1] == 'S') && (player2[1] == 'R') ||
(player1[1] == 'P') && (player2[1] == 'S'))
return player2
elsif ((player1[1] == 'R') && (player2[1] == 'R') ||
(player1[1] == 'S') && (player2[1] == 'S') ||
(player1[1] == 'P') && (player2[1] == 'P'))
return player1
end
end
def self.tournament_winner(tournament)
player1 = Array.new
player2 = Array.new
nextround = Array.new
while tournament.length != 1 do
tournament.each_with_index {|item, index|
if (index%2!=0)
player2[0] = item[0]
player2[1] = item[1]
elsif (index%2 ==0)
player1[0] = item[0]
player1[1] = item[1]
else
puts 'bananas'
end
if (index%2!=0)
nextround[(index-1)/2] = winner(player1, player2)
end
}
tournament=nextround
end
return tournament
end
end
RockPaperScissors.tournament_winner([["num1", "R"], ["num2", "P"], ["num3", "P"], ["num4", "R"]])
Well, the last line is an execution launch. This code makes a tournament of rock, paper scissors. It takes as input an array of arrays with each character and its attack, and it has to return the array with the champion and its attack.
The tournament is num1 vs num2 (num2 wins), and num3 vs num4 (num3 wins). Then the final is Num2 vs Num3, and in this stablemate wins the first guy in the array (Num2).
It seems overcomplicated because the code has to work with any number of characters, as long as their number is base2 (2, 4, 8, 16 characters..., etc).
My problem is next (debug the code and you will see). When it changes the value of the array 'Player1' or 'Player2', it also changes the value in the array 'nextround', even if it is not in that line!
That is not suppose to happen!
By the way, I am learning Ruby so it may be a really stupid failure.
why does this need to be true?
"It seems overcomplicated because the code has to work with any number of characters, as long as their number is base2 (2, 4, 8, 16 characters..., etc)."
Rather having player1 and player2 be arrays, I would rewrite them to be instances of a class Player. Then write methods in the Player class so you can call player1.hand and it returns 'S' || 'R' || 'P'
that way you can store how many wins a player has on the player object,
things I'd look into learning more about
case/when statements
the special initialize method
attrs_accessor (used for making data accessible across classes)
modules
also i've seen it done and i may be wrong on this, but generally you don't put classes inside classes.

Rails 3 validation in model failure

I have a validate_completion method defined in my task.rb model. The Pseudo logic should be
if no hazards exist
date_completed = Date.today
elsif any hazard exists with a risk_total > 1000
date_completed = nil
else any hazard that exists has a risk_total =< 1000
date_complete = Date.today
end
The code looks like as follows.
def validate_completion
if self.date_completed.nil?
if self.Biohaz_exist == "No"
if self.Hazmat_exist == "No"
if self.Fire_exist == "No"
if self.Hazengy_exist == "No"
if self.Tool_exist == "No"
if self.Rad_exist == "No"
if self.Laz_exist == "No"
if self.Mag_exist == "No"
if self.Ergo_exist == "No"
if self.Mechand_exist == "No"
if self.Road_exist == "No"
if self.Fall_exist == "No"
if self.Hazatm_exist == "No"
if self.Noise_exist == "No"
if self.Ovrhead_exist == "No"
if self.Cut_exist == "No"
if self.Temp_exist == "No"
if self.Access_exist == "No"
if self.Cowrkr_exist == "No"
if self.Lonewrkr_exist == "No"
self.date_completed = Date.today
elsif self.Biohaz_exist == "Yes" and self.Biohaz.risk_total > 1000
self.date_completed = nil
elsif self.Hazmat_exist == "Yes" and self.Hazmat.risk_total > 1000
self.date_completed = nil
elsif self.Fire_exist == "Yes" and self.Fire.risk_total > 1000
self.date_completed = nil
elsif self.Hazengy_exist == "Yes" and self.Hazengy.risk_total > 1000
self.date_completed = nil
elsif self.Tool_exist == "Yes" and self.Tool.risk_total > 1000
self.date_completed = nil
elsif self.Rad_exist == "Yes" and self.Rad.risk_total > 1000
self.date_completed = nil
elsif self.Laz_exist == "Yes" and self.Laz.risk_total > 1000
self.date_completed = nil
elsif self.Mag_exist == "Yes" and self.Mag.risk_total > 1000
self.date_completed = nil
elsif self.Ergo_exist == "Yes" and self.Ergo.risk_total > 1000
self.date_completed = nil
elsif self.Mechand_exist == "Yes" and self.Ergo.risk_total > 1000
self.date_completed = nil
elsif self.Road_exist == "Yes" and self.Ergo.risk_total > 1000
self.date_completed = nil
elsif self.Fall_exist == "Yes" and self.Fall.risk_total > 1000
self.date_completed = nil
elsif self.Hazatm_exist == "Yes" and self.Hazatm.risk_total > 1000
self.date_completed = nil
elsif self.Noise_exist == "Yes" and self.Noise.risk_total > 1000
self.date_completed = nil
elsif self.Ovrhead_exist == "Yes" and self.Ovrhead.risk_total > 1000
self.date_completed = nil
elsif self.Cut_exist == "Yes" and self.Cut.risk_total > 1000
self.date_completed = nil
elsif self.Temp_exist == "Yes" and self.Temp.risk_total > 1000
self.date_completed = nil
elsif self.Access_exist == "Yes" and self.Access.risk_total > 1000
self.date_completed = nil
elsif self.Cowrkr_exist == "Yes" and self.Cowrk.risk_total > 1000
self.date_completed = nil
elsif self.Lonewrkr_exist == "Yes" and self.Lonewrkr.risk_total > 1000
self.date_completed = nil
else
self.date_completed = Date.today
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
end
As is right now if no hazards exist, it successfully sets the date to today. And if I then add a hazard it effectively switches the date back to nil. However, If one hazard exists and it has a risk_total below 1000 the date remains nil.
"Well, given that your hazards are statically defined and not in the database, you could do something like this:
#definition of all the hazard
hazards = [:Fire, :Road, :Fall]
def validate_completion
# find all the hazards that exist
exists = hazards.select { |hazard| self.send("#{hazard.to_s}_exist") }
# find if at least one high risk hazard exists
high_risk_total = exists.detect {|hazard| self.send("#{hazard.to_s}_risk_total") > 1000 }
# find if at least one low rick hazard exists
low_risk_total = exists.detect {|hazard| self.send("#{hazard.to_s}_risk_total") <= 1000 }
# validation logic here
end
You can get by with this logic, but it might be significantly easier to make your hazards a database table and use ActiveRecord associations and queries to simplify this.

Ruby: Undefined method error on method called AFTER definition

I am not sure what's happening here...but say I do this:
def who_wins?(choice1, choice2)
if (choice1 == 'R' && choice2 == 'S') || (choice1 == 'S' && choice2 == 'P') || (choice1 == 'P' && choice2 == 'R')
return choice1
elsif choice1 == choice2
return "tie"
else
raise NoSuchStrategyError
end
end
won_wins?('R', 'P')
It gives me the following error:
NoMethodError: undefined method `won_wins?' for main:Object
at top level in my-file.rb at line 25
Why would it do that, even though I am calling the method AFTER the definition?
You typed won_wins? and not who_wins?

Resources