Comment vérifier si un objet Ruby est un booléen

122

Je n'arrive pas à vérifier si un objet est un booléen facilement. Y a-t-il quelque chose comme ça dans Ruby?

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

En ce moment, je fais ceci et je voudrais le raccourcir:

some_var = rand(1) == 1 ? true : false
(some_var.is_a?(TrueClass) || some_var.is_a?(FalseClass))
Lance Pollard
la source

Réponses:

136

Le moyen le plus simple auquel je puisse penser:

# checking whether foo is a boolean
!!foo == foo
Konstantin Haase
la source
6
classe X; def!; fin de soi; x = X.new; !! x == x # => true
Alexey
5
Oui, cela s'appelle le typage canard et un principe de base de la POO. Je pense que c'est une fonctionnalité.
Konstantin Haase
62
Court ne veut pas nécessairement dire simple. Par quoi je veux dire, qu'est-ce que c'est?
Grant Birchmeier
11
Transforme foo en booléen, vérifie si c'est la même chose que foo.
Konstantin Haase
9
Notez que la double négation est considérée comme un mauvais style par certains contrôleurs (comme RuboCop ).
sschuberth
104

Je trouve cela concis et auto-documenté:

[true, false].include? foo

Si vous utilisez Rails ou ActiveSupport, vous pouvez même effectuer une requête directe en utilisant in?

foo.in? [true, false]

La vérification par rapport à toutes les valeurs possibles n'est pas quelque chose que je recommande pour les flottants, mais c'est faisable lorsqu'il n'y a que deux valeurs possibles!

Mahemoff
la source
1
meilleure réponse de loin, même si j'ai aussi aimé foo == true or foo == falseque quelqu'un mette un commentaire.
Ryan Taylor
3
J'aime cela parce que son intention est moins cryptique que le !!foo == foo.
stringsn88keys
Franchement pythonique! Certainement la réponse la plus sémantique ici de loin.
JM Janzen
85

Il n'y a pas de Booleanclasse dans Ruby, la seule façon de vérifier est de faire ce que vous faites (comparer l'objet avec trueet falseou la classe de l'objet avec TrueClassetFalseClass ). Vous ne savez pas pourquoi vous auriez besoin de cette fonctionnalité, pouvez-vous expliquer? :)

Si vous avez vraiment besoin de cette fonctionnalité, vous pouvez la pirater dans:

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

true.is_a?(Boolean) #=> true
false.is_a?(Boolean) #=> true
horseyguy
la source
1
essayer de faire du typage en fonction de la valeur actuelle.
Lance Pollard
75
«Pourquoi as-tu jamais fait ça? (et ses dérivés) n'est qu'une des questions les plus ennuyeuses qu'un ingénieur puisse en poser :)
vemv
11
+1 parce que je peux utiliser ceci dans rspec comme:expect(some_method?(data)).to be_a(Boolean)
Automatico
3
Un autre cas où vous devez vérifier le type, c'est lorsque vous implémentez un adaptateur de base de données et que vous avez besoin de chaînes enveloppantes avec "quotes"mais pas de nombres et de booléens
Daniel Garmoshka
23

Comme indiqué ci-dessus, il n'y a pas de classe booléenne juste TrueClass et FalseClass, mais vous pouvez utiliser n'importe quel objet comme sujet de if / sauf et tout est vrai sauf les instances de FalseClass et nil

Les tests booléens retournent une instance de FalseClass ou TrueClass

(1 > 0).class #TrueClass

Le monkeypatch suivant à Object vous dira si quelque chose est une instance de TrueClass ou FalseClass

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

L'exécution de certains tests avec irb donne les résultats suivants

?> "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
la source
4
Plus simple à écrire self == true or self == false. Ce sont les seules instances de TrueClass et FalseClass.
Chuck
@chuck qui renvoie les mêmes résultats sauf pour Time.now.boolean? qui renvoie nul. Une idée pourquoi?
Steve Weet
Définir un contrôle de classe sur soi dans la méthode n'est pas quelque chose de bon. Vous devez définir deux versions de boolean, une pour TrueClass / FalseClass et une pour Object.
Konstantin Haase
4
La raison en est qu'un bogue dans la version de Time#==dans Ruby 1.8 fait qu'une comparaison avec des valeurs non-Time renvoie nil plutôt que faux.
Chuck
17

Si votre code peut raisonnablement être écrit comme une déclaration de cas, c'est assez décent:

case mybool
when TrueClass, FalseClass
  puts "It's a bool!"
else
  puts "It's something else!"
end
Henrik N
la source
6

Un objet qui est un booléen aura soit une classe de TrueClass ou FalseClass donc le one-liner suivant devrait faire l'affaire

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

Ce qui suit vous donnera également un résultat de vérification de type booléen vrai / faux

mybool = true    
[TrueClass, FalseClass].include?(mybool.class)
=> true
user1966234
la source
4

Alors essayez cette (x == true) ^ (x == false)note, vous avez besoin de la parenthèse mais c'est plus beau et compact.

Il passe même le suggéré comme "cuak" mais pas un "cuak" ... class X; def !; self end end ; x = X.new; (x == true) ^ (x == false)

Remarque : voyez que c'est tellement basique que vous pouvez aussi l'utiliser dans d'autres langues, cela ne fournit pas de "chose est booléenne".

Note 2 : Vous pouvez également utiliser ceci pour dire que la chose est l'une des ??: "red", "green", "blue"si vous add more XORS... ou dites que cette chose est l'une des ??: 4, 5, 8, 35.

tyoc213
la source
Pourquoi XOR? Pourquoi pas OU?
Nakilon
2

Ce bijou ajoute une classe booléenne à Ruby avec des méthodes utiles.

https://github.com/RISCfuture/boolean

Utilisation:

require 'boolean'

Alors votre

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

fonctionnera exactement comme vous le souhaitez.

Convaincant
la source
0

Non, pas comme si vous aviez votre code. Il n'y a aucune classe nommée Boolean. Maintenant, avec toutes les réponses que vous avez, vous devriez pouvoir en créer une et l'utiliser. Vous savez comment créer des classes, n'est-ce pas? Je ne suis venu ici que parce que je me demandais moi-même cette idée. Beaucoup de gens pourraient dire "Pourquoi? Vous devez simplement savoir comment Ruby utilise Boolean". C'est pourquoi vous avez obtenu les réponses que vous avez faites. Alors merci pour la question. Nourriture pour la pensée. Pourquoi Ruby n'a-t-il pas de classe booléenne?

NameError: uninitialized constant Boolean

Gardez à l'esprit que les objets n'ont pas de types. Ce sont des classes. Les objets ont des données. C'est pourquoi, lorsque vous dites les types de données, c'est un peu un abus de langage.

Essayez aussi rand 2 car rand 1 semble toujours donner 0. rand 2 donnera 1 ou 0 clic plusieurs fois ici. https://repl.it/IOPx/7

Bien que je ne sache pas comment faire moi-même une classe booléenne. Je l'ai expérimenté mais ...

class Boolean < TrueClass
  self
end

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

Au moins, nous avons cette classe maintenant, mais qui sait comment obtenir les bonnes valeurs?

Douglas G. Allen
la source