If i give input as 1 or 2, regardless of that program goes in default. Tried comparing input with "1" and 1 both. Same result.
My first Ruby program, plz excuse for naivety.
$choice
def getInfo
puts "Info"
end
def getMoreInfo
puts "MoreInfo"
end
def switch
if $choice == "1" #intentionally in ""
getInfo
elsif $choice == 2 #intentionally without ""
getMoreInfo
else
puts "default"
end
end
def callMainMenu
puts "Choose the operation:"
puts "[1] Get some Info"
puts "[2] Get some moreInfo"
$choice=gets
$choice.chomp
end
callMainMenu
switch
You need to use the destructive version of chomp if you're going to assign it like that.
$choice.chomp!
Or
$choice = $choice.chomp
In order to debug this, what I'd do is add puts $choice.inspect at the beginning of your switch method to see exactly what's in the variable. That said, I believe the problem here is that you're calling $choice.chomp instead of $choice.chomp!. The former will return the result, and the latter will change the variable in place.
When you change $choice.chomp to $choice.chomp! and get rid of the // (change those to #), then you'll have something working. Keep refining it , it is not perfect yet.
Use $choice.chomp!. chomp without ! does not alter $choice. It returns a new string. This a naming convention in Ruby.
Related
I want to recall the case until user writes a or b. I do not want to use "case"
particularly.
I just want to get input from user but not geting something else. If he writes something else, he should need to write until he writes a or b.
str = gets.chomp.to_s
case str
when "a"
print "nice a"
when "b"
puts "nice b"
else
puts "please do it again"
end
class person
attr_accessor :name , :surname #and other attributes
end
#There will be a method here and it will run when the program is opened.
#The method will create the first object as soon as the program is opened.
#The new object that the user will enter will actually be the 2nd object.
puts "What do you want to do?
add
list
out"
process = gets.chomp.to_s
case process
when "add"
#in here user will add new objects of my class
when "list"
#in here user will show my objects
when "out"
puts "Have a nice day"
else
puts "please do it again"
end
In fact, if you look at it, many actions will be taken as a result of the user entering the correct input. what I want to tell is more detailed in this example. According to the input of the user, there will be actions such as calling methods, adding objects, etc.
I wrote most of the code on my computer. But still I couldn't solve my first problem.
Use Kernel#loop
There are a lot of ways to solve this problem, but let's start with a simple Kernel#loop wrapper around your existing code, as that's probably the easiest path forward for you.
loop do
str = gets.chomp.to_s
case str
when "a"
print "nice a"
when "b"
puts "nice b"
else
puts "please do it again"
# restart your loop when not "a" or "b"
next
end
# exit the loop if else clause wasn't triggered
break
end
Use until Control Expression
The loop construct above is pretty straightforward, but it requires you to think about where you need next and break statements for flow control. My own instinct would be to simply call a block until it's truthy. For example, the core logic could be shortened to:
str = nil; until str =~ /a|b/i do str = gets.chomp end; p str
This is a lot shorter, but it's not particularly user-friendly. To leverage this approach while making the solution more communicative and error-resistant, I'd refactor the original code this way:
# enable single-character input from console
require 'io/console'
# make sure you don't already have a value,
# especially in a REPL like irb
str = nil
until str =~ /a|b/ do
printf "\nLetter (a, b): "
str = STDIN.getch.downcase
end
puts "\nYou entered: #{str}"
While not much shorter than your original code, it handles more edge cases and avoids branching. It also seems less cluttered to me, but that's more a question of style. This approach and its semantic intent also seem more readable to me, but your mileage may legitimately vary.
See Also
IO::Console
Control Expressions
"I just want to do something until something else happens" is when you use some sort of while loop.
You can do this:
while true
str = gets.chomp
break unless str == 'a' || str == 'b'
puts "please do it again"
end
You can also use loop do:
loop do
str = gets.chomp
break unless ['a', 'b'].include?(str)
puts "please do it again"
end
puts "Nice #{str}."
Rubyists tend to prefer loop do over while true. They do pretty much the same thing.
One more thing. There's a simpler way to write out arrays of strings:
loop do
str = gets.chomp
break unless %w(a b).include?(str)
puts "please do it again"
end
puts "Nice #{str}."
It doesn't look a whole lot simpler, but if you have, say, 10 strings, it's definitely quicker to type in when you don't have to use all those quotation marks.
As your intuition was telling you, you don't need to use the case statement at all. Like trying to kill a flea with a sledgehammer. The most concise way to do your check is to check whether the input character is included in an array of the desired characters.
I have a small code for determining the number of hours per year.
What I am looking for is for a Ruby way to allow different user's input options for all possible valid answer stored in an array
to check if the user provided a valid option by calling include? on the array.
When year consist of 52 weeks.
Week consists of 7 days.
Day consists of 24 hours
My problem comes up when trying to pass different answers for the gets method such as follows:
if answer == "yes" || "yup" || "yeah" || "positive";
if answer == ("yes", "yup", "yeah", "positive")
if answer == ["yes" or "yup" or "yeah" or "positive"]
I receive an error which I couldn't solve
answer = gets.chomp
if answer == "yes" or "yup" or "yeah" or "positive"
puts "Good!"
puts desc_text
my_var = gets.chomp.to_i
if my_var == 3736
puts good_text
else
puts wrong_text
puts bad_text
end
elsif answer == [ "no" || "nop" || "nay || ""negative" ]
puts bad_text
else
puts yes_no
end
I'd like to pass different answer options such as yes, yup, yeah, positive instead of just enclose me to a yes and/or no answer
A more idiomatic Ruby way of allowing for these different user options would be to have all possible valid user input stored in an array, then checking if the user provided a valid option by calling include? on the array. This way, you can update the array with more possible options at a later time. Generally arrays like this are stored as constants, though you can also store them as local variables. I find that for a script like this, variables are fine, but if I'm writing a larger program and I need arrays like this (for example, arrays that specify valid options) in a class, then I use constants to make it easy for other contributors to find them. Another option yet would be to have a configuration file (can be a Ruby file, yaml file, JSON file...) that defines valid options, and then you can load this file when executing your program.
Here is an example of what I mean:
VALID_AFFIRMATIVE_ANSWERS = %w(yes yup yea positive)
VALID_NEGATIVE_ANSWERS = %w(no not nay negative)
answer = gets.chomp
if VALID_AFFIRMATIVE_ANSWERS.include?(answer)
puts "Good!"
puts desc_text
my_var = gets.chomp.to_i
if my_var == 3736
puts good_text
else
puts wrong_text
puts bad_text
end
elsif VALID_NEGATIVE_ANSWERS.include?(answer)
puts bad_text
else
puts yes_no
end
I'm not sure what errors you're receiving, but I'm not sure if you're ever defining some of these variables (for example desc_text etc.).
if code is excetly as you write above your issue is in line written below
elsif answer == [ "no" || "nop" || "nay || ""negative" ]
although it won't work , so the solution for you would be like below
def process_positive_response
my_var = gets.chomp.to_i
if my_var == 3736
puts good_text
else
puts wrong_text
puts bad_text
end
end
answer = gets.chomp
case answer
when 'yes','yup','yeah','positive'
puts "Good!"
puts desc_text
process_positive_response
when 'no', 'nop', 'nay', 'negative'
puts bad_text
else
puts yes_no
end
first why write so much conditions when ruby already does that for you with case statement, and second distribute your code in chunks so it will make your code more traceable.
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 am new to Ruby.
I need to make this script work:
puts "Do you like cats?"
ask = gets
def ask(n)
if ask == yes
return "I do too"
end
if ask == no
return "Dogs are better"
end
end
puts "#{ask(n)}"
Error message is :
pracif.rb:15:in <main>': undefined local variable or methodn' for
main: Object (NameError)
Here's a script that would work for you :
puts "Do you like cats?"
answer = gets
def ask(n)
if n == 'yes'
return "I do too"
end
if n == 'no'
return "Dogs are better"
end
end
puts ask(answer.downcase.chomp)
Explaination
As the error said you were trying to pass in a variable n which was not defined
Secondly you have a method name ask same as variable name. I've renamed the variable to answer instead
Thirdly, enclose yes and no in quotes
And finally, since you are using gets a \n gets appended like yes\n so none of your conditions would match. So i've used chomp to remove \n. And also used downcase to make input case insensitive.
EDIT
As mentioned by #Jordan in the comments, there is no reason to use string interpolation for the puts statement. So it's enough to call the method directly.
There are a bunch of issues with your code. Try something more like:
def reply(response)
return 'I do too' if response == 'yes'
return 'Dogs are better' if response == 'no'
'Invalid response!'
end
puts 'Do you like cats?'
response = gets().chomp()
puts reply(response)
Pay attention to the variable names. If you keep them descriptive, it is easier to spot mistakes.
Your script has no n local variable defined that you are passing to your ask(n) method at the end.
Rename your ask variable that your script gets from user to answer for example and pass it to your ask method at the end like so:
Updated code to fix other problem I did not see in the first run.
puts "Do you like cats?"
answer = gets.chomp
def ask(n)
(n == 'yes') ? "I do too" : "Dogs are better"
end
puts "#{ask(answer)}"
I am trying to determine the best way to loop through a case statement until a user provides a certain input (in this case, exit).
So far, my code works with a while loop, but it seems a little redundant when I have input = gets.chomp over and over.
Here's a bit of abbreviated code:
input = gets.chomp
while input.downcase != 'exit'
case input.downcase
when 'help'
puts "Available commands are..."
input = gets.chomp
#more when statements go here...
else
puts "That is not a valid command. Type 'HELP' for available commands."
input = gets.chomp
end
end
puts "Goodbye!"
I'd write it like:
loop do
input = gets.chomp.downcase
case input
when 'help'
puts "Available commands are..."
# more when statements go here...
when 'exit'
break
else
puts "That is not a valid command. Type 'HELP' for available commands."
end
end
puts "Goodbye!"
A loop is designed for this sort of case, where you just want to loop cleanly, and then eventually break out on some condition.
For ultimate clarity in what the code is doing, I'd put the exit immediately after reading the input, instead of being embedded in the case statements. It's a minor thing, but is useful to remember if you're coding and others have to help maintain it:
loop do
input = gets.chomp.downcase
break if input == 'exit'
case input
when 'help'
puts "Available commands are..."
# more when statements go here...
else
puts "That is not a valid command. Type 'HELP' for available commands."
end
end
puts "Goodbye!"
Why don't you change the while to:
while (input = gets.chomp.downcase) != 'exit'
Note that this also means that instead of using case input.downcase, you can use case input, as it has already been made lowercase.
edit: my roots in C betray me...
As mentioned in the comments, this is not a particularly "ruby-esque" solution. It also causes a stack trace when gets returns nil. You might prefer to split it into two lines:
while (input = gets)
input = input.chomp.downcase
break if input == 'exit'
case input
# when statements
else
puts "That is not a valid command. Type 'HELP' for available commands."
end
end
I separated the "exit" from the case criteria for a couple of reasons:
It was part of the loop logic in the question, so it's (arguably) more readable to keep it separate from the other cases.
I didn't realise that break behaves differently in Ruby case statements to other languages that I am more familiar with, so I didn't think it would do what you wanted.
You could equally well do this:
while (input = gets)
case input.chomp.downcase
when 'exit'
break
# other when statements
else
puts "That is not a valid command. Type 'HELP' for available commands."
end
end
edit: I am delighted to hear that like Perl, Ruby also has the $_ variable, to which the value of gets will be assigned:
while gets
case $_.chomp.downcase
when 'exit'
break
# other when statements
else
puts "That is not a valid command. Type 'HELP' for available commands."
end
end
You can even get rid of input by exiting the loop with break instead of checking the result in the while condition
while true
case gets.chomp.downcase
when 'exit'
break
when 'help'
# stuff
else
# other stuff
end
end