Ruby - How to Execute something and then Break inside IF block? - ruby

EDIT: Someone pointed out that I needed to break correctly so I am editing the question
Scenario:
Please see following code:
print "UserID: "
uid = $stdin.gets.chomp
print "Password: "
pwd = $stdin.gets.chomp
usr_inp = "#{uid};#{pwd}"
login_status = -1
# login_info.txt - "#{userid};#{password}" - format
File.open(File.join(File.dirname(__FILE__), 'login_info.txt'), "r") do |f|
f.each_line do |line|
puts line
if (line.chomp == usr_inp)
login_status = 1
elsif (line.chomp != usr_inp && line.include?(uid)) #case a person inputs invalid password
login_status = 0
elsif (line.chomp != usr_inp && !(line.include?(uid))) #case a person inputs an invalid id
login_status = 2
end
end
end
if (login_status == 1)
puts "\nLogged in successfully: #{uid}"
elsif (login_status == 2)
puts "\nSorry, that Employee does not exist."
elsif (login_status == 0)
puts "\nLogin failed.\nPlease check credentials."
end
Problem:
break if (condition) exists in Ruby. But I don't waht that.
I want to do something like:
if (condition x)
(do something)
break
elsif (condition y)
(do something else)
break
else
(whatever)
end
Maybe I am not understanding how ruby code works. Whenever I try to put the break as I want to use it, it associates with the next elsif.
Please help.

It depends on what you need and where you need it.
A script like this:
condition = 1
case condition
when 1
puts 'one'
break
when 2
puts 'two'
else
puts 'Other %s' % condition
end
puts 'end'
has a syntax error. break leaves a loop and there is no loop.
But with a loop, this works:
[1,2,3].each{|condition|
case condition
when 1
puts 'one'
break
when 2
puts 'two'
else
puts 'Other %s' % condition
end
puts 'end'
}
puts 'very end'
The output is:
one
very end
You see, the loop is stopped.
If you want to continue the loop with the next element, you need next (sorry, I'm just not aware what break is doing really in Java - it's been a long time since my last Java program):
[1,2,3].each{|condition|
case condition
when 1
puts 'one'
next
when 2
puts 'two'
else
puts 'Other %s' % condition
end
puts 'end %s' % condition
}
puts 'very end'
The result:
one
two
end 2
Other 3
end 3
very end
When you are not inside a loop (like in your code snippet), you may use exit (leave the program) or return (leave a method).

Related

gets.chomp three times in a row to exit

The task is taken from "Learn to Program" by Chrise Pine. The program is called 'Deaf Grandma'. Here's the task: "whatever you type, grandma (the program) should respond with this:
`HUH?! SPEAK UP, SONNY!`
unless you shout it (type in all capitals). In this case she responds with:
`NO, NOT SINCE 1938!`
Have Grandma shout a different year each time, maybe any year at random between 1930 and 1950. You have to shout BYE three times in a row. Make sure to test your program: if you shout
BYE three times but not in a row, you should still be talking to
Grandma."
Now, everything looks fine to me, except I didn't get where to put gets.chomp 3 times to exit a program. Eventually, I came up with this:
speak = gets.chomp
while speak != 'BYE'
puts 'HUH?! SPEAK UP, SONNY!'
if speak == speak.upcase
puts 'NO, NOT SINCE ' + (1930 + rand(20)).to_s + '!'
else repeat = gets.chomp
end
end
But in this case if I type BYE grandma still asks me:
`HUH?! SPEAK UP, SONNY!`
My question is: how can I properly make the program exit after I type BYE three times in a row?
Have a look at this, I've made some changes though. But should give you the expected output.
bye_count = 0
while true
speak = gets.chomp
if speak == 'BYE'
bye_count +=1
bye_count == 3 ? break : next
end
bye_count = 0 # Resets count
if speak == speak.upcase
puts 'NO, NOT SINCE ' + (1930 + rand(20)).to_s + '!'
else
puts 'HUH?! SPEAK UP, SONNY!'
end
end
You've not added anywhere in your code that using 'bye' 3 times will exit the program.
while bye < 3
Try looking at your code again and implementing the changes to exit after 3 byes.
Here's another way:
responses = ["", "", ""]
loop do
speak = gets.chomp
responses.shift
responses << speak
break if responses.all? { |r| r == "BYE" }
if speak == speak.upcase
puts 'NO, NOT SINCE ' + (1930 + rand(20)).to_s + '!'
else
puts 'HUH?! SPEAK UP, SONNY!'
end
end
Alternatively,
break if responses.uniq == ["BYE"]
puts "what can i do for your son?"
a=0
while a != 3
n= gets.chomp
if n.include? 'BYE'
puts "NO NOT SINCE #{rand(1897..1930)}".chomp
a = (a + 1)
end
if n != n.upcase
puts 'HUH?! SPEAK UP, SONNY!'.chomp
a=0
end
if n == n.upcase and n != 'BYE'
puts "NO NOT SINCE #{rand(1897..1930)}".chomp
a=0
end
end

