2
votes

I'm trying to make users input a positive integer(>=1). If the user inputs a negative integer or 0, the program gonna notice and say you didn't put a valid integer, please try again. my program works so far until I try to input a string. My program break after I input a string. Does anybody know how to fix this?

I tried elsif !barsofsoap.match (/\A[-+]?[0-9]*.?[0-9]+\Z/) puts "You didn't enter an integer, please put a positive integer", but it didn't work

loop do
  puts "How many soaps are you looking to purchase? (Please put an integer)"
  x = gets.chomp
  barsofsoap = Integer(x) rescue false

  if barsofsoap >= 1
    break
  else
    puts "You didn't put an integer, please put an integer and try again."
  end
end

I hope the program will not break if the user inputs a string.

3
if barsofsoap >= 1 is in fact the right way to check this. match would work for a String type, but your barsofsoap = Integer(x) ensures that you're dealing with a numeric type. Try it again!Chris Heald
@Chris Heald if barsofsoap >= 1 works, but if I input a string, the program will break, I guess my problem is how to make the program not break if I put a string.Leslie

3 Answers

6
votes

The reason why your current code fails is because you use false as rescue value. You can't compare false >= 1. Sticking close to your original code you might wrap the comparison into a begin/end block.

loop do
  puts "How many soaps are you looking to purchase? (Please put an integer)"
  x = gets.chomp
  begin
    barsofsoap = Integer(x)
    if barsofsoap >= 1
      break
    end
  rescue ArgumentError => _error
    puts "You didn't put an integer, please put an integer and try again."
  end
end

Or simplifying the code:

loop do
  puts "How many soaps are you looking to purchase? (Please put an integer)"
  break if (barsofsoap = gets.to_i).positive?
  puts "Invalid input. Provide a positive integer."
end

The above code doesn't detect if the input is a string or an integer. By replacing Integer(x) with x.to_i it would simply return 0 if invalid. Since you want the user to provide an positive integer it still requests them to provide a new integer.

nil.to_i #=> 0
''.to_i #=> 0
'asdf'.to_i #=> 0
'12.34'.to_i #=> 12

Like shown above the string '12.34' will produce the value 12. Depending on your requirements you might not want to use this value and instead mark it as invalid input. In this case you could use a regex to check the provided input.

loop do
  puts "How many soaps are you looking to purchase? (Please put an integer)"
  input = gets
  break barsofsoap = input.to_i if input.match?(/\A[1-9]\d*\Z/)
  puts "Invalid input. Provide a positive integer."
end

The regex /\A[1-9]\d*\Z/ will match the following:

  • \A Matches start of string.
  • [1-9] Matches one of the digits 1-9.
  • \d* Matches zero or more digits 0-9.
  • \Z Matches end of string. If the string ends with a newline, it matches just before the newline.
6
votes

You try this: num.positive?

see here: https://ruby-doc.org/core-2.6/Numeric.html#method-i-positive-3F

Also you can try convert the text to an integer and validate by doing this: num.is_a?(Integer)

https://ruby-doc.org/core-2.6/Object.html#method-i-is_a-3F

Or even better since input is always text, you can use a regex to make sure only numbers are entered: "12345" =~ /\A\d+\Z/

How about try this:

loop do
  puts "How many soaps are you looking to purchase? (Please put an integer)"

  barsofsoap = gets.chomp

  if barsofsoap.match(/^[\d]+$/).nil?
    puts "You didn't put an integer, please put an integer and try again."
  elsif barsofsoap.to_i.positive?
    break
  else
    puts "You didn't put an integer, please put an integer and try again."
  end
end
1
votes

Other option, using n.to_i.to_s == n to check the input is an Integer and moving the loop into a method:

def get_input_integer
  loop do
    puts "Enter a positive Integer"
    n = gets.chomp
    if n.to_i.to_s == n
      return n.to_i if n.to_i.positive?
      puts "It's not positive"
    else
      puts "It's not an integer" 
    end
  end
end

x = get_input_integer