Ответ 1
def true?(obj)
obj.to_s.downcase == "true"
end
У меня есть значение, которое будет одной из четырех вещей: boolean true, boolean false, строка "true" или строка "false". Я хочу преобразовать строку в логическое значение, если это строка, иначе оставить ее немодифицированной. Другими словами:
"true" должно стать истинным
"false" должно стать ложным
true должно оставаться верным
false должен оставаться ложным
def true?(obj)
obj.to_s.downcase == "true"
end
Если вы используете Rails 5, вы можете сделать ActiveModel::Type::Boolean.new.cast(value)
.
В Rails 4.2 используйте ActiveRecord::Type::Boolean.new.type_cast_from_user(value)
.
Поведение немного отличается, так как в Rails 4.2 проверяется истинное значение и ложные значения. В Rails 5 проверяются только ложные значения - если значения не равны нулю или не соответствуют ложному значению, оно считается истинным. В обеих версиях значения False одинаковы:
FALSE_VALUES = [false, 0, "0", "f", "F", "false", "FALSE", "off", "OFF"]
Rails 5 Источник: https://github.com/rails/rails/blob/5-1-stable/activemodel/lib/active_model/type/boolean.rb
Я часто использовал этот шаблон для расширения основного поведения Ruby, чтобы упростить работу с преобразованием произвольных типов данных в логические значения, что позволяет легко справляться с различными параметрами URL и т.д.
class String
def to_boolean
ActiveRecord::Type::Boolean.new.cast(self)
end
end
class NilClass
def to_boolean
false
end
end
class TrueClass
def to_boolean
true
end
def to_i
1
end
end
class FalseClass
def to_boolean
false
end
def to_i
0
end
end
class Integer
def to_boolean
to_s.to_boolean
end
end
Итак, скажем, у вас есть параметр foo
, который может быть:
Вместо того, чтобы использовать кучу условных выражений, вы можете просто вызвать foo.to_boolean
, и он сделает остальную магию для вас.
В Rails я добавляю это в инициализатор с именем core_ext.rb
почти во всех моих проектах, так как этот шаблон настолько распространен.
## EXAMPLES
nil.to_boolean == false
true.to_boolean == true
false.to_boolean == false
0.to_boolean == false
1.to_boolean == true
99.to_boolean == true
"true".to_boolean == true
"foo".to_boolean == true
"false".to_boolean == false
"TRUE".to_boolean == true
"FALSE".to_boolean == false
"0".to_boolean == false
"1".to_boolean == true
true.to_i == 1
false.to_i == 0
if value.to_s == 'true'
true
elsif value.to_s == 'false'
false
end
h = { "true"=>true, true=>true, "false"=>false, false=>false }
["true", true, "false", false].map { |e| h[e] }
#=> [true, true, false, false]
Не думайте слишком много:
bool_or_string.to_s == "true"
Итак,
"true".to_s == "true" #true
"false".to_s == "true" #false
true.to_s == "true" #true
false.to_s == "true" #false
Вы также можете добавить ".downcase", если вас беспокоят заглавные буквы.
Хотя мне нравится хеш-подход (я использовал его в прошлом для подобных вещей), учитывая, что вы действительно заботитесь только о соответствии правных значений, поскольку - все остальное ложно - вы можете проверить включение в массив:
value = [true, 'true'].include?(value)
или если другие значения могут считаться правдивыми:
value = [1, true, '1', 'true'].include?(value)
вам придется делать другие вещи, если ваш оригинальный value
может быть смешанным:
value = value.to_s.downcase == 'true'
но опять же, для вашего конкретного описания вашей проблемы, вы можете уйти с этим последним примером в качестве своего решения.
Можно использовать драгоценный камень, например https://rubygems.org/gems/to_bool, но его можно легко записать в одну строку с помощью регулярного выражения или тройная.
Примерregex:
boolean = (var.to_s =~ /^true$/i) == 0
тернарный пример:
boolean = var.to_s.eql?('true') ? true : false
Преимущество метода регулярных выражений состоит в том, что регулярные выражения являются гибкими и могут соответствовать широкому спектру шаблонов. Например, если вы подозреваете, что var может быть любым из "True", "False", "T", "F", "t" или "f", вы можете изменить регулярное выражение:
boolean = (var.to_s =~ /^[Tt].*$/i) == 0
В приложении rails 5.1 я использую это базовое расширение, построенное поверх ActiveRecord::Type::Boolean
. Он отлично работает для меня, когда я deserialize boolean из строки JSON.
https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
# app/lib/core_extensions/string.rb
module CoreExtensions
module String
def to_bool
ActiveRecord::Type::Boolean.new.deserialize(downcase.strip)
end
end
end
инициализировать расширения ядра
# config/initializers/core_extensions.rb
String.include CoreExtensions::String
RSpec
# spec/lib/core_extensions/string_spec.rb
describe CoreExtensions::String do
describe "#to_bool" do
%w[0 f F false FALSE False off OFF Off].each do |falsey_string|
it "converts #{falsey_string} to false" do
expect(falsey_string.to_bool).to eq(false)
end
end
end
end
У меня есть небольшой взлом для этого. JSON.parse('false')
вернет false
а JSON.parse('true')
вернет true. Но это не работает с JSON.parse(true || false)
. Итак, если вы используете что-то вроде JSON.parse(your_value.to_s)
это должно достичь вашей цели простым, но хакерским способом.
В рельсах я ранее делал что-то вроде этого:
class ApplicationController < ActionController::Base
# ...
private def bool_from(value)
!!ActiveRecord::Type::Boolean.new.type_cast_from_database(value)
end
helper_method :bool_from
# ...
end
Хорошо, если вы пытаетесь сопоставить логические сравнения строк таким же образом, как и рельсы для вашей базы данных.
В Rails я предпочитаю использовать ActiveModel::Type::Boolean.new.cast(value)
как упоминалось в других ответах здесь
Но когда я пишу простой Ruby lib. затем я использую хак, где JSON.parse
(стандартная библиотека Ruby) преобразует строку "true" в true
и "false" в false
. Например:
require 'json'
azure_cli_response = 'az group exists --name derrentest' # => "true\n"
JSON.parse(azure_cli_response) # => true
azure_cli_response = 'az group exists --name derrentesttt' # => "false\n"
JSON.parse(azure_cli_response) # => false
Пример из живого приложения:
require 'json'
if JSON.parse('az group exists --name derrentest')
'az group create --name derrentest --location uksouth'
end
подтверждено в Ruby 2.5.1
Один из способов - написать код таким образом, чтобы он прямо отражал бизнес-логику, точно выраженную OP:
def true_or_false answer
if answer == true || answer == false
answer
elsif answer == "true"
true
else
false
end
end
Как насчет smthing как:
boolean_str = 'false'
boolean = eval(boolean_str)