1
votes

As I understand it, the way to accept user input is

puts "Can you guess what number the computer is thinking of?"
userguess = gets.chomp

gets.chomp is a string method and so if the user enters the number 5, userguess stores the value "5" as string. I would then have to do userguess.to_i! to convert this to an int. However, I would not like to do this. I want to accept the user input either as a string or an int and then have the program do something like:

if @guess.is_a?(Integer) == true
  puts "I got your number. Let me get back to you."
  # do something
elsif @guess.is_a?(Integer) == false
  puts "That's not a number. You MUST enter a number! Try again"
  # Ask the user to guess again.
else
  #something else
end

I don't want to accept the user input explicitly as a string because I want to check if it is a string or an int later on in the program. How would I do this?

4
Anything input will be read as a string. You must handle type coercion yourselfBrennan
Thanks, @Brennan. Then how would I distinguish between whether user input was a string or a number?Sean Bernardino
Your understanding that the way to accept an input is gets.chomp is wrong in the first place. The way to accept is gets. And there is no such thing as to_i!. Changing the receiver's class while retaining its id is impossible.sawa
You could use a regex: s = gets.chomp; if s[/^-?\d+$/] .... – Cary Swoveland 7 mins ago editCary Swoveland

4 Answers

0
votes

That is impossible. All user input from the terminal are a string. If it were possible, how would you think a user can input a number 5 as opposed to a string "5"?

0
votes

No, that is not possible.

But you can define a little function to check whether that string can be an integer or not:

def is_i?(s)
  s.to_i.to_s == s
end

Be aware that string with spaces will not be an integer in this case:

is_i? '123'    # true
is_i? '123 '   # false
is_i? ' 123'   # false
is_i? '12 123' # false

To handle second and third example you can strip your user input.

Your code will look like:

guess = gets.chomp.strip

if is_i? guess
  puts 'is integer' 
else
  puts 'is not an integer'
end
0
votes

To check if a string contains valid integer (or float, etc.) you could use this approach:

def coerce(string)
  Integer(string) rescue Float(string) rescue string
end 

coerce('115').class      # Fixnum
coerce('115.12').class   # Float
coerce('115.aa').class   # String

Also check out highline gem, it provides lots of helpful functionality when it comes to cli.

0
votes

You don't understand how a keyboard device and the console input work.

ALL input typed on the keyboard and read via gets or anything else, is always a String. You can not get anything else.

We use gets.chomp to remove the trailing newline that is entered when the user presses Return or Enter. For instance, a bare gets will return a line-end if I enter nothing else:

gets #=> "\n"

Adding additional characters results in those characters, plus the terminating line-end:

gets #=> "foo\n"

We use chomp to remove that trailing line-end. Repeating the same inputs and using chomp:

gets.chomp #=> ""
gets.chomp #=> "foo"

Ruby makes it easy to tell if what was input can be cleanly converted to an integer. Simply use Integer(). Here is some output from an IRB session:

>> Integer('1') #=> 1
>> Integer('123') #=> 123
>> Integer('foo')
ArgumentError: invalid value for Integer(): "foo"
    from (irb):14:in `Integer'
    from (irb):14
    from /usr/local/bin/irb:12:in `<main>'
>> Integer('1a')
ArgumentError: invalid value for Integer(): "1a"
    from (irb):15:in `Integer'
    from (irb):15
    from /usr/local/bin/irb:12:in `<main>'

Using a rescue makes it easy to handle the exception:

begin
  Integer('1')
rescue ArgumentError
  puts 'not a number'
end #=> 1

Or:

begin
  Integer('a')
rescue ArgumentError
  'not a number'
end #=> "not a number"