Jak sprawdzić, czy obiekt Ruby jest logiczny

122

Nie mogę łatwo sprawdzić, czy obiekt jest wartością logiczną. Czy jest coś takiego w Rubim?

true.is_a?(Boolean)
false.is_a?(Boolean)

Teraz robię to i chciałbym to skrócić:

some_var = rand(1) == 1 ? true : false
(some_var.is_a?(TrueClass) || some_var.is_a?(FalseClass))
Lance Pollard
źródło

Odpowiedzi:

136

Najprościej przychodzi mi do głowy:

# checking whether foo is a boolean
!!foo == foo
Konstantin Haase
źródło
6
klasa X; def!; koniec własny; x = X.new; !! x == x # => true
Alexey
5
Tak, to się nazywa pisanie kaczkowe i podstawową zasadą OOP. Myślę, że to funkcja.
Konstantin Haase
62
Krótkie niekoniecznie oznacza proste. Przez co mam na myśli, wtf to jest?
Grant Birchmeier
11
Zamienia foo na wartość logiczną, sprawdza, czy to to samo, co foo.
Konstantin Haase,
9
Zauważ, że podwójna negacja jest uważana za zły styl przez niektóre warcaby (jak RuboCop ).
sschuberth
104

Uważam, że jest to zwięzłe i samodokumentujące się:

[true, false].include? foo

Jeśli używasz Rails lub ActiveSupport, możesz nawet wykonać bezpośrednie zapytanie za pomocą in?

foo.in? [true, false]

Sprawdzanie wszystkich możliwych wartości nie jest czymś, co polecałbym w przypadku wartości zmiennoprzecinkowych, ale jest wykonalne, gdy są tylko dwie możliwe wartości!

mahemoff
źródło
1
zdecydowanie najlepsza odpowiedź, chociaż podobało mi się też, foo == true or foo == falseże ktoś umieścił komentarz.
Ryan Taylor,
3
Podoba mi się to, ponieważ jest mniej tajemnicze w zamiarze niż !!foo == foo.
stringsn88keys
Po prostu pytoniczny! Zdecydowanie najbardziej semantyczna odpowiedź tutaj.
JM Janzen
85

W BooleanRubim nie ma klasy, jedynym sposobem sprawdzenia jest zrobienie tego, co robisz (porównanie obiektu z truei falselub klasą obiektu z TrueClassi FalseClass). Nie mogę jednak wymyślić, dlaczego potrzebujesz tej funkcji, czy możesz to wyjaśnić? :)

Jeśli jednak naprawdę potrzebujesz tej funkcji, możesz zhakować ją w:

module Boolean; end
class TrueClass; include Boolean; end
class FalseClass; include Boolean; end

true.is_a?(Boolean) #=> true
false.is_a?(Boolean) #=> true
koński
źródło
1
próbuje wykonać rzutowanie na podstawie bieżącej wartości.
Lance Pollard,
75
- Dlaczego miałbyś kiedykolwiek co to? (i pochodne) to tylko jedno z najbardziej irytujących pytań, jakie może zadać inżynier :)
vemv
11
+1, ponieważ mogę tego używać w rspec jak:expect(some_method?(data)).to be_a(Boolean)
Automatico
3
Innym przypadkiem, w którym trzeba sprawdzić typ, jest zaimplementowanie adaptera bazy danych i potrzeba zawijania ciągów z "quotes"liczbami i wartościami logicznymi, ale nie z liczbami i wartościami logicznymi
Daniel Garmoshka
23

Jak wspomniano powyżej, nie ma klasy boolowskiej tylko TrueClass i FalseClass, jednak możesz użyć dowolnego obiektu jako podmiotu if /orrow i wszystko jest prawdziwe z wyjątkiem instancji FalseClass i nil

Testy logiczne zwracają wystąpienie FalseClass lub TrueClass

(1 > 0).class #TrueClass

Następująca monkeypatch do Object powie Ci, czy coś jest instancją TrueClass czy FalseClass

class Object
  def boolean?
    self.is_a?(TrueClass) || self.is_a?(FalseClass) 
  end
end

Wykonanie niektórych testów z irb daje następujące wyniki

