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
Related
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.
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.
I have a program that displays a numbered list and asks the user to input either a number or name from the list, and loops a block until the user enters "exit", after which it ends.
I want to add a line or two that puts an error message like, "Sorry, I don't seem to understand your request" if the user inputs something that is not on the list (name/number) and is not the word "exit".
I can't seem to figure it out. Any advice? My current code is below.
def start
display_books
input = nil
while input != "exit"
puts ""
puts "What book would you more information on, by name or number?"
puts ""
puts "Enter list to see the books again."
puts "Enter exit to end the program."
puts ""
input = gets.strip
if input == "list"
display_books
elsif input.to_i == 0
if book = Book.find_by_name(input)
book_info(book)
end
elsif input.to_i > 0
if book = Book.find(input.to_i)
book_info(book)
end
end
end
puts "Goodbye!!!"
end
Seems that you should add an elsif statement in this if:
if book = Book.find_by_name(input)
book_info(book)
elsif input != 'exit'
puts "Sorry, I don't seem to understand your request"
end
A good template for an interpreter is to build around Ruby's very capable case statement:
loop do
case (gets.chomp.downcase)
when 'list'
display_books
when /\Afind\s+(\d+)/
if book = Book.find($1.to_i)
book_info(book)
end
when /\Afind\s+(.*)/
if book = Book.find_by_name($1)
book_info(book)
end
when 'exit'
break
else
puts "Not sure what you're saying."
end
end
Although this involves regular expressions, which can be a bit scary, it does give you a lot of flexibility. \A represents "beginning of string" as an anchor, and \s+ means "one or more spaces". This means you can type in find 99 and it will still work.
You can create a whole command-line interface with it if you take the time to specify the commands clearly. Things like show book 17 and delete book 17 are all possible with a bit of tinkering.
I have been trying to make a while loop in ruby that responds to user input.
What is supposed to happen is that when a user inputs the word "Omega" correctly it ends the loop and displays a message, if the word "hint" is entered a message is displayed and the loop repeats, and anything else will have a "try again" message displayed. What is happening is that regardless of what is entered, the loop just asks the original question.
Can anyone find what is wrong with my code, thank you
#GateOneLocked = true
GateOnePassword = String.new('Omega')
GateOneHint= String.new('hint')
#Omega is supposed to be the correct password
while (#GateOneLocked == true) do
puts 'What is the password?'
passwordEntered = gets.to_s
if (#passwordEntered == #GateOnePassword)
#GateOneLocked == false
else if (#passwordEntered != #GateOneHint)
puts "This is a hint: the password is 'Omega'"
puts " "
puts " "
else
puts "wrong password, try again"
puts " "
puts " "
end
end
end
puts 'You entered the correct password!'
instead #GateOneLocked == false should be #GateOneLocked = false
addiotional remarks:
in ruby variable names follow different conventions than C#/Java, instead of
GateOneLocked devs write gate_one_locked
no need to write String.new, variable = "your_string" is enough (GateOnePassword = 'Omega')
while(#GateOneLocked) is enough - no need to check whether it's == true
I made several fixes to your code. I changed the else if to elsif and added # to the variable references that were missing it so that your code is consistent. (I'd actually ditch them all unless you're using this code in a class.) I changed your #GateOneLocked == false to use the assignment operator instead of the comparison operator. Most importantly, perhaps, I added a chomp call that will remove the \n (new line character) from your user's input. Also, I changed the comparison in the elsif to == so that your user can request a hint, which is what I think you intended.
#GateOneLocked = true
#GateOnePassword = String.new('Omega')
#GateOneHint= String.new('hint')
#Omega is supposed to be the correct password
while (#GateOneLocked == true) do
puts 'What is the password?'
#passwordEntered = gets.chomp.to_s
if (#passwordEntered == #GateOnePassword)
puts "abc"
#GateOneLocked = false
elsif (#passwordEntered == #GateOneHint)
puts "This is a hint: the password is 'Omega'"
puts " "
puts " "
else
puts "wrong password, try again"
puts " "
puts " "
end
end
puts 'You entered the correct password!'
I know you can use the case statement without a target object, like so:
case
when condition1
do_something1
when condition2
do_something2
else
do_something_else
end
This is equivalent to:
if condition1
do_something1
elsif condition2
do_something2
else
do_something_else
end
Is there any reason the case expression allows being used with no target object? Are there any situations where one would want to use the case expression that way?
It may be used to check multiple expressions. Consider this example:
print "Enter first string: "
some_string = gets.chomp
print "Enter second string: "
some_string1 = gets.chomp
puts case
when some_string.match(/\d/)
'String has numbers'
when some_string1.match(/[a-zA-Z]/)
'String has letters'
else
'String has no numbers or letters'
end
Here, you have to check two different variables. Maybe the experts have some different opinion.
There's actually no difference, an empty case statement won't call === since there's nothing to call. Example:
class CaseExample
def ===(other)
puts "received #{other}"
super(other)
end
end
When called like this:
case
when CaseExample.new()
puts "got here"
end
Will print:
"got here"
While:
case "me"
when CaseExample.new()
puts "got here"
end
It will print:
"received me"
I'd rather go for the if/elsif if there isn't a case object to begin with since the intention is going to be clearer.