160

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
"dadadad@asdasd.net".is_an_int #=> false?
Nic
  • 6,211
  • 10
  • 46
  • 69
AnApprentice
  • 108,152
  • 195
  • 629
  • 1,012
  • possible duplicate of [Does ruby 1.9.2 have an is_a? function?](http://stackoverflow.com/questions/4282273/does-ruby-1-9-2-have-an-is-a-function) – Andrew Grimm Jan 04 '11 at 02:09
  • 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. – the Tin Man Jan 04 '11 at 05:34
  • 7
    @the Tin Man: Not entirely. "hello".to_i returns 0 which may not be what you expect. – EinLama Jan 04 '11 at 07:40
  • @Andrew Grimm: it is in content, but the question is different. If you didn't know about "is_a?", you wouldn't know to ask if there is a "is_a?". – Groxx Jan 04 '11 at 21:30
  • 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. – the Tin Man Jan 04 '11 at 23:13
  • 1
    @AnApprentice For your information, `kind_of?` is an alias to `is_a?`. – Jacob Relkin Jan 05 '11 at 01: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. – Tom Harrison Oct 28 '13 at 19:51

12 Answers12

311

You can use the is_a? method

>> 1.is_a? Integer
=> true
>> "dadadad@asdasd.net".is_a? Integer
=> false
>> nil.is_a? Integer
=> false
Purplejacket
  • 1,808
  • 2
  • 25
  • 43
mportiz08
  • 10,206
  • 12
  • 40
  • 42
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
Alex D
  • 29,755
  • 7
  • 80
  • 126
  • 2
    Maybe I'm just a noob, but this tweak would have helped me. result = Integer(obj) rescue false. – John Curry Oct 16 '14 at 02:58
  • @JohnCurry, feel free to edit the answer if you can improve it. That's how SO works. – Alex D Oct 16 '14 at 05:55
  • 3
    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! – John Curry Oct 17 '14 at 00:11
  • 8
    Integer('08') will fail because of the string being interpreted as octal, Integer('08', 10) works fine. Just in case. – Jong Bor Lee Mar 10 '15 at 18:38
  • 1
    Not sure if `Integer(2.5) => 2` is always a meaningful conversion. – mkataja Apr 24 '17 at 12:12
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
Jacob Relkin
  • 161,348
  • 33
  • 346
  • 320
  • This it is exactly what i was looking for the is_numeric? – workdreamer Feb 17 '12 at 16:52
  • 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. – Jeff Apr 24 '12 at 16:04
  • 1
    Why not just to use this regexp: `\A\d+\z`? – NARKOZ Oct 03 '12 at 16:12
  • 1
    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 :-) – Tom Harrison Oct 28 '13 at 19:47
23

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!
Jaime Gómez
  • 6,961
  • 3
  • 40
  • 41
bigpotato
  • 26,262
  • 56
  • 178
  • 334
5

You can use triple equal.

if Integer === 21 
    puts "21 is Integer"
end
Sebastián Palma
  • 32,692
  • 6
  • 40
  • 59
Tsoodol
  • 59
  • 1
  • 3
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.

Groxx
  • 2,489
  • 1
  • 25
  • 32
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
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
vish
  • 2,436
  • 1
  • 24
  • 20
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
Cyril Duchon-Doris
  • 12,964
  • 9
  • 77
  • 164
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
Community
  • 1
  • 1
Vadym Tyemirov
  • 8,288
  • 4
  • 42
  • 38
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

penguincoder
  • 547
  • 7
  • 8
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
-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

Owais Akbani
  • 65
  • 1
  • 5