163

Does Rails 3 or Ruby have a built-in way to check if a variable is an integer?

For example,

1.is_an_int #=> true
"[email protected]".is_an_int #=> false?
7
  • 1
    Rather than caring whether a variable is an integer, you should check to see if the variable responds to to_i. That's part of Ruby's "duck typing": If it can act like an integer, treat it like one. Commented Jan 4, 2011 at 5:34
  • 8
    @the Tin Man: Not entirely. "hello".to_i returns 0 which may not be what you expect. Commented Jan 4, 2011 at 7:40
  • 1
    @EinLama, well, to confuse things further, '0xdeadbeef'.to_i #=> 0 but '0xdeadbeef'.to_i(16) #=> 3735928559 as does 'deadbeef'.to_i(16) #=> 3735928559 or 'deadbeef'.to_i(16).to_s(16) #=> "deadbeef". We're expected to test to make sure we're catching the corner cases but somethings things get slippery. Otherwise we can go old-school and do it asking about types and be more limiting. This is the crux of the arguments surrounding duck-typing. Commented Jan 4, 2011 at 23:13
  • 1
    @AnApprentice For your information, kind_of? is an alias to is_a?. Commented Jan 5, 2011 at 1:20
  • 3
    @JacobRelkin is_a? is slightly different; it asks if the object of an instance of a specific class; kind_of? asks if it is an instance or child of a specific class. fido.is_a? Dog is true; fido.kind_of? Animal is true, for example. Commented Oct 28, 2013 at 19:51

12 Answers 12

317

You can use the is_a? method

>> 1.is_a? Integer
=> true
>> "[email protected]".is_a? Integer
=> false
>> nil.is_a? Integer
=> false
Sign up to request clarification or add additional context in comments.

8 Comments

Thats very cool. does that work to validate email addresses to?
@AnApprentice Since when was validating email addresses part of the question?
this wont work if the number comes in a string like "11111111"
look below Integer(obj) rescue false This will not work for "1" if you want to check if it will convert
@Ricbermo "1111111" is a String. A String that happens to be convertible to and Integer.
|
54

If you want to know whether an object is an Integer or something which can meaningfully be converted to an Integer (NOT including things like "hello", which to_i will convert to 0):

result = Integer(obj) rescue false

5 Comments

Maybe I'm just a noob, but this tweak would have helped me. result = Integer(obj) rescue false.
@JohnCurry, feel free to edit the answer if you can improve it. That's how SO works.
I did, it got rejected. "This edit deviates from the original intent of the post" But regardless, thank you for your answer, it helped me solve my issue!
Integer('08') will fail because of the string being interpreted as octal, Integer('08', 10) works fine. Just in case.
Not sure if Integer(2.5) => 2 is always a meaningful conversion.
32

Use a regular expression on a string:

def is_numeric?(obj) 
   obj.to_s.match(/\A[+-]?\d+?(\.\d+)?\Z/) == nil ? false : true
end

If you want to check if a variable is of certain type, you can simply use kind_of?:

1.kind_of? Integer #true
(1.5).kind_of? Float #true
is_numeric? "545"  #true
is_numeric? "2aa"  #false

4 Comments

This it is exactly what i was looking for the is_numeric?
I think this is close, but not exactly correct. For instance, it will fail for ".34". The problem, I think, is that in \d+? the ? specifies a non-greedy match, whereas you probably want an optional match. Changing \d+? to \d* might fix it, but I'd want to run it through a suite of tests to be sure. This also won't match hex or exponential notation, but I'm sure that's fine for certain use cases.
Why not just to use this regexp: \A\d+\z?
Compare to the Integer(obj) rescue false code from @alex-d below; regexp is difficult to read and not clear in its intent. Both work, I came to this question in an attempt to fix a poorly constructed regexp that was not always working :-)
24

If you're uncertain of the type of the variable (it could be a string of number characters), say it was a credit card number passed into the params, so it would originally be a string but you want to make sure it doesn't have any letter characters in it, I would use this method:

    def is_number?(obj)
        obj.to_s == obj.to_i.to_s
    end

    is_number? "123fh" # false
    is_number? "12345" # true

@Benny points out an oversight of this method, keep this in mind:

is_number? "01" # false. oops!

3 Comments

thanks, you save my day. For anyone that need to check if it float or not can change directly to obj.to_s == obj.to_f.to_s just like in my case.
Edmund that's clever! 🙌
Awesome, i prefer this than Integer('123fh') and rescue exception.
5

There's var.is_a? Class (in your case: var.is_a? Integer); that might fit the bill. Or there's Integer(var), where it'll throw an exception if it can't parse it.

Comments

5

You can use triple equal.

if Integer === 21 
    puts "21 is Integer"
end

Comments

3

A more "duck typing" way is to use respond_to? this way "integer-like" or "string-like" classes can also be used

if(s.respond_to?(:match) && s.match(".com")){
  puts "It's a .com"
else
  puts "It's not"
end

Comments

2

In case you don't need to convert zero values, I find the methods to_i and to_f to be extremely useful since they will convert the string to either a zero value (if not convertible or zero) or the actual Integer or Float value.

"0014.56".to_i # => 14
"0014.56".to_f # => 14.56
"0.0".to_f # => 0.0
"not_an_int".to_f # 0
"not_a_float".to_f # 0.0

"0014.56".to_f ? "I'm a float" : "I'm not a float or the 0.0 float" 
# => I'm a float
"not a float" ? "I'm a float" : "I'm not a float or the 0.0 float" 
# => "I'm not a float or the 0.0 float"

EDIT2 : be careful, the 0 integer value is not falsey it's truthy (!!0 #=> true) (thanks @prettycoder)

EDIT

Ah just found out about the dark cases... seems to only happen if the number is in first position though

"12blah".to_i => 12

2 Comments

0 is truthy in ruby!
@prettycoder thanks for the heads up, I will fix this immediately in the answer
1

To capitalize on the answer of Alex D, using refinements:

module CoreExtensions
  module Integerable
    refine String do
      def integer?
        Integer(self)
      rescue ArgumentError
        false
      else
        true
      end
    end
  end
end

Later, in you class:

require 'core_ext/string/integerable'

class MyClass
  using CoreExtensions::Integerable

  def method
    'my_string'.integer?
  end
end

Comments

0

I have had a similar issue before trying to determine if something is a string or any sort of number whatsoever. I have tried using a regular expression, but that is not reliable for my use case. Instead, you can check the variable's class to see if it is a descendant of the Numeric class.

if column.class < Numeric
  number_to_currency(column)
else
  column.html_safe
end

In this situation, you could also substitute for any of the Numeric descendants: BigDecimal, Date::Infinity, Integer, Fixnum, Float, Bignum, Rational, Complex

Comments

0

Basically, an integer n is a power of three, if there exists an integer x such that n == 3x.

So to verify that you can use this functions

def is_power_of_three(n)
  return false unless n.positive?

  n == 3**(Math.log10(n)/Math.log10(3)).to_f.round(2)
end

Comments

-1

Probably you are looking for something like this:

Accept "2.0 or 2.0 as an INT but reject 2.1 and "2.1"

num = 2.0

if num.is_a? String num = Float(num) rescue false end

new_num = Integer(num) rescue false

puts num

puts new_num

puts num == new_num

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.