Czy istnieje Ruby lub Ruby-izm dla not_nil? przeciwieństwo zera? metoda?

87

Nie mam doświadczenia w Rubim, więc mój kod wydaje się „brzydki” i nie jest idiomatyczny:

def logged_in?
  !user.nil?
end

Wolałbym mieć coś takiego

def logged_in?
  user.not_nil?
end

Ale nie mogę znaleźć takiej metody, która jest sprzeczna nil?

Berkes
źródło

Odpowiedzi:

51

kiedy używasz ActiveSupport, jest user.present? http://api.rubyonrails.org/classes/Object.html#method-i-present%3F , aby sprawdzić, czy nie ma wartości zerowej, dlaczego nie użyć

def logged_in?
  user # or !!user if you really want boolean's
end
lwe
źródło
48
Uwaga: present?wymaga niepustego ciągu. ! "".nil?zwraca prawdę, ale "".present?zwraca fałsz.
lambshaanxy
9
Uwaga 2: Zauważę również, że !! użytkownik NIE rozróżnia pomiędzy użytkownikiem będącym zerowym a użytkownikiem fałszywym; użycie podwójnego huku łączy te dwa. Więc jeśli naprawdę chcesz ustalić, czy obiekt nie jest zerowy (czyli: prawda, fałsz, 0, „”, cokolwiek innego niż zero), musisz użyć „brzydkiego” podejścia, którego Berkes nie lubi lub monkeypatch, który @Tempus proponuje poniżej . Oczywiście w tym przypadku nie jest zerowa nie potrzebne (użytkownik w Rails), podejście przyjęte przez Samo to najmniej brzydkie, imo.
likethesky
12
false.present? == false !false.nil? == true
Dudo
3
Ta odpowiedź wcale nie odpowiada na zadane pytanie. To odpowiedź na ten konkretny problem implementacyjny.
Ekkstein
3
Ta odpowiedź jest nieprawidłowa. false.nil? jest fałszywe, a fałszywe. obecne? jest TAKŻE fałszywy!
Mike,
49

Wydajesz się zbytnio przejmować wartościami logicznymi.

def logged_in?
  user
end

Jeśli użytkownik ma wartość zero, to logged_in? zwróci wartość „falsey”. W przeciwnym razie zwróci obiekt. W Rubim nie musimy zwracać true ani false, ponieważ mamy wartości „truey” i „falsey”, jak w JavaScript.

Aktualizacja

Jeśli używasz Railsów, możesz ładniej to czytać używając present?metody:

def logged_in?
  user.present?
end
Samo
źródło
1
Oczekiwanie w przypadku metody kończącej się a ?jest takie, że zwraca wartość logiczną. !!valueto klasyczny sposób konwertowania czegokolwiek na wartość logiczną. Nie do końca to samo, ale w tym przypadku Object#present?w RoR też jest dobrze.
tokland
to faktycznie psuje się w Rubim 2.4 z Path! [43] (pry) # <ReactOnRails :: AssetsPrecompile>: 0> asset_path.blank? true [44] (pry) # <ReactOnRails :: AssetsPrecompile>: 0> asset_path.to_s "/ var / folders / rp / _k99k0pn0rsb4d3lm9l3dnjh0000gn / T / d20170603-96466-zk7di7" [45] (pryOnPR) # >: 0> asset_path.present? false [46] (pry) # <ReactOnRails :: AssetsPrecompile>: 0> asset_path.nil? false
justingordon
25

Uważaj na inne odpowiedzi przedstawiające present?odpowiedź na Twoje pytanie.

present?jest przeciwieństwem blank?w szynach.

present?sprawdza, czy istnieje znacząca wartość. Te rzeczy mogą się nie udać present?:

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

Natomiast !nil?czek daje:

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

nil?sprawdza, czy obiekt jest rzeczywiście nil. Coś jeszcze: pusty ciąg 0, falseniezależnie, nie jest nil.

present?jest bardzo przydatne, ale zdecydowanie nie jest przeciwieństwem nil?. Mylenie tych dwóch może prowadzić do nieoczekiwanych błędów.

Twój przypadek użycia present?zadziała, ale zawsze dobrze jest być świadomym różnicy.

A Fader Darkly
źródło
Powinien zostać uwzględniony w zaakceptowanej odpowiedzi. false.blank?to nie to samo, cofalse.nil?
Yason
present?zapyta twoją bazę danych, nil?nie, uważaj na to
Tony
17

Może to mogłoby być podejście:

class Object
  def not_nil?
    !nil?
  end
end
Geo
źródło
Dobry pomysł. Robię z tego, że nie ma not_nil? w języku Ruby. Ale czy !self.nil?raczej nie powinno tak być !nil?, czy też jest to selfdorozumiane?
berkes
3
Nie potrzebujesz siebie. Będzie to sugerowane.
Geo,
Self jest implikowane podczas czytania z metod instancji (lub akcesorów, które tak naprawdę są tylko metodami). Podczas ustawiania wartości, zmienna lokalna dla metody zostanie utworzona, zanim Ruby sprawdzi instancję klasy pod kątem metody ustawiającej o tej samej nazwie. Ogólna zasada: jeśli masz attr_accessor o nazwie xxx, użyj „self.xxx = 3” (ustawiając wartość) lub „temp = xxx” (odczytując wartość). Użycie „xxx = 3” nie zaktualizuje metody dostępu, po prostu utworzy nową zmienną w zakresie metody.
A Fader Darkly
4

Możesz po prostu użyć następujących:

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

To działa nie tylko w przypadku nil, ale także false itp., Więc powinieneś przetestować, czy działa w twoim przypadku.

Bitterzoet
źródło
4

Czy mogę zaoferować Ruby-esque ! metodę na wynikach tej nil?metody.

def logged_in?
  user.nil?.!
end

Tak ezoteryczne, że RubyMine IDE oznaczy to jako błąd. ;-)

Christopher Oezbek
źródło
2

Doszedłem do tego pytania, szukając metody obiektowej, abym mógł użyć Symbol#to_procskrótu zamiast bloku; Uważam, że jest arr.find(&:not_nil?)nieco bardziej czytelny niżarr.find { |e| !e.nil? } .

Metoda, którą znalazłem, to Object#itself. W moim przypadku chciałem znaleźć wartość w skrócie klucza name, gdzie w niektórych przypadkach ten klucz został przypadkowo zamieniony na wielką literę jako Name. Ten jednolinijkowy jest następujący:

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

Jak zauważono w innych odpowiedziach , zakończy się to spektakularnym niepowodzeniem w przypadkach, gdy testujesz wartość logiczną.

Ian
źródło
Czym to się różni od my_hash.values_at("Name", "name").find?
berkes
To jest dokładnie to samo. W oryginale miałem inną logikę map, którą usunąłem dla uproszczenia w tym przykładzie, więc jak napisano tutaj, jest ona wymienna values_at. Ważną częścią jest to, co jest przekazywane find.
Ian