While loops in Ruby

I want to exit only after I say 'BYE' three consecutive times. It is about a deaf grandma who will only hear things if the letters are all in caps.
I tried having three different variables, but that did not work. My code is below and it works when I say 'BYE' only once.
whatSaid = 'Hi!'
while (whatSaid != 'BYE')
whatSaid = gets.chomp
if (whatSaid == 'BYE')
puts 'FINE! LEAVE YOUR POOR GRANDMA TO DIE.'
else
if (whatSaid == whatSaid.upcase)
puts 'NO, NOT SINCE ' + rand(1930...1951).to_s + '!'
else
puts 'HUH!? SPEAK UP, SONNY!'
end
end
end
why not a variable called bye_count - start it out at 0 and increment it each time you hear 'BYE' - and when that gets to 3, exit
eg
what_said = 'Hi!'
bye_count = 0
while (bye_count < 3)
what_said = gets.chomp
if (what_said == 'BYE')
bye_count += 1
puts 'FINE! LEAVE YOUR POOR GRANDMA TO DIE.'
else
if (what_said == what_said.upcase)
puts 'NO, NOT SINCE ' + rand(1930...1951).to_s + '!'
else
puts 'HUH!? SPEAK UP, SONNY!'
end
end
end
Unrelated note: ruby generally uses underscore_case for variable names, rather than camelCase :)

how to break a loop?

when 1
add(first_number, second_number)
begin
print "Calculate again? [y/n]: "
response = gets.chomp
if response.downcase =~ /[n]/
break
elsif response.downcase =~ /[^ny]/
puts "please input y or n"
else response.downcase =~ /[y]/
puts "yay"
end
end
EDIT
Profuse apologies. This is a changed version.
My question as it stands now is how do I keep repeating the question of 'please input y or n' when a user chooses to enter other than those characters?
the begin <code> end while <condition> is regretted by Ruby's author Matz. Instead, he suggests to use Kernel#loop,
e.g.
The while statement modifier normally checks the condition before entering the loop. But if the while statement modifier is on a begin ... end statement, then it loops at least once. Same with the until statement modifier.
Example of while
val = 0
begin
val += 1
puts val
end while val % 6 != 0
Example of until
val = 0
begin
val += 1
puts val
end until val % 6 == 0
As you wants to know about breaks..
Example of break unless
val = 0
loop do
val += 1
puts val
break unless val %6 != 0
end
Example of break if
val = 0
loop do
val += 1
puts val
break if val %6 == 0
end
Output:
Above all four of these examples print the numbers 1, 2, 3, 4, 5, 6.
I hope this answer makes you clear..
For your reference I have found very nice Example of Code about Table of Contents You can Execute(Run) that code here online and check the result. If my answer somehow helps you then you can accept as answered. :)
I would probably extract the confirmation into a method, something like:
def confirm(message)
loop do
print "#{message} [y/n]: "
case gets.chomp
when 'y', 'Y' then
return true
when 'n', 'N'
return false
else
puts 'please input y or n'
end
end
end
And use it like:
loop do
puts 'Calculating...'
sleep 5 # calculation
puts '42'
break unless confirm('Calculate again?')
end
Usage:
$ ruby test.rb
Calculating...
42
Calculate again? [y/n]: maybe
please input y or n
Calculate again? [y/n]: y
Calculating...
42
Calculate again? [y/n]: n
$
You should run your loopy method in a separate thread, and then
kill that thread when the user presses any key on the keyboard ...

Ruby: passing array items into a case statement

