¿Hay un rubí o un rubí para not_nil? opuesto a cero? ¿método?

87

No tengo experiencia en Ruby, por lo que mi código se siente "feo" y no idiomático:

def logged_in?
  !user.nil?
end

Prefiero tener algo como

def logged_in?
  user.not_nil?
end

Pero no puedo encontrar un método que se oponga nil?

Berkes
fuente

Respuestas:

51

cuando usa ActiveSupport, hay user.present? http://api.rubyonrails.org/classes/Object.html#method-i-present%3F , para verificar solo si no es nulo, ¿por qué no usar

def logged_in?
  user # or !!user if you really want boolean's
end
nosotros
fuente
48
Cuidado: present?requiere una cadena que no esté en blanco. ! "".nil?devuelve verdadero, pero "".present?devuelve falso.
lambshaanxy
9
Cuidado 2: también notaré que !! el usuario NO distingue entre el usuario es nulo y el usuario es falso; el uso de doble explosión combina esos dos. Entonces, si realmente desea determinar si un objeto no es nulo (es decir, es: verdadero, falso, 0, "", cualquier otra cosa que no sea nulo), debe usar el enfoque 'feo' que a Berkes no le gusta o el parche de mono que @Tempus propone a continuación . Por supuesto, en este caso en el que no se nulas no necesita (un usuario en rieles), el enfoque adoptado por Samo es el menos feo, imo.
likethesky
12
false.present? == false !false.nil? == true
Dudo
3
Esta respuesta no responde en absoluto a la pregunta formulada. Es una respuesta a este problema de implementación en particular.
Ekkstein
3
Esta respuesta no es correcta. false.nil? es falso, mientras que falso.presente? ¡TAMBIÉN es falso!
Mike
49

Parece demasiado preocupado por los valores booleanos.

def logged_in?
  user
end

Si el usuario es nulo, entonces log_in? devolverá un valor "falsey". De lo contrario, devolverá un objeto. En Ruby no necesitamos devolver verdadero o falso, ya que tenemos valores de "verdadero" y "falso" como en JavaScript.

Actualizar

Si está usando Rails, puede hacer que esto se lea mejor usando el present?método:

def logged_in?
  user.present?
end
Samo
fuente
1
La expectativa con un método que termina en a ?es que devuelva un booleano. !!valuees la forma clásica de convertir cualquier cosa a booleana. No es exactamente lo mismo, pero en este caso Object#present?en RoR también es bueno.
tokland
¡esto realmente se rompe en Ruby 2.4 con Path! [43] (palanca) # <ReactOnRails :: AssetsPrecompile>: 0> assets_path.blank? true [44] (palanca) # <ReactOnRails :: AssetsPrecompile>: 0> ruta_activos.to_s "/ var / carpetas / rp / _k99k0pn0rsb4d3lm9l3dnjh0000gn / T / d20170603-96466-zk7di7" [45] (AssetsnPy) >: 0> assets_path.present? falso [46] (palanca) # <ReactOnRails :: AssetsPrecompile>: 0> assets_path.nil? falso
justingordon
25

Tenga cuidado con otras respuestas que se presentan present?como una respuesta a su pregunta.

present?es lo contrario de blank?en rieles.

present?comprueba si hay un valor significativo. Estas cosas pueden fallar en una present?verificación:

"".present? # false
"    ".present? # false
[].present? # false
false.present? # false
YourActiveRecordModel.where("false = true").present? # false

Mientras que un !nil?cheque da:

!"".nil? # true
!"    ".nil? # true
![].nil? # true
!false.nil? # true
!YourActiveRecordModel.where("false = true").nil? # true

nil?comprueba si un objeto es realmente nil. Cualquier otra cosa: una cadena vacía, 0, false, lo que sea, no es nil.

present?es muy útil, pero definitivamente no es lo contrario de nil?. Confundir los dos puede provocar errores inesperados.

Porque su caso de uso present?funcionará, pero siempre es aconsejable ser consciente de la diferencia.

Un atenuador oscuro
fuente
Debe incluirse en la respuesta aceptada. false.blank?no es lo mismo quefalse.nil?
Yason
present?consultará su base de datos, nil?no, tenga cuidado con eso
Tony
17

Quizás este podría ser un enfoque:

class Object
  def not_nil?
    !nil?
  end
end
Geo
fuente
Buena idea. Hago de esto que no hay not_nil? en Ruby. Pero, ¿no debería ser !self.nil?más bien entonces !nil?, o está selfimplícito?
Berkes
3
No te necesitas a ti mismo. Estará implícito.
Geo
Self está implícito cuando se lee desde métodos de instancia (o accesores, que en realidad son solo métodos). Al establecer valores, se creará una variable local al método antes de que Ruby verifique la instancia de la clase para un método de establecimiento del mismo nombre. Regla general: si tiene un attr_accessor llamado xxx, use "self.xxx = 3" (estableciendo un valor) o "temp = xxx" (leyendo el valor). El uso de "xxx = 3" no actualizará el descriptor de acceso, solo creará una nueva variable en el alcance del método.
A Fader Darkly
4

Puedes usar lo siguiente:

if object
  p "object exists"
else
  p "object does not exist"
end

Esto no solo funciona para nil sino también falso, etc., por lo que debe probar para ver si funciona en su caso de uso.

Bitterzoet
fuente
4

¿Puedo ofrecer el !método Ruby-esque sobre el resultado del nil?método?

def logged_in?
  user.nil?.!
end

Tan esotérico que RubyMine IDE lo marcará como un error. ;-)

Christopher Oezbek
fuente
2

Llegué a esta pregunta buscando un método de objeto, para poder usar la Symbol#to_proctaquigrafía en lugar de un bloque; Encuentro arr.find(&:not_nil?)algo más legible que arr.find { |e| !e.nil? }.

El método que encontré es Object#itself. En mi uso, quería encontrar el valor en un hash para la clave name, donde en algunos casos esa clave se capitalizó accidentalmente como Name. Esa frase es la siguiente:

# Extract values for several possible keys 
#   and find the first non-nil one
["Name", "name"].map { |k| my_hash[k] }.find(&:itself)

Como se señaló en otras respuestas , esto fallará espectacularmente en los casos en que esté probando un booleano.

Ian
fuente
¿En qué se diferencia eso de my_hash.values_at("Name", "name").find?
berkes
Es exactamente lo mismo. Tenía alguna otra lógica en mi original mapque eliminé por simplicidad en este ejemplo, así que como está escrito aquí es intercambiable values_at. La parte importante es a lo que se le pasa find.
Ian