?> "String".boolean?
=> false
>> 1.boolean?
=> false
>> Time.now.boolean?
=> false
>> nil.boolean?
=> false
>> true.boolean?
=> true
>> false.boolean?
=> true
>> (1 ==1).boolean?
=> true
>> (1 ==2).boolean?
=> true
Steve Weet
źródło
4
Prostsze po prostu pisać self == true or self == false. To jedyne wystąpienia TrueClass i FalseClass.
Chuck,
@chuck, który zwraca te same wyniki, z wyjątkiem Time.now.boolean? która zwraca nil. Każdy pomysł, dlaczego?
Steve Weet
Definiowanie sprawdzania klasy na sobie w metodzie nie jest oop. Należy zdefiniować dwie wersje boolean, jedną dla TrueClass / FalseClass i jedną dla Object.
Konstantin Haase
4
Powodem jest to, że błąd w wersji Time#==Rubiego 1.8 powoduje, że porównanie z wartościami innymi niż Time zwraca zero, a nie fałsz.
Chuck
17

Jeśli twój kod można rozsądnie zapisać jako instrukcję, jest to całkiem przyzwoite:

case mybool
when TrueClass, FalseClass
  puts "It's a bool!"
else
  puts "It's something else!"
end
Henrik N
źródło
6

Obiekt, który jest wartością logiczną, będzie miał klasę TrueClass lub FalseClass, więc poniższy wiersz powinien załatwić sprawę

mybool = true
mybool.class == TrueClass || mybool.class == FalseClass
=> true

Poniższe również dałoby wynik sprawdzenia typu boolowskiego prawda / fałsz

mybool = true    
[TrueClass, FalseClass].include?(mybool.class)
=> true
user1966234
źródło
4

Więc wypróbuj tę (x == true) ^ (x == false)notatkę, potrzebujesz nawiasu, ale jest piękniejszy i bardziej zwarty.

Spełnia nawet sugestie, takie jak „cuak”, ale nie „cuak” ... class X; def !; self end end ; x = X.new; (x == true) ^ (x == false)

Uwaga : zobacz, że jest to tak podstawowe, że możesz go używać również w innych językach, co nie zapewnia „rzeczy jest logiczne”.

Uwaga 2 : Możesz również użyć tego, aby powiedzieć, że rzecz jest jedną z ??:"red", "green", "blue"jeśliadd more XORS... lub powiesz, że ta rzecz jest jedną z ??:4, 5, 8, 35.

tyoc213
źródło
Dlaczego XOR? Dlaczego nie OR?
Nakilon
2

Ten klejnot dodaje klasę Boolean do Rubiego za pomocą przydatnych metod.

https://github.com/RISCfuture/boolean

Posługiwać się:

require 'boolean'

Wtedy twój

true.is_a?(Boolean)
false.is_a?(Boolean)

będzie działać dokładnie tak, jak oczekujesz.

Przekonany
źródło
0

Nie. Nie tak, jak masz swój kod. Nie ma klasy o nazwie Boolean. Teraz, mając wszystkie odpowiedzi, powinieneś być w stanie je utworzyć i używać. Wiesz, jak tworzyć zajęcia, prawda? Przyjechałem tutaj tylko dlatego, że sam zastanawiałem się nad tym pomysłem. Wiele osób może powiedzieć „Dlaczego? Musisz tylko wiedzieć, w jaki sposób Ruby używa wartości logicznych”. Dlatego otrzymałeś odpowiedzi, które zrobiłeś. Więc dziękuję za pytanie. Do przemyślenia. Dlaczego Ruby nie ma klasy logicznej?

NameError: uninitialized constant Boolean

Pamiętaj, że obiekty nie mają typów. To są klasy. Obiekty mają dane. Dlatego kiedy mówisz o typach danych, jest to trochę mylące.

Spróbuj także rand 2, ponieważ rand 1 wydaje się zawsze dawać 0. rand 2 da 1 lub 0 kliknięć kilka razy tutaj. https://repl.it/IOPx/7

Chociaż sam nie wiedziałbym, jak zrobić klasę boolowską. Eksperymentowałem z tym, ale ...

class Boolean < TrueClass
  self
end

true.is_a?(Boolean) # => false
false.is_a?(Boolean) # => false

Przynajmniej mamy teraz tę klasę, ale kto wie, jak uzyskać właściwe wartości?

Douglas G. Allen
źródło