Esiste un Ruby o Ruby-ism per not_nil? opposto di zero? metodo?


87

Non ho esperienza in Ruby, quindi il mio codice sembra "brutto" e non idiomatico:

def logged_in?
  !user.nil?
end

Preferisco qualcosa di simile

def logged_in?
  user.not_nil?
end

Ma non riesco a trovare un tale metodo che si opponga nil?

Risposte:


51

quando usi ActiveSupport, c'è user.present? http://api.rubyonrails.org/classes/Object.html#method-i-present%3F , per controllare solo se non è nullo, perché non usare

def logged_in?
  user # or !!user if you really want boolean's
end

48
Attenzione: present?richiede una stringa non vuota. ! "".nil?restituisce true, ma "".present?restituisce false.
lambshaanxy

9
Attenzione 2: noterò anche che !! user NON distingue tra user nil e user false; l'uso del double-bang fonde questi due. Quindi, se vuoi veramente determinare se un oggetto non è nullo (significa, è: vero, falso, 0, "", qualcosa di diverso da zero), devi usare l'approccio 'brutto' che a berkes non piace o il monkeypatch che @Tempus propone di seguito . Naturalmente, in questo caso in cui non nullo è non necessaria (un utente in Rails), l'approccio adottato dal Samo è la meno brutta, imo.
likethesky

12
false.present? == false !false.nil? == true
Dudo

3
Questa risposta non risponde affatto alla domanda posta. È una risposta a questo particolare problema di implementazione.
Ekkstein

3
Questa risposta non è corretta. false.nil? è falso, mentre falso.presente? è ANCHE falso!
Mike

49

Sembri eccessivamente preoccupato per i booleani.

def logged_in?
  user
end

Se l'utente è nullo, allora loggato_in? restituirà un valore "falso". Altrimenti, restituirà un oggetto. In Ruby non abbiamo bisogno di restituire true o false, poiché abbiamo valori "true" e "falsey" come in JavaScript.

Aggiornare

Se stai usando Rails, puoi renderlo più leggibile usando il present?metodo:

def logged_in?
  user.present?
end

1
L'aspettativa con un metodo che termina con a ?è che restituisca un valore booleano. !!valueè il modo classico per convertire qualsiasi cosa in un booleano. Non esattamente lo stesso, ma in questo caso Object#present?in RoR è anche un bene.
Tokland

questo si rompe effettivamente in Ruby 2.4 con Path! [43] (pry) # <ReactOnRails :: AssetsPrecompile>: 0> assets_path.blank? true [44] (pry) # <ReactOnRails :: AssetsPrecompile>: 0> assets_path.to_s "/ var / folders / rp / _k99k0pn0rsb4d3lm9l3dnjh0000gn / T / d20170603-96466-zk7di7" [45] :: ReactecRails >: 0> assets_path.present? false [46] (pry) # <ReactOnRails :: AssetsPrecompile>: 0> assets_path.nil? false
justingordon

25

Fai attenzione alle altre risposte che si presentano present?come risposta alla tua domanda.

present?è l'opposto di blank?in rails.

present?controlla se esiste un valore significativo. Queste cose possono fallire un present?controllo:

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

Mentre un !nil?controllo dà:

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

nil?controlla se un oggetto è effettivamente nil. Tutto il resto: una stringa vuota, 0, false, qualunque sia, non è nil.

present?è molto utile, ma sicuramente non il contrario di nil?. Confondere i due può portare a errori imprevisti.

Per il tuo caso d'uso present?funzionerà, ma è sempre saggio essere consapevoli della differenza.


Dovrebbe essere incluso nella risposta accettata. false.blank?non è uguale afalse.nil?
Yason

present?interrogherà il tuo database, nil?no, starai attento
Tony

17

Forse questo potrebbe essere un approccio:

class Object
  def not_nil?
    !nil?
  end
end

Buona idea. Ne deduco che non c'è not_nil? in Ruby. Ma questo non dovrebbe essere !self.nil?piuttosto allora !nil?o è selfimplicito?
berkes

3
Non hai bisogno di te stesso. Sarà implicito.
Geo

Self è implicito quando si legge da metodi di istanza (o accessor, che in realtà sono solo metodi). Quando si impostano i valori, verrà creata una variabile locale al metodo prima che Ruby controlli l'istanza della classe per un metodo setter con lo stesso nome. Regola generale: se hai un attr_accessor chiamato xxx, usa "self.xxx = 3" (impostando un valore) o "temp = xxx" (leggendo il valore). L'utilizzo di "xxx = 3" non aggiornerà la funzione di accesso, ma creerà semplicemente una nuova variabile nell'ambito del metodo.
A Fader Darkly

4

Puoi semplicemente usare quanto segue:

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

Questo non funziona solo per zero ma anche per false ecc., Quindi dovresti provare per vedere se funziona nel tuo caso d'uso.


4

Posso offrire il !metodo Ruby sul risultato del nil?metodo.

def logged_in?
  user.nil?.!
end

Così esoterico che RubyMine IDE lo contrassegnerà come un errore. ;-)


2

Sono arrivato a questa domanda cercando un metodo oggetto, in modo da poter usare la Symbol#to_procscorciatoia invece di un blocco; Trovo arr.find(&:not_nil?)un po 'più leggibile di arr.find { |e| !e.nil? }.

Il metodo che ho trovato è Object#itself. Nel mio utilizzo, volevo trovare il valore in un hash per la chiave name, dove in alcuni casi quella chiave veniva accidentalmente maiuscola come Name. Quella frase è la seguente:

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

Come notato in altre risposte , questo fallirà in modo spettacolare nei casi in cui stai testando un booleano.


In che modo è diverso da my_hash.values_at("Name", "name").find?
berkes

È esattamente lo stesso. Avevo un'altra logica nel mio originale mapche ho rimosso per semplicità in questo esempio, quindi come scritto qui è intercambiabile convalues_at . La parte importante è ciò a cui viene passato find.
Ian
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.