2

How to check if users didn't put an integer in if statement in a loop. I want the if statement to check if the user didn't put an integer, the system gonna say "please put an integer" Right now, everything works fine, but when user input a decimal number, the program will convert it to an integer. I want the program to say "you need to put an integer" when user put a decimal number.

I tried if soap.match(/^[\d]+$/).nil? and other methods, but didn't work. I think I need to change some code in 'if (soap_type = SOAPS[soap.to_i])', but I don't know how to change it.

  SOAPS = {
  1 => 'face soap',
  2 => 'bar soap',
  3 => 'shave soap',
  4 => 'shampoo soap'
}.freeze

loop do
  puts "What type of soaps do you want? (#{SOAPS.map { |k, v| "#{k} - #{v}" }.join(', ')}) Please put a number from 1 - 4 "

  soap = gets

  if (soap_type = SOAPS[soap.to_i])
    puts "Great! You want #{soap_type}."
    break

  elsif !soap.match (/\A[-+]?[0-9]*\.?[0-9]+\Z/)
    puts "You didn't enter an integer, please put an integer from 1-4"

  else
    puts "#{soap.inspect} is not a valid integer, please try again."
  end
end

I hope when the user input a decimal number, the program gonna say You didn't enter an integer, please put an integer.

Leslie
  • 67
  • 1
  • 2
  • 7
  • You might find [this](https://www.google.com/search?q=ruby+check+if+input+is+integer) helpful. Or [this](https://stackoverflow.com/questions/14900490/how-to-cleanly-verify-if-the-user-input-is-an-integer-in-ruby). Or [this](https://stackoverflow.com/questions/2095493/how-can-i-check-if-a-value-is-a-number). – jvillian Aug 15 '19 at 15:57
  • There's no such thing as `.to_i` in isolation. That's a method call *on nothing*. – tadman Aug 15 '19 at 16:15
  • @tadman Yeah, I also tried other ways, but it didn't work – Leslie Aug 15 '19 at 16:20
  • What you were looking for was `if !soap.match(/\A\d+\z/)` to determine if it's not just made of just digits. That's a really heavy handed approach, though, since you already have logic to test for specific values, so just complain at the end if nothing matched. – tadman Aug 15 '19 at 16:23

1 Answers1

3

There's a much more Ruby way to express this, the idiomatic form if you will:

loop do
  puts "What type of soaps do you want? (1 = face soap, 2 = bar soap, 3 = shave soap, 4 = shampoo soap) Please put a number from 1 - 4 "

  case (soap = gets)
  when '1'
    puts "Great! You want face soap."
  when '2'
    puts "Great! You want bar soap"
  when '3'
    puts "Great! You want shave soap."
  when '4'
    puts "Great! You want shampoo soap."
  else
    puts "#{soap.inspect} is not a valid entry, please try again."
  end
end

Where the case statement can do a ton of work for you. Here the string values are being tested instead of bothering to convert since that doesn't really matter.

Notice there's still a lot of duplication though. This is where a look-up table can be the key to simplifying things:

SOAPS = {
  1 => 'face soap',
  2 => 'bar soap',
  3 => 'shave soap',
  4 => 'shampoo soap'
}.freeze

loop do
  puts "What type of soaps do you want? (#{SOAPS.map { |k, v| "#{k} - #{v}" }.join(', ')}) Please put a number from 1 - 4 "

  soap = gets

  if (soap_type = SOAPS[soap.to_i])
    puts "Great! You want #{soap_type}."
  else
    puts "#{soap.inspect} is not a valid entry, please try again."
  end
end

Where now you can easily add and remove entires and everything updates accordingly. This is a data-driven approach and it's what Ruby excels at because once you have something expressed in terms of data, you can build on that with a series of transformations to get the desired result.

tadman
  • 208,517
  • 23
  • 234
  • 262
  • @tadman Hi tadman, my team member still wants the result to be different when user input a string, is there anyway to say if soap == integer or if soap == string? – Leslie Aug 15 '19 at 18:22
  • The input from `gets` will be a String, it will never be anything but. The conversion with `.to_i` will be an Integer, but `0` in the case of bad input. I suggested a regular expression solution in the comment on your question to trap "non-number" input. That might be what you want. – tadman Aug 15 '19 at 18:23
  • @tadman Hey tadman, I use the second solution you provide, but when user input a decimal number, the program will convert it to an integer. Is there any ways to stop the program from doing that. I want the program to say you didn't put an integer when users input a float. – Leslie Aug 20 '19 at 20:43
  • You'll have to apply that "is just digits" regular expression from above as well, or you can avoid the numerical conversion altogether and use strings. In that case `SOAPS = { '1' => 'face soap', ... }` and avoid the `.to_i`. You are just using this as a quick look-up anyway. – tadman Aug 20 '19 at 21:29