Gibt es einen Ruby oder Ruby-Ismus für not_nil? Gegenteil von Null? Methode?

87

Ich habe keine Erfahrung mit Ruby, daher fühlt sich mein Code "hässlich" und nicht idiomatisch an:

def logged_in?
  !user.nil?
end

Ich hätte lieber so etwas

def logged_in?
  user.not_nil?
end

Kann aber keine solche Methode finden, die sich widerspricht nil?

berkes
quelle

Antworten:

51

Wenn Sie ActiveSupport verwenden, gibt es user.present? http://api.rubyonrails.org/classes/Object.html#method-i-present%3F , um nur auf Nicht-Null zu prüfen, warum nicht verwenden

def logged_in?
  user # or !!user if you really want boolean's
end
lwe
quelle
48
Achtung: present?erfordert eine nicht leere Zeichenfolge. ! "".nil?gibt true zurück, gibt aber "".present?false zurück.
Lammhaanxy
9
Achtung 2: Ich werde auch beachten, dass !! Benutzer NICHT zwischen Benutzer Null und Benutzer Falsch unterscheidet. Die Doppelknall-Nutzung verbindet diese beiden. Wenn Sie also wirklich feststellen möchten, ob ein Objekt nicht Null ist (dh: wahr, falsch, 0, "", etwas anderes als Null), müssen Sie den 'hässlichen' Ansatz verwenden, den berkes nicht mag oder das Monkeypatch, das @Tempus unten vorschlägt . Natürlich in diesem Fall , in dem nicht gleich Null ist nicht (ein Benutzer in Rails) benötigt, der Ansatz von Samo ist die am wenigsten hässlich, imo.
likethesky
12
false.present? == false !false.nil? == true
Dudo
3
Diese Antwort beantwortet die gestellte Frage überhaupt nicht. Es ist eine Antwort auf dieses spezielle Implementierungsproblem.
Ekkstein
3
Diese Antwort ist nicht korrekt. false.nil? ist falsch, während false.present? ist AUCH falsch!
Mike
49

Sie scheinen übermäßig besorgt über Boolesche Werte zu sein.

def logged_in?
  user
end

Wenn der Benutzer Null ist, dann angemeldet? gibt einen "Falsey" -Wert zurück. Andernfalls wird ein Objekt zurückgegeben. In Ruby müssen wir weder true noch false zurückgeben, da wir wie in JavaScript "truey" - und "falsey" -Werte haben.

Aktualisieren

Wenn Sie Rails verwenden, können Sie dies mithilfe der folgenden present?Methode besser lesen :

def logged_in?
  user.present?
end
Samo
quelle
1
Die Erwartung bei einer Methode, die mit a endet, ?ist, dass sie einen Booleschen Wert zurückgibt. !!valueist der klassische Weg, etwas in einen Booleschen Wert umzuwandeln. Nicht genau das gleiche, aber in diesem Fall ist Object#present?RoR auch gut.
Tokand
Dies bricht tatsächlich in Ruby 2.4 mit 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] (pryP) >: 0> assets_path.present? false [46] (pry) # <ReactOnRails :: AssetsPrecompile>: 0> assets_path.nil? false
justingordon
23

Passen Sie auf andere Antworten auf, die present?als Antwort auf Ihre Frage angezeigt werden.

present?ist das Gegenteil von blank?in Schienen.

present?prüft, ob ein aussagekräftiger Wert vorliegt. Diese Dinge können eine present?Prüfung nicht bestehen:

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

Während ein !nil?Scheck ergibt:

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

nil?prüft, ob ein Objekt tatsächlich ist nil. Alles andere: ein leerer String, 0, false, was auch immer, ist nicht nil.

present? ist sehr nützlich, aber definitiv nicht das Gegenteil von nil? . Die Verwechslung der beiden kann zu unerwarteten Fehlern führen.

Für Ihren Anwendungsfall present?wird es funktionieren, aber es ist immer ratsam, sich des Unterschieds bewusst zu sein.

Ein Fader dunkel
quelle
Sollte in der akzeptierten Antwort enthalten sein. false.blank?ist nicht dasselbe wiefalse.nil?
Yason
17

Vielleicht könnte dies ein Ansatz sein:

class Object
  def not_nil?
    !nil?
  end
end
Geo
quelle
Gute Idee. Ich mache daraus, dass es kein not_nil gibt? in Ruby. Aber sollte das nicht !self.nil?eher so sein !nil?oder ist es selfimplizit?
Berkeley
3
Du brauchst dich nicht. Es wird impliziert.
Geo
Selbst wird beim Lesen von Instanzmethoden (oder Zugriffsmethoden, die eigentlich nur Methoden sind) impliziert. Beim Festlegen von Werten wird eine für die Methode lokale Variable erstellt, bevor Ruby die Klasseninstanz auf eine gleichnamige Setter-Methode überprüft. Allgemeine Regel: Wenn Sie einen attr_accessor namens xxx haben, verwenden Sie "self.xxx = 3" (Festlegen eines Werts) oder "temp = xxx" (Lesen des Werts). Wenn Sie "xxx = 3" verwenden, wird der Accessor nicht aktualisiert. Erstellen Sie einfach eine neue Variable im Methodenbereich.
Ein Fader dunkel
4

Sie können einfach Folgendes verwenden:

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

Dies funktioniert nicht nur für Null, sondern auch für Falsch usw. Daher sollten Sie testen, ob es in Ihrem Anwendungsfall funktioniert.

Bitterzoet
quelle
3

Darf ich die Ruby-ähnliche !Methode für das Ergebnis der nil?Methode anbieten?

def logged_in?
  user.nil?.!
end

So esoterisch, dass RubyMine IDE es als Fehler kennzeichnet. ;-);

Christopher Oezbek
quelle
2

Ich kam zu dieser Frage und suchte nach einer Objektmethode, damit ich die Symbol#to_procKurzschrift anstelle eines Blocks verwenden konnte. Ich finde arr.find(&:not_nil?)etwas lesbarer alsarr.find { |e| !e.nil? } .

Die Methode, die ich gefunden habe, ist Object#itself. In meiner Verwendung wollte ich den Wert in einem Hash für den Schlüssel finden name, wobei dieser Schlüssel in einigen Fällen versehentlich als groß geschrieben wurde Name. Dieser Einzeiler ist wie folgt:

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

Wie in anderen Antworten erwähnt , schlägt dies in Fällen, in denen Sie einen Booleschen Wert testen, spektakulär fehl.

Ian
quelle
Wie unterscheidet sich das von my_hash.values_at("Name", "name").find?
Berkeley
Es ist genau das gleiche. Ich hatte eine andere Logik in meinem Original map, die ich der Einfachheit halber in diesem Beispiel entfernt habe. Wie hier geschrieben, ist sie austauschbar mit values_at. Der wichtige Teil ist, was weitergegeben wird find.
Ian