Throwing Error in Rescue method? - ruby

I'm New to ruby,learning basics,I want to enter only Integer Values in age field,Need to Throw Not a number when it is a string when executing the following code
puts "Enter Age "
age=Integer(gets) rescue nil
if age.is_a?(Numeric)
puts "Your age is #{age}"
else
puts "Not a Number"
end
if age>25
puts "You are Permitted"
else
puts "Not allowed"
end
getting error as ': undefined method `>' for nil:NilClass (NoMethodError) What am doing wrong ?

The user input was not in a format to give an integer, so by rescue, age became nil. You tried to apply > on it in if age>25, which is not defined.

You wrote puts "Not a number" which will print a message but then your program will keep running as usual. On that line, try replacing "puts" with "raise" and then read about Ruby exceptions.

You don't need to rescue to nil because you're planning to get and respond to whatever the user inputs and you don't need to raise because you don't want the program to exit after the user inputs a non Integer.
This is probably what you need:
age = ""
loop do
puts "Enter Age "
age = gets.chomp
if age.to_i.to_s == age.to_s
puts "Your age is #{age}"
else
puts "Not a Number"
next
end
if age.to_i > 25
puts "You are Permitted"
break
else
puts "Not allowed"
break
end
end until age.to_i.to_s == age.to_s
next will make it go back and do the next loop, and break will break out of the loop.
You can use age.to_i.to_s == age.to_s to really check if age is an integer.

Related

Why does defined input variable return nil after exception occurs?

I've noticed this strange behavior with the begin/rescue block in Ruby, when I define a variable, and an exception occurs and I try to call that variable that the exception occurred on it returns nil.
For example:
begin
print "Enter a number: "
input = Integer(gets.chomp)
sum = input + 5
puts "This is your number plus five: #{sum}"
rescue ArgumentError
puts "#{input}" #This outputs nil
end
Why does the begin/rescue block work like this, and is there a way to print the variable without it returning nil?
I'm not sure this is what you want but I try
input = gets.chomp
begin
number = Integer(input)
puts "your number plus five: #{number + 5}"
rescue ArgumentError
puts "#{input} is not a valid number"
end

How do I return an error message when the user inputs wrong info?

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.

Handling Ruby Case Statement

I tried to rewrite the "if/else statement" in the following piece of code by replacing it with a "case" statement, and I am deadly stuck with it for a few hours - what am I missing?
puts "Welcome to 'Guess My Number!'"
print "What is your name?"
input = gets
name = input.chomp
puts "Welcome, #{name.upcase!}!"
puts "I've got a random number between 1 and 100!"
puts "Can you guess it?"
target = rand(100) + 1
num_guesses = 0
guessed_it = false
until num_guesses == 10 || guessed_it
remaining_guesses = 10 - num_guesses
puts "You've got #{remaining_guesses.to_s} guesses left!"
print "Make a guess, put down a number: "
guess = gets.chomp.to_i
num_guesses = num_guesses + 1
end
puts case verification
when guess < target
then "Ooops. Your guess was LOW."
when guess > target
then "Ooops. Your guess was HIGH."
when guess < -1
then puts "Oooops. You have entered a number lower that 1!"
when guess > 100
then puts "Oooops. You have entered a number higher than 100!"
when guess =~ /^([w])/
then puts "Ooops. Looks like you have entered a non numeric
value!"
when guess == String
then puts "Oooops! Looks like you have entered a non numeric
value"
when guess == target
then puts "Good job, #{name}!"
puts "You guessed my number in #{num_guesses} guesses!"
guessed_it = true
end
unless guessed_it
puts "Sorry, you didn't get my number. My number was #{target}."
end
The "case statement" was used to replace and enhance the logic of the following if else statement:
if guess < target
puts "Ooops. Your guess was LOW."
elsif guess > target
puts "Ooops. Your guess was HIGH."
elsif guess == target
puts "Good job, #{name}!"
puts "You guessed my number in #{num_guesses} guesses!"
guessed_it = true
end
Your problem is that you're using the form of case with the optional condition, but you're using when clauses as if you were using the condition-less case.
puts case
when guess < target
"Ooops. Your guess was LOW."
should work.
Further explanation:
using case without a condition, the earliest when branch with a truthy expression is executed. This is what you want here.
But you were using case with verification. In this case, all branches are compared to verification, and the first branch where verification === branch condition is true is executed.
Since in your example I'm guessing verification is always nil, and all your branches' conditions are always true or false, no branch will ever get executed.
You can use a case statement like so:
class String
def green;"\e[32m#{self}\e[0m";end
def yellow;"\e[33m#{self}\e[0m";end
def cyan;"\e[36m#{self}\e[0m";end
def bg_blue;"\e[44m#{self}\e[0m";end
def bold;"\e[1m#{self}\e[22m";end
def underline;"\e[4m#{self}\e[24m";end
def border(num);"\n#{'-' * num}\n#{self}\n#{'-' * num}\n";end
end
puts;puts "Welcome to 'Guess My Number!'".bold.bg_blue;puts
print 'What is your name? '.green
name = gets.chomp
puts "\nWelcome, #{name.upcase!}!\n".cyan.underline
puts "I've got a random number between 1 and 100!\nCan you guess it?".border(44)
target = rand(100) + 1
num_guesses = 0
guessed_it = false
until num_guesses == 10 || guessed_it
remaining_guesses = 10 - num_guesses
puts "\nYou've got #{remaining_guesses} guesses left!\n"
puts;print 'Make a guess, put down a number: '
guess = gets.chomp
case guess.to_i
when (1...target)
puts 'Ooops. Your guess was LOW'.yellow.border(26)
when (target + 1..100)
puts 'Ooops. Your guess was HIGH'.yellow.border(26)
when target
puts; puts; puts
puts "Good job, #{name}!".bold.green
puts 'You guessed my number in ' + "#{num_guesses} guesses!".cyan
puts; puts; puts
guessed_it = true
else
puts "Oooops. You didn't enter a number from 1 to 100".yellow.border(47); puts
end
num_guesses += 1
end
unless guessed_it
puts;puts;puts "Sorry, you didn't get my number. My number was #{target}.".yellow;puts
end
Thanks a lot to everybody! With your invaluable help I managed to regain patience in my soul and satisfaction from this small task :) My mistake is that I violated the rules of common sense by trying to run several pieces of code in a wrong sequence. I moved the case statement inside the until loop and now all I have to do is correct the mistakes in particular when/then statements. It works :)
until num_guesses == 10 || guessed_it
remaining_guesses = 10 - num_guesses
puts "You've got #{remaining_guesses.to_s} guesses left!"
print "Make a guess, put down a number: "
guess = gets.chomp.to_i
num_guesses = num_guesses + 1
puts case
when guess < target
then "Ooops. Your guess was LOW."
when guess > target
then "Ooops. Your guess was HIGH."
when guess < -1
then puts "Oooops. You have entered a number lower that 1!"
when guess > 100
then puts "Oooops. You have entered a number higher than 100!"
when guess =~ /^([w])/
then puts "Ooops. Looks like you have entered a non numeric value!"
when guess == String
then puts "Oooops! Looks like you have entered a non numeric value"
when guess == target
then puts "Good job, #{name}!"
puts "You guessed my number in #{num_guesses} guesses!"
guessed_it = true
end
end
unless guessed_it
puts "Sorry, you didn't get my number. My number was #{target}."
end

