J'ai une valeur qui sera l'une des quatre choses suivantes: boolean true, boolean false, la chaîne "true" ou la chaîne "false". Je veux convertir la chaîne en un booléen s'il s'agit d'une chaîne, sinon laissez-la non modifiée. En d'autres termes:
"vrai" devrait devenir vrai
"faux" devrait devenir faux
vrai devrait rester vrai
faux devrait rester faux
def true?(obj)
obj.to_s == "true"
end
Si vous utilisez Rails 5, vous pouvez effectuer ActiveModel::Type::Boolean.new.cast(value)
.
Dans Rails 4.2, utilisez ActiveRecord::Type::Boolean.new.type_cast_from_user(value)
.
Le comportement est légèrement différent, car dans Rails 4.2, la valeur vraie et les valeurs fausses sont vérifiées. Dans Rails 5, seules les valeurs fausses sont vérifiées. À moins que la valeur ne soit nulle ou ne corresponde à une valeur fausse, elle est supposée être vraie. Les valeurs fausses sont les mêmes dans les deux versions:
FALSE_VALUES = [false, 0, "0", "f", "F", "false", "FALSE", "off", "OFF"]
Rails 5 Source: https://github.com/Rails/rails/blob/5-1-stable/activemodel/lib/active_model/type/boolean.rb
if value.to_s == 'true'
true
elsif value.to_s == 'false'
false
end
J'ai souvent utilisé ce modèle pour étendre le comportement principal de Ruby afin de faciliter la conversion de types de données arbitraires en valeurs booléennes, ce qui facilite grandement la gestion de paramètres URL variés, etc.
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
Alors disons que vous avez un paramètre foo
qui peut être:
Au lieu d'utiliser un tas de conditions, vous pouvez simplement appeler foo.to_boolean
et le reste de la magie fera le reste pour vous.
Dans Rails, j'ajoute ceci à un initialiseur nommé core_ext.rb
dans presque tous mes projets, car ce modèle est si courant.
## 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
h = { "true"=>true, true=>true, "false"=>false, false=>false }
["true", true, "false", false].map { |e| h[e] }
#=> [true, true, false, false]
Ne pense pas trop:
bool_or_string.to_s == "true"
Alors,
"true".to_s == "true" #true
"false".to_s == "true" #false
true.to_s == "true" #true
false.to_s == "true" #false
Vous pouvez également ajouter ".downcase" si vous vous inquiétez des majuscules.
Bien que j'apprécie l'approche de hachage (je l'ai déjà utilisée pour des choses similaires), étant donné que vous ne vous souciez que de faire correspondre les valeurs de vérité - puisque - tout le reste est faux - vous pouvez vérifier l'inclusion dans un tableau:
value = [true, 'true'].include?(value)
ou si d'autres valeurs pouvaient être considérées comme véridiques:
value = [1, true, '1', 'true'].include?(value)
vous auriez à faire autre chose si votre value
originale pouvait être mixte:
value = value.to_s.downcase == 'true'
mais encore une fois, pour votre description spécifique de votre problème, vous pouvez vous en tenir à ce dernier exemple comme solution.
J'ai un petit bidouillage pour celui-ci. JSON.parse('false')
retournera false
et JSON.parse('true')
retournera true. Mais cela ne fonctionne pas avec JSON.parse(true || false)
. Donc, si vous utilisez quelque chose comme JSON.parse(your_value.to_s)
, votre objectif devrait être atteint d'une manière simple mais simpliste.
Une gemme telle que https://rubygems.org/gems/to_bool peut être utilisée, mais elle peut facilement être écrite sur une seule ligne à l'aide d'une expression régulière ou ternaire.
exemple de regex:
boolean = (var.to_s =~ /^true$/i) == 0
exemple ternaire:
boolean = var.to_s.eql?('true') ? true : false
L'avantage de la méthode regex est que les expressions régulières sont flexibles et peuvent correspondre à une grande variété de modèles. Par exemple, si vous suspectez que var puisse être "True", "False", "T", "F", "t" ou "f", vous pouvez modifier l'expression régulière:
boolean = (var.to_s =~ /^[Tt].*$/i) == 0
Dans Rails, j'ai déjà fait quelque chose comme ceci:
class ApplicationController < ActionController::Base
# ...
private def bool_from(value)
!!ActiveRecord::Type::Boolean.new.type_cast_from_database(value)
end
helper_method :bool_from
# ...
end
Ce qui est bien si vous essayez de faire correspondre vos comparaisons de chaînes booléennes de la même manière que Rails le ferait pour votre base de données.
Dans Rails, je préfère utiliser ActiveModel::Type::Boolean.new.cast(value)
comme mentionné dans d'autres réponses ici.
Mais quand j'écris Ruby lib. J'utilise ensuite un hack où JSON.parse
(bibliothèque Ruby standard) convertira la chaîne "true" en true
et "false" en false
. Par exemple.:
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
Exemple d'application en direct:
require 'json'
if JSON.parse(`az group exists --name derrentest`)
`az group create --name derrentest --location uksouth`
end
confirmé sous Ruby 2.5.1
Dans une application Rails 5.1, j'utilise cette extension principale construite sur ActiveRecord::Type::Boolean
. Cela fonctionne parfaitement pour moi lorsque je désérialise un booléen de chaîne 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
initialiser les extensions de base
# 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