Ruby Endless Loop - ruby

I am new to Ruby. I have written the code below, its working about 90% except the else statement. The else statement triggers endless loop. I just want it to ask user to try again. Here is my code
puts "Do you want to print something? (Y / N)"
user = gets.chomp.downcase
answer = true
while answer
if user == "y"
puts "Something"
answer = false
elsif user == "n"
puts " "
answer = false
else
puts "Invalid input! Please enter Y or N"
end
end

Somewhat shorter (note user has gone, the answer is now referred to as answer).
answer = ""
until (answer == "y") or (answer == "n")
puts 'Do you want to print something? (Y/N)'
answer = gets.chomp.downcase
end

Once you exit the else, answer is still true. If you want to re-prompt, you can move your puts and user statement into the loop.
Something like this should work.
while true # (alternately) loop do
puts 'Do you want to print something? (Y/N)'
case gets.chomp.downcase
when 'y'
puts 'foo'
break
when 'n'
puts 'bar'
break
else
puts 'Invalid input! Please enter Y or N'
end
end
You can use break to exit out of your loop instead of setting up another variable. Also, this looks like a good use-case for a case statement to have some explicit cases listed.

Related

Different Messages For Different User Inputs

How do I put a message (string) for a specific answer (user input) and another message for another answer? For e.g.
puts "Did You Like My Program?"
feedback = gets
if feedback = "Yes"
puts "We're Glad!"
elsif feedback = "No"
puts "We Will Try To Improve!"
end
What should I change, add, or modify?
Your problem is that, when you compare, you have to use ==, not =.
When you input on command line, you always use Enter. It produces \n at the end of the string. So you need to remove it with chomp.
Also, to filter user input, I suggest this variant:
feedback = nil
until %w[y n].include?(feedback)
puts 'Did You Like My Program? Y/N'
feedback = gets.chomp.downcase
end
if feedback == 'y'
puts "We're Glad!"
else
puts "We Will Try To Improve!"
end
Brief explanation:
The code uses Array#include? and String#downcase.
%w[y n] is equal to ["y", "n"].
The until-loop executes the code while the condition is false.

How to jump to a line in ruby

I'm doing a pwd generator in ruby and when I get to a certain point of the code I need to return back if the user says that he want to retry to generate the pwd.
print "do you want to retry to generate the password? [y/n]"
retrypwd = gets.chomp
if retrypwd == y
(code to jump to some lines ago)
elsif retrypwd == n
print "Ok, It'll be for the next time"
end
The trick is to use a loop and break it or repeat it according to your expectations:
def try_again?
loop do
print "Would you like to try again? Y/N"
again = gets.chomp.capitalize
case (again)
when 'N'
return false
when 'Y'
return true
else
puts "Huh? I don't know what that means."
end
end
end
Then you can incorporate this into your main program:
begin
try_password
end while try_again?
You will keep trying passwords until try_again? returns false, which happens if you type "N".

Enter with no input as a valid boolean

