web-dev-qa-db-fra.com

Ruby: Comment convertir une chaîne en booléen

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

62
emery
def true?(obj)
  obj.to_s == "true"
end
94
steenslag

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

65
rado
if value.to_s == 'true'
  true
elsif value.to_s == 'false'
  false
end
15
archana

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:

  • un entier (0 est faux, tous les autres sont vrais)
  • un vrai booléen (vrai/faux) 
  • une chaîne ("true", "false", "0", "1", "TRUE", "FALSE")
  • néant

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
14
Steve Craig
h = { "true"=>true, true=>true, "false"=>false, false=>false }

["true", true, "false", false].map { |e| h[e] }
  #=> [true, true, false, false] 
13
Cary Swoveland

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.

11
David Foley

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.

3
Pavling

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. 

2
Felipe Funes

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
2
emery

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.

1
Chad M

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

0
equivalent8

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
0
mnishiguchi