Reputation: 110
I'm trying to find out if a user inputs a string or an integer. I can find it out if I enter a fixed value with user input's requirement. I can't get its class.
This works:
name = 5
type = name.class
This doesn't work:
print "Enter the value to findout its class "
name = gets
type = name.class
if type == String
puts "this is a string"
elsif type == Fixnum
puts "this is a fixnum"
else
puts "this is unknown type"
end
Upvotes: 2
Views: 4582
Reputation: 1424
(gets.chomp == '0' || gets.chomp.to_i != 0) => true for input is integer
Upvotes: 0
Reputation: 6754
How about this?
class String
def is_number?
true if Float(self) rescue false
end
end
Now call is_number?
on user_input
user_input.is_number?
Upvotes: 0
Reputation: 114158
You could call Kernel#String
, Kernel#Integer
and Kernel#Float
to find "valid" classes, i.e. classes you can convert the input into.
def valid_classes(value)
classes = []
classes << String(value) rescue nil
classes << Integer(value) rescue nil
classes << Float(value) rescue nil
classes.map(&:class)
end
valid_classes("foo") #=> [String]
valid_classes("123.456") #=> [String, Float]
valid_classes("123") #=> [String, Fixnum, Float]
valid_classes("100000000000000000000") #=> [String, Bignum, Float]
Other notations are recognized, too:
valid_classes("1_000") #=> [String, Fixnum]
valid_classes("1e20") #=> [String, Float]
valid_classes("0b111") #=> [String, Fixnum]
If you need more control, use a regular expression.
Here's a simple REPL:
loop do
print "Enter a value to find out its class: "
input = gets.chomp
puts "'#{input}' could be a: #{valid_classes(input).join(', ')}"
end
Upvotes: 2
Reputation:
I think the question I would have to ask you is how is the user expected to enter a string?
If the user enters:
10 #=> Fixnum
1_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000 #=> Bignum
1.0 #=> Float
"hello" #=> String
'hello' #=> String
Then you can just do:
def test_input
input = gets.chomp
puts eval(input).class
rescue NameError
puts "Unknown Input Class"
end
This actually should work with all defined objects, so if you only want to catch those four that you mentioned then:
def test_input
input = gets.chomp
klass = eval(input).class
raise NameError unless [Fixnum, Bignum, Float, String].include?(klass)
puts klass
rescue NameError
puts "Unknown Input Class"
end
EDIT:
To circumvent the use of eval with direct user input, which is a vulnerability, Gumbo suggests to use a parser instead.
$ gem install parser
#!/usr/bin/ruby
require 'parser/current'
def test_input
input = Parser::CurrentRuby.parse(gets.chomp)
puts case input.type
when :str then "String"
when :float then "Float"
when :int
eval(input.to_sexp.slice(/\d+/)).class
# Yes using eval again to get Fixnum vs Bignum, but this time
# we know what the input will be, and that's ok to eval
else
"Unknown Input Class"
end
end
Upvotes: 2
Reputation: 14051
As @ArupRakshit mentioned in his comment above, gets
always gets you a String
.
What you want to do is get the user's input and determine what it is.
For instance, "1"
is a String
but 1
is a Fixnum
.
[2] pry(main)> "1".class
=> String
[3] pry(main)> 1.class
=> Fixnum
In your comment above, you mentioned that gets.to_i
gives you an integer. There's a problem with that. String#to_i
returns 0 for strings that are not numeric:
[6] pry(main)> gets.to_i
hello
=> 0
[7] pry(main)> "hello".to_i
=> 0
So basically you're getting a String
and will be determining its possible class(es).
# add more Kernel methods here
POSSIBLE_CLASSES = [Integer, Float, Bignum, String]
str = gets.chomp # chomp gets rid of the \n that gets appended
# to your String because you press enter
# As @Stefan does it, but with meta-programming
POSSIBLE_CLASSES.collect { |p|
(Kernel.method(p.name).call(str); p) rescue nil
}.compact
Explanation of the last line:
Kernel.Integer("1")
returns 1
Kernel.Float("1.0")
returns 1.0
So basically, I want to call a Kernel's method which name is the same as my class.
Kernel.method( method_name )
returns the method to me, which I then call with the string str.
Kernel.Integer("hello")
would throw an ArgumentError
; which will be rescued and a nil will be collected.
So basically, the line above will loop through the possible classes and attempt initializing them with the string we got from the console. We collect the class if there's no exception and nil otherwise. Then we compact the array (remove the nils), which will then contain the 'valid' classes.
Note that our code above only supports Kernel
types and can be easily tweaked to support other classes.
Upvotes: 1