Ruby a une idée universelle de « véracité » et de « fausseté ».
Ruby n'ont deux classes spécifiques pour les objets Boolean, et , avec les instances singleton désignés par les variables spéciales et , respectivement.TrueClass
FalseClass
true
false
Cependant, la véracité et la fausseté ne sont pas limitées aux instances de ces deux classes, le concept est universel et s'applique à chaque objet unique dans Ruby. Chaque objet est soit vrai soit faux . Les règles sont très simples. En particulier, seuls deux objets sont faux :
nil
, l'instance singleton deNilClass
etfalse
, l'instance singleton deFalseClass
Chaque autre objet est véridique . Cela inclut même les objets qui sont considérés comme faux dans d'autres langages de programmation, tels que
Ces règles sont intégrées dans la langue et ne sont pas définissables par l'utilisateur. Il n'y a pas de to_bool
conversion implicite ou quelque chose de similaire.
Voici une citation de la spécification ISO Ruby Language :
6.6 Valeurs booléennes
Un objet est classé en un objet vrai ou un objet faux .
Seuls faux et nil sont des objets faux. false est la seule instance de la classe
FalseClass
(voir 15.2.6) à laquelle une fausse expression est évaluée (voir 11.5.4.8.3). nil est la seule instance de la classeNilClass
(voir 15.2.4) à laquelle une expression nil est évaluée (voir 11.5.4.8.2).Les objets autres que faux et nul sont classés en objets vrais. true est la seule instance de la classe
TrueClass
(voir 15.2.5) à laquelle une expression vraie est évaluée (voir 11.5.4.8.3).
L'exécutable Ruby / Spec semble d'accord :
it "considers a non-nil and non-boolean object in expression result as true" do if mock('x') 123 else 456 end.should == 123 end
Selon ces deux sources, je suppose que les Regexp
s sont également véridiques , mais selon mes tests, ils ne le sont pas:
if // then 'Regexps are truthy' else 'Regexps are falsy' end
#=> 'Regexps are falsy'
J'ai testé cela sur YARV 2.7.0-preview1 , TruffleRuby 19.2.0.1 et JRuby 9.2.8.0 . Les trois implémentations sont en accord et en désaccord avec la spécification ISO Ruby Language et mon interprétation de Ruby / Spec.
Plus précisément, les Regexp
objets qui sont le résultat de l'évaluation des Regexp
littéraux sont faux , alors que les Regexp
objets qui sont le résultat d'une autre expression sont véridiques :
r = //
if r then 'Regexps are truthy' else 'Regexps are falsy' end
#=> 'Regexps are truthy'
Est-ce un bug ou un comportement souhaité?
Regex.new("a")
est intéressant, c'est que c'est vrai.!!//
est faux mais!!/r/
vrai. Étrange en effet.!!/r/
produitfalse
pour moi en utilisant (RVM) Ruby 2.4.1.//
dansif // then
est interprété comme un test (un raccourci pourif //=~nil then
) (qui est toujours faux quel que soit le motif) et non comme une instance Regexp.Réponses:
Ce n'est pas un bug. Ce qui se passe, c'est que Ruby réécrit le code pour que
devient effectivement
Si vous exécutez ce code dans un script normal (et n'utilisez pas l'
-e
option), vous devriez voir un avertissement:C'est probablement un peu déroutant la plupart du temps, c'est pourquoi l'avertissement est donné, mais peut être utile pour une ligne utilisant l'
-e
option. Par exemple, vous pouvez imprimer toutes les lignes correspondant à une expression rationnelle donnée à partir d'un fichier avec(L'argument par défaut de l'
print
est$_
également.)la source
-n
,-p
,-a
et-l
options, ainsi que la poignée de méthodes du noyau qui ne sont disponibles que lorsque-n
ou-p
sont utilisés (chomp
,chop
,gsub
etsub
).NODE_LIT
avec typeT_REGEXP
. Celui que vous avez publié dans votre réponse concerne un littéral dynamiqueRegexp
, c'est-à-dire unRegexp
littéral qui utilise l'interpolation, par exemple/#{''}/
.$_
tant que nœud que le compilateur gère normalement, tandis que dans le cas statique, tout est traité par le compilateur. Ce qui est dommage pour moi car "hé, vous pouvez voir où l'arbre d'analyse est réécrit ici" fait une belle réponse.C'est le résultat (pour autant que je sache) d'une fonctionnalité non documentée du langage ruby, qui s'explique mieux par cette spécification :
Vous pouvez généralement penser
$_
à la "dernière chaîne lue pargets
"Pour rendre les choses encore plus confuses,
$_
(avec$-
) n'est pas une variable globale; il a une portée locale .Lorsqu'un script Ruby démarre,
$_ == nil
.Donc, le code:
S'interprète comme:
... Ce qui renvoie falsey.
En revanche, pour une expression rationnelle non littérale (par exemple
r = //
ouRegexp.new('')
), cette interprétation spéciale ne s'applique pas.//
est véridique; comme tous les autres objets en rubis en plusnil
etfalse
.À moins d'exécuter un script ruby directement sur la ligne de commande (c'est-à-dire avec le
-e
drapeau), l'analyseur ruby affichera un avertissement contre une telle utilisation:Vous pouvez utiliser ce comportement dans un script, avec quelque chose comme:
... Mais il serait plus normal d'affecter une variable locale au résultat
gets
et d'effectuer la vérification d'expression régulière par rapport à cette valeur explicitement.Je ne connais aucun cas d'utilisation pour effectuer cette vérification avec une expression régulière vide , en particulier lorsqu'elle est définie comme une valeur littérale. Le résultat que vous avez mis en évidence surprendrait en effet la plupart des développeurs de rubis.
la source
!// #=> true
a le même comportement et n'est pas conditionnel. Je n'ai trouvé aucun contexte booléen (conditionnel ou non), où il se comporte comme prévu.!// ? true : false
retourstrue
? Je pense que c'est encore le même point - il est interprété comme:!(// =~ nil) ? true : false
$_ = 'hello world'
avant d'exécuter le code ci-dessus, vous devriez obtenir un résultat différent - car// =~ 'hello world'
, mais ne correspond pasnil
.!//
sans l' évaluation conditionnelletrue
. La spécification que vous avez citée concerne unRegexp
littéral dans un conditionnel, mais dans cet exemple, il n'y a pas de conditionnel, donc cette spécification ne s'applique pas.puts !//; $_ = ''; puts !//
- Je suppose que l'analyseur le développe comme une macro; il n'a pas nécessairement besoin d'être dans un conditionnel?