I am attempting to pass an array into a case statement so I can read the array elements as commands. Unfortunately, it seems that it is not working and the program jumps to the else statement.
def input_console()
quit = 0
puts "Tell me what you want to do:"
loop do
print "\n >>> "
input = gets.chomp
sentence = input.split
case sentence
when sentence[0] == "go" && sentence[1] == "to"
puts sentence[2]
when sentence[0] == "quit"
quit = 1
else
puts "No le entiendo Senor..."
end
break if quit == 1
end
end
This piece of code returns "No le entiendo Senor..." whatever you introduce. I expected to get the place I want to go after stating "go to Wherever".
Please, ¿may you help me?
You can do this by making your case statement independent of a specific variable.
change
case sentence
to
case
Here is an example of how you would use case-when while checking for values in the array.
numbers = [1,2,3]
case
when a[1] == 2
p "two"
else
p "nothing"
end
So in your case you can just say
case
when sentence[0] == "go" && sentence[1] == "to"
puts sentence[2]
when sentence[0] == "quit"
quit = 1
else
puts "No le entiendo Senor..."
end
Why are you making this a case statement? (And why is quit a Fixnum rather than a boolean? Actually, why have it at all?)
while true
# ... prompt and get input ...
if sentence[0] == "go" && sentence[1] == "to"
puts sentence[2]
elsif sentence[0] == "quit"
break
else
puts "No le entiendo Senor..."
end
end
You could use regular expressions. Something like this:
case gets
when /\Ago to (.*)\Z/
puts $1
when /\Aquit\Z/
# handle quit
else
puts "No le entiendo Senor..."
end
\A matches the beginning of string and \Z matches just before the trailing newline, so you don't need chomp.

Is there a way to 'cd ..' up a nested "if" statement tree?

I'm curious if there's a way to have the program go back up the if statement stack?
Ideally, the program would return to line 2 and prompt the user for the input variable, then continue to evaluate like it did the first time. Think of it like a cursor in a text editor, I just want to move it from either of those two comments back up to line 2. The two places of interest are commented out below:
while true
input = gets.chomp
if input != input.upcase
puts "HUH?! SPEAK UP, SONNY!"
elsif input == 'BYE'
puts "HUH?! SPEAK UP, SONNY!"
input = gets.chomp
if input == 'BYE'
puts "HUH?! SPEAK UP, SONNY!"
input = gets.chomp
if input == 'BYE'
puts "GOOD BYE!";
break
else
# return to top-level if statement
end
else
# return to top-level if statement
end
else
random_year = rand(1930..1950)
puts "NO, NOT SINCE #{random_year}!"
end
end
In the code you show, you don't need to do anything to make the flow of execution go back to line 2. Just omit the else clauses in the two places you marked. The flow of execution will drop down to the bottom of the while loop, then loop back to the top, then go back to line 2.
You need to use a while statement to set a condition flag and check it, which will loop back to the while statement if you don't change the flag:
flag = 0
while flag1 == 0
if var = "string"
then ...statements...
flag1 = 1 ; this allows us to break out of this while loop
else ...statements...
end
end
If flag1 is not 0 at the end of the while statement, the while statement will loop back. For two such conditions, you need to nest the while loops. You might have to re-order your statements to make multiple while loops work this way.
You can avoid this level of neasted ifs with:
byecount = 0
while byecount < 3
input = gets.chomp
if input == "BYE"
byecount += 1
next
else
byecount = 0
end
if input != input.upcase
puts "HUH?! SPEAK UP, SONNY!"
else
puts "NO, NOT SINCE #{rand(1930..1950)}!"
end
end
puts "GOOD BYE!"
Or you can write a catch..throw flow structure. (Really.. if you need to use it, something is wrong with your design)
catch :exitloop do
while ...
if ...
if ...
if ...
throw :exitloop
end
end
end
end
end
Here's how I'd write a similar exercise:
BYE = 'BYE'
HUH = "HUH?! SPEAK UP, SONNY!"
loop do
input = gets.chomp
if input != input.upcase
puts HUH
next
end
if input != BYE
random_year = rand(1930..1950)
puts "NO, NOT SINCE #{random_year}!"
next
end
puts HUH
input = gets.chomp
if input == BYE
puts HUH
input = gets.chomp
if input == BYE
puts "GOOD BYE!";
break
end
end
end
I used loop instead of while. Matz, the main man for Ruby, recommends loop. See "Is there a “do … while” loop in Ruby?" for further discussion about it.

Resources