I'm writing some very simple code, asking for confirmation on a text input, and
what I want to do is that if the users simply presses "Enter", make it count as a "yes". For example:
define method
puts "enter some text"
#text= gets.chomp
puts "you entered '#{#text}', is it correct?"
correct = gets.chomp
if correct == 'y' || ''
other_method
else
method
end
end
But when I run it on Ruby, I get the "Warning, literal string in condition", and whatever you enter, calls the "other_method". The solution I found is the following:
define method
puts "enter some text"
#text= gets.chomp
puts "you entered '#{#text}', is it correct?"
correct = gets.chomp
if correct == 'y'
other_method
elsif correct == ''
other_method
else
method
end
end
But it's pretty annoying, I'd rather understand why the first one doesn't work, and how can I make it work using the | |
Thank you!
What the error is saying is that you are supplying a string (literal) inside of a conditional statement by itself. When you do if correct == "y" || "" you're actually telling it if correct == "y" OR "" and just supplying the string by itself is not a condition.
To fix this you'd simply supply the condition after the operator as well as before it. Ruby does not assume you want the same thing to happen after the ||.
Like this:
define method
puts "enter some text"
#text= gets.chomp
puts "you entered '#{#text}', is it correct?"
correct = gets.chomp
if correct == 'y' || correct == ''
other_method
else
method
end
end
Hope this helps. Happy coding
The solution here is to use Ruby's very versatile case statement to set up a number of "cases" you want to test:
puts "you entered '#{#text}', is it correct?"
case (gets.chomp)
when 'y', 'yes', ''
method_a
else
method_b
end
This can be extended to use regular expressions for even more versatility:
case (gets.chomp)
when /\A\s*y(?:es)?\s*\z/i
method_a
else
method_b
end
Where now anything like "y" or "yes" or "Yes " will work.
When you have bunch of if statements all testing the same variable, consider using a case statement to simplify your logic.
Here is another option using Regex (Docs):
puts "enter some text"
#text= gets.chomp
puts "you entered '#{#text}', is it correct?"
correct = gets.chomp
if /^y?$/ =~ correct # This will match 'y' and empty string both
other_method
else
method
end

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.

ruby program basic design explanation

I want to rewrite the following code with the code below, but I am stuck.
def ask question
good_answer = false
while (not good_answer)
puts question
reply = gets.chomp.downcase
if (reply == 'yes' or reply =='no')
good_answer = true
if reply == 'yes'
answer = true
else
answer = false
end
else
puts 'Please answer "yes" or "no"'
end
end
answer
end
Replacement code:
def ask question
puts question
reply = gets.chomp
if (reply == 'yes' or reply == 'no')
puts reply.capitalize
else
puts 'Please enter "yes" or "no"'
#jump the code to like 2 ( but how?)- use while reply != empty & comment the below lines
puts question
reply = gets.chomp
end
end
I want to jump to the main part of program is there any goto, jump or can I call method inside that method?
I want to jump to the main part of program is there any goto, jump or can I call method inside that method?
Yes, it is called a loop, i.e., what you are using in your original code. Why in the world would you want to replace a loop with a goto? Makes no sense.
It can however be simplified. I don't like the checking against 'yes' or 'no', but I also don't have time to restructure your program.
def ask question
while true
puts(question)
reply = gets.chomp.downcase
if reply == 'yes' || reply == 'no'
return reply == 'yes'
else
puts('Please answer "yes" or "no"')
end
end
end
Even if there was a goto statement you shouldn't be using it. Not only is it bad form, but it causes all kinds of headaches for maintainers since your program ends up being hard to follow.
A better approach is to define proper structures for your questions and valid answers, then iterate over those simply, collecting the results into a structure you can use later:
# Auto-flush output buffer
STDOUT.sync = true
questions = [
[ 'Is this a good question?', 'yes', 'no' ],
[ 'Is the sky blue?', 'yes', 'no' ],
[ 'Do hamsters fly?', 'no', 'yes' ]
]
answers_given = [ ]
questions.each do |question, *answers|
print question + ' '
while (true)
answer = gets
answer.chomp!
if (answers.include?(answer))
puts "Thanks!"
answers_given << (answer == answers.first)
break
end
puts "You must answer one of #{answers.join(', ')}!"
print question + ' '
end
end
questions.each_with_index do |(question, *answers), i|
puts "#{question} #{answers_given[i]}"
end
You can try something liek this:
def ask_question
puts('Please answer "yes" or "no"') until (reply = gets.chomp.downcase) =~ /^(yes|no)$/
return reply == 'yes'
end
def ask question
puts question
reply = gets.chomp.downcase
if (reply == 'yes' or reply == 'no')
puts reply.capitalize
else
puts 'Please enter "yes" or "no"'
ask question # this does the looping of loop
end
end
Thanks, and sorry I didn't copy it well from my clipboard last time.

Resources