153

I can't seem to check if an object is a boolean easily. Is there something like this in Ruby?

true.is_a?(Boolean)
false.is_a?(Boolean)

Right now I'm doing this and would like to shorten it:

some_var = rand(1) == 1 ? true : false
(some_var.is_a?(TrueClass) || some_var.is_a?(FalseClass))
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Lance
  • 75,200
  • 93
  • 289
  • 503
  • Similar: [check-whether-a-variable-is-a-string-in-ruby?](http://stackoverflow.com/questions/7749416/check-whether-a-variable-is-a-string-in-ruby?rq=1) – nawfal Jul 24 '14 at 01:58

9 Answers9

148

Simplest way I can think of:

# checking whether foo is a boolean
!!foo == foo
Konstantin Haase
  • 25,687
  • 2
  • 57
  • 59
  • 6
    class X; def !; self end end ; x = X.new ; !!x == x #=> true – Alexey Jun 07 '12 at 12:08
  • 5
    Yes, that's called duck typing and a core principle of OOP. I think it's a feature. – Konstantin Haase Jun 19 '12 at 16:41
  • 2
    The problem with it is that "if it walks like duck" does not imply "it quacks like duck". Correspondingly `!!pseudo_bool == pseudo_bool` does not imply `pseudo_bool & true == pseudo_bool` for example. – Alexey Jun 23 '12 at 17:24
  • 1
    Right, if there would be an agreed upon method to check this, like with `to_ary`, then it would be easier. However, I don't think this argument really counts. People could also override `is_a?`. In that case the only real way would be to use `Module#===`, as it does not call any method on the object in question. Which in turn is a violation of OOP, as all you should do is sending methods. – Konstantin Haase Jun 27 '12 at 21:56
  • 77
    Short doesn't necessarily mean simple. By which I mean, wtf is that? – Grant Birchmeier Apr 11 '13 at 22:00
  • 12
    Turns foo into a boolean, checks if that's the same as foo. – Konstantin Haase Apr 12 '13 at 18:06
  • it's cryptic, but really no alternative comes close –  May 20 '14 at 08:11
  • I don't know about this answer... If foo = "" then `!!foo == foo` return true. – Dan Jan 28 '16 at 16:53
  • 2
    @Dan No it doesn't. If `foo = ""`, then `!!foo` is true, and true does not equal an empty string. – Ben Visness Mar 01 '16 at 23:05
  • 12
    Note that double negation is considered bad style by some checkers (like [RuboCop](https://github.com/bbatsov/rubocop)). – sschuberth May 10 '16 at 10:25
  • since a boolean column can be nil, and this doesn't work for nil, is there a better way? – jpw Mar 02 '17 at 20:13
  • @jpwynn what makes you think this doesn't work for nil? `nil != false` so this works just fine for nil – TheRealMrCrowley Dec 29 '17 at 09:20
  • Considering `foo` as a string, it considers it as a Boolean which is not true. Am I right? – Aboozar Rajabi Apr 09 '19 at 19:58
  • @AboozarRajabi: `foo = "bar"; !!foo == foo #=> false` – Eric Duminil May 22 '19 at 20:35
  • 1
    -1: This does not check if `foo` is a boolean, this _converts the value_ of `foo` into a boolean. That is, this is not the same as `foo.is_a?(TrueClass) || foo.is_a?(FalseClass) – Josh May 31 '21 at 15:52
147

I find this to be concise and self-documenting:

[true, false].include? foo

If using Rails or ActiveSupport, you can even do a direct query using in?

foo.in? [true, false]

Checking against all possible values isn't something I'd recommend for floats, but feasible when there are only two possible values!

mahemoff
  • 44,526
  • 36
  • 160
  • 222
94

There is no Boolean class in Ruby, the only way to check is to do what you're doing (comparing the object against true and false or the class of the object against TrueClass and FalseClass). Can't think of why you would need this functionality though, can you explain? :)

If you really need this functionality however, you can hack it in:

module Boolean; end
class TrueClass; include Boolean; end
class FalseClass; include Boolean; end

true.is_a?(Boolean) #=> true
false.is_a?(Boolean) #=> true
horseyguy
  • 29,455
  • 20
  • 103
  • 145
  • 2
    trying to do typecasting based on the current value. – Lance Jun 12 '10 at 10:45
  • 89
    'Why would you ever what that?' (and derivatives) is just one of the most annoying questions an engineer can make another :) – deprecated Mar 27 '14 at 14:20
  • 13
    +1 because I can use this in rspec like: `expect(some_method?(data)).to be_a(Boolean)` – Automatico Oct 14 '14 at 15:56
  • 3
    Other case when need to check type, is when you implement database adapter and need wrap strings with `"quotes"` but not numbers and booleans – Daniel Garmoshka Dec 30 '16 at 18:19
  • I'd say that being able to check the type of a variable is such a fundamentally valuable thing for a programming language, and is super important when validating user input. The fact that it's not supported without these odd hacks is... confusing to me.. Doing some research it seems to be that Ruby's way of implementing dynamic typing means there is no way to derive the type. Javascript doesn't have this issue, so I guess there is some larger story behind this.. – Seth Oct 12 '22 at 18:16
29

As stated above there is no boolean class just TrueClass and FalseClass however you can use any object as the subject of if/unless and everything is true except instances of FalseClass and nil

Boolean tests return an instance of the FalseClass or TrueClass

(1 > 0).class #TrueClass

The following monkeypatch to Object will tell you whether something is an instance of TrueClass or FalseClass

class Object
  def boolean?
    self.is_a?(TrueClass) || self.is_a?(FalseClass) 
  end
end

Running some tests with irb gives the following results

?> "String".boolean?
=> false
>> 1.boolean?
=> false
>> Time.now.boolean?
=> false
>> nil.boolean?
=> false
>> true.boolean?
=> true
>> false.boolean?
=> true
>> (1 ==1).boolean?
=> true
>> (1 ==2).boolean?
=> true
Steve Weet
  • 28,126
  • 11
  • 70
  • 86
  • 5
    Simpler just to write `self == true or self == false`. Those are the only instances of TrueClass and FalseClass. – Chuck Jun 12 '10 at 18:50
  • @chuck that returns the same results except for Time.now.boolean? which returns nil. Any idea why? – Steve Weet Jun 12 '10 at 22:24
  • Defining a class check on self in the method is somewhat not oop. You should define two versions of `boolean`, one for TrueClass/FalseClass and one for Object. – Konstantin Haase Jun 13 '10 at 19:41
  • 4
    The reason is that a bug in the version of `Time#==` in Ruby 1.8 causes a comparison to non-Time values to return nil rather than false. – Chuck Jun 13 '10 at 20:58
22

If your code can sensibly be written as a case statement, this is pretty decent:

case mybool
when TrueClass, FalseClass
  puts "It's a bool!"
else
  puts "It's something else!"
end
Henrik N
  • 15,786
  • 5
  • 82
  • 131
7

An object that is a boolean will either have a class of TrueClass or FalseClass so the following one-liner should do the trick

mybool = true
mybool.class == TrueClass || mybool.class == FalseClass
=> true

The following would also give you true/false boolean type check result

mybool = true    
[TrueClass, FalseClass].include?(mybool.class)
=> true
tig
  • 25,841
  • 10
  • 64
  • 96
user1966234
  • 71
  • 1
  • 2
4

So try this out (x == true) ^ (x == false) note you need the parenthesis but this is more beautiful and compact.

It even passes the suggested like "cuak" but not a "cuak"... class X; def !; self end end ; x = X.new; (x == true) ^ (x == false)

Note: See that this is so basic that you can use it in other languages too, that doesn't provide a "thing is boolean".

Note 2: Also you can use this to say thing is one of??: "red", "green", "blue" if you add more XORS... or say this thing is one of??: 4, 5, 8, 35.

tyoc213
  • 1,223
  • 18
  • 21
3

This gem adds a Boolean class to Ruby with useful methods.

https://github.com/RISCfuture/boolean

Use:

require 'boolean'

Then your

true.is_a?(Boolean)
false.is_a?(Boolean)

will work exactly as you expect.

Convincible
  • 314
  • 2
  • 10
-1

No. Not like you have your code. There isn't any class named Boolean. Now with all the answers you have you should be able to create one and use it. You do know how to create classes don't you? I only came here because I was just wondering this idea myself. Many people might say "Why? You have to just know how Ruby uses Boolean". Which is why you got the answers you did. So thanks for the question. Food for thought. Why doesn't Ruby have a Boolean class?

NameError: uninitialized constant Boolean

Keep in mind that Objects do not have types. They are classes. Objects have data. So that's why when you say data types it's a bit of a misnomer.

Also try rand 2 because rand 1 seems to always give 0. rand 2 will give 1 or 0 click run a few times here. https://repl.it/IOPx/7

Although I wouldn't know how to go about making a Boolean class myself. I've experimented with it but...

class Boolean < TrueClass
  self
end

true.is_a?(Boolean) # => false
false.is_a?(Boolean) # => false

At least we have that class now but who knows how to get the right values?

Douglas G. Allen
  • 2,203
  • 21
  • 20