Как проверить, является ли объект Ruby логическим

123

Кажется, я не могу легко проверить, является ли объект логическим. Есть ли что-то подобное в Ruby?

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

Сейчас я делаю это и хотел бы сократить его:

some_var = rand(1) == 1 ? true : false
(some_var.is_a?(TrueClass) || some_var.is_a?(FalseClass))
Лэнс Поллард
источник

Ответы:

138

Самый простой способ, который я могу придумать:

# checking whether foo is a boolean
!!foo == foo
Константин Хаазе
источник
6
класс X; def!; самоконец конец; x = X.new; !! x == x # => true
Алексей
5
Да, это называется утиной типизацией и основным принципом ООП. Думаю, это особенность.
Konstantin Haase
62
Короткое не обязательно означает простое. Что я имею в виду, что это такое?
Грант Бирчмайер,
11
Превращает foo в логическое значение, проверяет, совпадает ли оно с foo.
Константин Хаасе
9
Обратите внимание, что некоторые шашки (например, RuboCop ) считают двойное отрицание плохим стилем .
sschuberth
104

Я считаю это кратким и самодокументированным:

[true, false].include? foo

Если вы используете Rails или ActiveSupport, вы даже можете выполнить прямой запрос, используя in?

foo.in? [true, false]

Я бы не рекомендовал проверку всех возможных значений для чисел с плавающей запятой, но это выполнимо, когда есть только два возможных значения!

mahemoff
источник
1
лучший ответ на сегодняшний день, хотя мне также понравилось, foo == true or foo == falseчто кто-то оставил комментарий.
Райан Тейлор
3
Мне это нравится, потому что он менее загадочен, чем !!foo == foo.
stringsn88keys
Прямо питонический! Определенно, это самый смысловой ответ.
JM Janzen
85

В BooleanRuby нет класса, единственный способ проверить - это сделать то, что вы делаете (сравнивая объект с trueи / falseили класс объекта с TrueClassи FalseClass). Не можете придумать, зачем вам эта функция, можете объяснить? :)

Однако, если вам действительно нужна эта функция, вы можете взломать ее:

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

true.is_a?(Boolean) #=> true
false.is_a?(Boolean) #=> true
horseyguy
источник
1
пытается выполнить приведение типов на основе текущего значения.
Лэнс Поллард,
75
- Зачем тебе это вообще? (и производные) - это лишь один из самых неприятных вопросов, который инженер может задать еще один :)
vemv
11
+1, потому что я могу использовать это в rspec, например:expect(some_method?(data)).to be_a(Boolean)
Automatico
3
Другой случай, когда нужно проверить тип, - это когда вы реализуете адаптер базы данных и вам нужно обернуть строки, "quotes"но не числами и логическими значениями,
Даниэль Гармошка
23

Как указано выше, нет логического класса, только TrueClass и FalseClass, однако вы можете использовать любой объект в качестве объекта if / except, и все верно, кроме экземпляров FalseClass и nil

Логические тесты возвращают экземпляр FalseClass или TrueClass

(1 > 0).class #TrueClass

Следующий патч обезьяны к Object сообщит вам, является ли что-то экземпляром TrueClass или FalseClass.

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

Выполнение некоторых тестов с irb дает следующие результаты

?> "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
Стив Уит
источник
4
Проще просто написать self == true or self == false. Это единственные экземпляры TrueClass и FalseClass.
Чак
@chuck, который возвращает те же результаты, кроме Time.now.boolean? который возвращает ноль. Есть идеи, почему?
Steve Weet,
Определение проверки класса для себя в методе несколько неуместно. Вы должны определить две версии: booleanодну для TrueClass / FalseClass и одну для Object.
Константин Хаасе,
4
Причина в том, что ошибка в версии Time#==Ruby 1.8 приводит к тому, что сравнение с не-Time значениями возвращает nil, а не false.
Чак
17

Если ваш код может быть разумно написан как оператор case, это довольно прилично:

case mybool
when TrueClass, FalseClass
  puts "It's a bool!"
else
  puts "It's something else!"
end
Хенрик Н
источник
6

Объект, который является логическим, будет либо иметь класс TrueClass, либо FalseClass, поэтому следующий однострочный объект должен помочь

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

Следующее также даст вам результат проверки логического типа true / false

mybool = true    
[TrueClass, FalseClass].include?(mybool.class)
=> true
user1966234
источник
4

Так что попробуйте эту (x == true) ^ (x == false)заметку, вам нужны скобки, но они более красивы и компактны.

Он даже передает предложенное "cuak", но не "cuak" ... class X; def !; self end end ; x = X.new; (x == true) ^ (x == false)

Примечание. Обратите внимание, что это настолько просто, что вы можете использовать его и на других языках, что не обеспечивает логического значения.

Примечание 2 : Также вы можете использовать это, чтобы сказать, что это одна из ??:"red", "green", "blue"if youadd more XORS... или говорите, что это одна из ??:4, 5, 8, 35.

tyoc213
источник
Почему XOR? Почему не ИЛИ?
Накилон
2

Этот гем добавляет в Ruby логический класс с полезными методами.

https://github.com/RISCfuture/boolean

Использование:

require 'boolean'

Тогда твой

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

будет работать именно так, как вы ожидаете.

поддающийся убеждению
источник
0

Нет. Не то чтобы у тебя есть код. Класса с именем Boolean не существует. Теперь, когда у вас есть все ответы, вы сможете создать его и использовать. Вы ведь знаете, как создавать классы, не так ли? Я пришла сюда только потому, что сама сама задавалась вопросом. Многие люди могут спросить: «Почему? Вы должны просто знать, как Ruby использует Boolean». Вот почему вы получили ответы. Так что спасибо за вопрос. Пища для размышлений. Почему в Ruby нет логического класса?

NameError: uninitialized constant Boolean

Помните, что у объектов нет типов. Это классы. У объектов есть данные. Вот почему, когда вы говорите о типах данных, это немного неправильно.

Также попробуйте rand 2, потому что rand 1, кажется, всегда дает 0. rand 2 даст здесь 1 или 0 кликов несколько раз. https://repl.it/IOPx/7

Хотя я бы не знал, как самому создать логический класс. Я экспериментировал с этим, но ...

class Boolean < TrueClass
  self
end

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

По крайней мере, теперь у нас есть этот класс, но кто знает, как получить правильные значения?

Дуглас Г. Аллен
источник