My case statement is not working, but the logic looks correct to me

This program prints the first statement, and exits after I enter a number e.g. "5", without printing anything else. From the logic I put in the case statement, I would expect it to output "You're not an adult :(" for 5. Other values lower than 120 do not work as expected either.
What is wrong?
print "Enter you age "
age = gets.chomp
if age.to_i<120
case age.to_i
when age.to_i<18
puts "You're not an adult :("
puts "Sorry"
when age.to_i>18
puts "You are now an adult!"
puts "phew"
end
end
Try this. Notice I've dropped the age.to_i from the case statement:
print "Enter you age "
age = gets.chomp
if age.to_i<120
case
when age.to_i<18
puts "You're not an adult :("
puts "Sorry"
when age.to_i>18
puts "You are now an adult!"
puts "phew"
end
end
EDIT
A little explanation is in order.
When you write this:
case foo
when "bar"
...
That essentially means:
if "bar" === foo
...
So your code was sort of like this:
if age.to_i<18 === age.to_i
...
which doesn't make a lot of sense. If you just write case with nothing after it, then it works more like a regular if statement. E.g.
case
when foo === "bar"
...
means roughly
if foo === "bar"
...
which is what you want. I hope that helps!
Here's a cleaned up version:
print "Enter you age "
age = gets.chomp.to_i
case age
when 0..18
puts "You're not an adult :("
puts "Sorry"
when 18..120
puts "You are now an adult!"
puts "phew"
else
puts "I think you're lying!"
end
Folding all of this into a single case statement and using ranges makes what's happening a lot more clear.

I can't figure out why I am getting error "can't convert nil into String"

puts 'Please enter your age '
age=gets.chomp
age=age.to_i
if age >=18
division='in the adult '
elsif age >=12
division='in the junior '
elsif age >=5
division='in the novice '
else
puts 'We are sorry, but you are ineligible to play in the league at this time.'
end
puts 'Congratulations! You are '+division+'league.'
sleep 5
The error I get is this:
We are sorry, but you are ineligible to play in the league at this time.
:18:in `+': can't convert nil into String (TypeError)
:18:in `<main>'
You're getting that message because division is nil. In the case that none of your conditions are met the 'We are sorry' message is displayed, but no value is assigned to the division variable.
You can get rid of it by doing:
puts 'Congratulations! You are '+division+'league.' unless division.nil?
This is because you're not initializing division, and it's thus set to nil.Initialize division like this:
division = 'in no'
Do that either in else block or before the first if.
Just to show how your code can be more Ruby-like:
print 'Please enter your age: '
age = gets.chomp.to_i
division = case
when age >= 18
'adult'
when age >= 12
'junior'
when age >=5
'novice'
else
nil
end
if division
puts "Congratulations! You are in the #{ division } league."
else
puts 'We are sorry, but you are ineligible to play in the league at this time.'
end
I'm sure it could be tighter, but this is how I'd do it. Also, because the code checks to see if division is set, it won't return the error you're seeing.

Resources