Ответ 1
К сожалению, это невозможно.
Это один из тех раздражающих случаев, когда Ruby не является объектно-ориентированным. В OO должно быть возможно, чтобы один объект имитировал другой (фактически, в зависимости от того, о ком вы спрашиваете, это само определение OO - помните, что OO вышел из симуляции), но невозможно построить объект, который имитирует false
.
Это связано с тем, что в Ruby структуры условного управления запекаются на языке и не переходят на отправку сообщений, тогда как на других языках OO они являются просто регулярными сообщениями (или, по крайней мере, переводить на сообщения, как, например, for
в Ruby переводится в each
). Например, в Smalltalk булевы на самом деле реализованы с использованием церковной кодировки логических букв, которые вы знаете из Lambda Calculus, и переведены в Ruby, они выглядят примерно так:
class FalseClass
def if(&block)
# do nothing
end
def if_then_else(then_lambda, else_lambda)
else_lambda.()
end
def not
true
end
def and(&block)
self
end
def or(&block)
block.()
end
end
И TrueClass
- это просто зеркальное изображение:
class TrueClass
def if(&block)
block.()
end
def if_then_else(then_lambda, else_lambda)
then_lambda.()
end
def not
false
end
def and(&block)
block.()
end
def or(&block)
self
end
end
И тогда вместо чего-то вроде
if 2 < 3 then foo end
if 2 < 3 then bar else baz end
У вас будет
(2 < 3).if { foo }
(2 < 3).if_then_else(-> { bar }, -> { baz })
# using the new keyword arguments in Ruby 2.0, it almost reads like Smalltalk:
class FalseClass
def if(then: -> {}, else: -> {})
else.()
end
end
class TrueClass
def if(then: -> {}, else: -> {})
then.()
end
end
(2 < 3).if(then: -> { bar }, else: { baz })
Таким образом, вы можете легко создать объект, который имитирует false
просто путем реализации соответствующих методов.
В других случаях, когда какой-то объект действительно абсолютно должен быть экземпляром определенного класса, а не просто говорить о правильном протоколе, Ruby предоставляет escape-люк. Например, если для метода действительно требуется Array
в качестве аргумента, он сначала попытается вызвать to_ary
, чтобы хотя бы дать вам возможность конвертировать ваш объект в Array
. То же самое относится к to_str
, to_int
, to_proc
, to_float
и т.д. Но нет эквивалентного протокола to_bool
.