Ruby tiene una idea universal de " veracidad " y " falsedad ".
Rubí hace tener dos clases específicas de objetos de tipo booleano, TrueClass
y FalseClass
, con instancias singleton denotados por las variables especiales true
y false
, respectivamente.
Sin embargo, la veracidad y la falsedad no se limitan a las instancias de esas dos clases, el concepto es universal y se aplica a todos los objetos en Ruby. Todo objeto es verdadero o falso . Las reglas son muy simples. En particular, solo dos objetos son falsos :
nil
, la instancia singleton deNilClass
yfalse
, la instancia singleton deFalseClass
Todo otro objeto es verdadero . Esto incluye incluso objetos que se consideran falsos en otros lenguajes de programación, como
Estas reglas están integradas en el lenguaje y no son definibles por el usuario. No hay to_bool
conversión implícita ni nada similar.
Aquí hay una cita de la especificación ISO Ruby Language :
6.6 Valores booleanos
Un objeto se clasifica en un objeto verdadero o un objeto falso .
Solo falso y nulo son objetos falsos. falso es la única instancia de la clase
FalseClass
(ver 15.2.6), a la que se evalúa una expresión falsa (ver 11.5.4.8.3). nil es la única instancia de la claseNilClass
(ver 15.2.4), a la que se evalúa una expresión nil (ver 11.5.4.8.2).Los objetos distintos de falso y nulo se clasifican en objetos verdaderos. verdadero es la única instancia de la clase
TrueClass
(ver 15.2.5), a la que se evalúa una expresión verdadera (ver 11.5.4.8.3).
El ejecutable Ruby / Spec parece estar de acuerdo :
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
Según esas dos fuentes, supongo que los Regexp
s también son verdaderos , pero según mis pruebas, no lo son:
if // then 'Regexps are truthy' else 'Regexps are falsy' end
#=> 'Regexps are falsy'
Probé esto en YARV 2.7.0-preview1 , TruffleRuby 19.2.0.1 y JRuby 9.2.8.0 . Las tres implementaciones están de acuerdo entre sí y no están de acuerdo con la especificación ISO Ruby Language y mi interpretación de Ruby / Spec.
Más precisamente, los Regexp
objetos que son el resultado de evaluar Regexp
literales son falsos , mientras Regexp
que los objetos que son el resultado de alguna otra expresión son verdaderos :
r = //
if r then 'Regexps are truthy' else 'Regexps are falsy' end
#=> 'Regexps are truthy'
¿Es esto un error o un comportamiento deseado?
Regex.new("a")
es verdad.!!//
es falso pero!!/r/
es cierto Extraño de hecho.!!/r/
producefalse
para mí usando (RVM) Ruby 2.4.1.//
en elif // then
se interpreta como una prueba (un acceso directo paraif //=~nil then
) (que es siempre Falsy cualquiera que sea el patrón) y no como una instancia Regexp.Respuestas:
Esto no es un error. Lo que está sucediendo es que Ruby está reescribiendo el código para que
efectivamente se convierte
Si está ejecutando este código en un script normal (y no está utilizando la
-e
opción), debería ver una advertencia:Probablemente esto sea algo confuso la mayor parte del tiempo, por eso se da la advertencia, pero puede ser útil para una línea utilizando la
-e
opción Por ejemplo, puede imprimir todas las líneas que coinciden con una expresión regular dada de un archivo con(El argumento predeterminado para
print
es$_
también.)fuente
-n
,-p
,-a
y-l
opciones, así como el puñado de métodos Kernel que sólo están disponibles cuando-n
o-p
se utilizan (chomp
,chop
,gsub
ysub
).NODE_LIT
con el tipoT_REGEXP
. El que publicó en su respuesta es para un literal dinámicoRegexp
, es decir, unRegexp
literal que utiliza interpolación, por ejemplo/#{''}/
.$_
como un nodo que el compilador maneja de forma normal, mientras que en el caso estático todo es manejado por compilador. Lo cual es una pena para mí porque "oye, puedes ver dónde se reescribe el árbol de análisis aquí" es una buena respuesta.Este es el resultado de (por lo que puedo decir) una característica indocumentada del lenguaje ruby, que se explica mejor con esta especificación :
En general, se puede considerar
$_
como la "última cadena leída porgets
"Para hacer las cosas aún más confusas,
$_
(junto con$-
) no es una variable global; Tiene alcance local .Cuando un script ruby comienza,
$_ == nil
.Entonces, el código:
Se interpreta como:
... Que vuelve falsey.
Por otro lado, para una expresión regular no literal (por ejemplo,
r = //
orRegexp.new('')
), esta interpretación especial no se aplica.//
es veraz al igual que todos los demás objetos en rubí además denil
yfalse
.A menos que ejecute un script ruby directamente en la línea de comando (es decir, con la
-e
bandera), el analizador ruby mostrará una advertencia contra dicho uso:Usted podría hacer uso de este comportamiento en un guión, con algo como:
... Pero sería más normal asignar una variable local al resultado
gets
y realizar la comprobación de expresiones regulares contra este valor explícitamente.No conozco ningún caso de uso para realizar esta verificación con una expresión regular vacía , especialmente cuando se define como un valor literal. El resultado que ha resaltado realmente sorprendería a la mayoría de los desarrolladores de ruby con la guardia baja.
fuente
!// #=> true
tiene el mismo comportamiento y no está en un condicional. No pude encontrar ningún contexto booleano (condicional o no), donde se comporta como se esperaba.!// ? true : false
devolucionestrue
? Creo que este es el mismo punto nuevamente: se está interpretando como:!(// =~ nil) ? true : false
$_ = 'hello world'
antes de ejecutar el código anterior, entonces debería obtener un resultado diferente, porque// =~ 'hello world'
, pero no coincidenil
.!//
sin el condicional evalúa atrue
. La especificación que citó es sobre unRegexp
literal en condicional, pero en este ejemplo, no hay condicional, por lo que esta especificación no se aplica.puts !//; $_ = ''; puts !//
- Supongo que porque el analizador lo expande como una macro; no necesariamente tiene que estar dentro de un condicional?