2016-03-25 23 views
32

Ho un valore che sarà una delle quattro cose: boolean true, boolean false, la stringa "true" o la stringa "false". Voglio convertire la stringa in un booleano se si tratta di una stringa, altrimenti lasciarla non modificata. In altre parole:Ruby: Come convertire una stringa in booleana

"vero" dovrebbe diventare vero

"false" dovrebbe diventare falsa

vero dovrebbe rimanere fedele

falso dovrebbe stare falso

+2

Il risultato * deve * essere uno dei due valori 'true' o' false' o è sufficiente se il risultato è vero o falso? Se quest'ultimo, quindi 'false' è già falso, ed entrambi' true' e ''true'' sono veri, quindi l'unico valore per il quale il risultato non è già corretto, è'' false'': 'if input = = 'false' allora vero else input end' dovrebbe farlo. –

+0

Questo è un ottimo commento Jorg, tuttavia suppongo che per alcune applicazioni sia necessario avere il valore booleano vero o falso e non solo un valore che sia vero o falso. – emery

+1

Emery, se hai bisogno di restituire un booleano puoi anteporre l'espressione di @ Jörg con due "not": '!! (se input == 'false' allora vero else input end)'. Il secondo '!' Converte il valore di ritorno in un valore booleano che è l'opposto di quello che vuoi; il primo '!' esegue quindi la correzione. Questo "trucco" è in circolazione da molto tempo. Non tutti gli sono affezionati. –

risposta

52
def true?(obj) 
    obj.to_s == "true" 
end 
+0

questo è sorprendente, qualcuno ti spiega come funziona? – null

+0

Sì, @null, il metodo to_s converte booleano vero o falso in "vero" o "falso" e lascia il valore invariato se originariamente era una stringa. Ora siamo certi di avere "vero" o "falso" come una stringa ... e dobbiamo solo usare == controllare se la stringa è uguale a "true". Se è così, il valore originale era vero o "vero". Se non lo è, il valore originale era falso, "falso" o qualcosa di totalmente non correlato. – emery

10
if value.to_s == 'true' 
    true 
elsif value.to_s == 'false' 
    false 
end 
+0

Altrimenti dovrete verificare se è un tipo String e se sì, controllare se è "vero" e se sì, restituire true. Perché tutti quei paragoni? – archana

+7

Il tuo codice come 'one-liner 'value.to_s ==' true '? true: false' –

+0

If/elsif/end è probabilmente il più leggibile per un principiante. Il to_s probabilmente non è realmente necessario quando si usa l'istruzione elsif, perché non eseguirà alcun blocco sotto "if" o "elsif" quando il valore booleano non corrisponde a una stringa, e quindi il booleano rimarrà intatto. – emery

11
h = { "true"=>true, true=>true, "false"=>false, false=>false } 

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

È possibile utilizzare una gemma come https://rubygems.org/gems/to_bool, ma può essere facilmente scritta in una riga utilizzando una regex o ternaria.

regex esempio:

boolean = (var.to_s =~ /^true$/i) == 0 

ternario esempio:

boolean = var.to_s.eql?('true') ? true : false 

Il vantaggio del metodo regex è che le espressioni regolari sono flessibili e possono adattarsi a un'ampia varietà di modelli. Ad esempio, se si sospetta che var potrebbe essere una qualsiasi di "True", "False", 'T', 'F', 't', o 'f', allora si può modificare l'espressione regolare:

boolean = (var.to_s =~ /^[Tt].*$/i) == 0 
+1

Nota: '\ A' /' \ z' è inizio/fine stringa e '^'/'$' è inizio/fine riga.Quindi se 'var ==" true \ nwhatevs "' then 'boolean == true'. – cremno

3

Anche se mi piace l'approccio hash (l'ho usato in passato per cose simili), dato che si preoccupano solo di far corrispondere valori di verità - dal momento che - tutto il resto è falso - è possibile verificare l'inclusione in un array :

value = [true, 'true'].include?(value) 

o se altri valori possono essere considerati truthy:

value = [1, true, '1', 'true'].include?(value) 

che avrei dovuto fare altre cose se l'originale caso value potrebbe essere miscelato:

value = value.to_s.downcase == 'true' 

ma ancora una volta, per la descrizione specifica del problema, si potrebbe ottenere via con quello ultimo esempio come la vostra soluzione .

1

In rotaie, ho fatto in precedenza qualcosa di simile:

class ApplicationController < ActionController::Base 
    # ... 

    private def bool_from(value) 
    !!ActiveRecord::Type::Boolean.new.type_cast_from_database(value) 
    end 
    helper_method :bool_from 

    # ... 
end 

che è bello se si sta cercando di soddisfare le vostre stringhe booleane confronti nello stesso modo come farebbe rotaie per il database.

-4

Che dire smthing come:

boolean_str = 'false' 
boolean = eval(boolean_str) 
+4

è abbastanza pericoloso se l'input proviene da fuori dal mondo. –

+0

mai utilizzare eval da dati esterni – jacopobeschi

35

Se si utilizza Rails 5, si può fare ActiveModel::Type::Boolean.new.cast(value).

In Rails 4.2, utilizzare ActiveRecord::Type::Boolean.new.type_cast_from_user(value).

Il comportamento è leggermente diverso, poiché in Rails 4.2 vengono verificati il ​​valore vero e i valori falsi.In Rails 5, vengono controllati solo i valori falsi, a meno che i valori siano nulli o corrispondano a un valore falso, si presume che sia vero. falsi valori sono gli stessi in entrambe le versioni: FALSE_VALUES = [false, 0, "0", "f", "F", "false", "FALSE", "off", "OFF"]

Rails 5 Fonte: https://github.com/rails/rails/blob/5-1-stable/activemodel/lib/active_model/type/boolean.rb

+0

Questo è utile, anche se mi auguro che il set di 'FALSE_VALUES' in Rails includesse anche" no ". – pjrebsch

7

Ho usato spesso questo modello per estendere il comportamento di base di Ruby per rendere più facile trattare con la conversione di tipi di dati arbitrari valori booleani, che lo rende molto facile da affrontare con diversi parametri URL, ecc

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 

Quindi diciamo che avete un parametro che può essere foo:

  • un numero intero (0 è falso, tutti gli altri sono vere)
  • una vera booleano (true/false)
  • una stringa ("true", "false", "0", "1", " TRUE", 'FALSE')
  • nil

Invece di usare un po 'di condizionali, si può chiamare foo.to_boolean e farà il resto della magia per voi.

In Rails, aggiungo questo a un inizializzatore denominato core_ext.rb in quasi tutti i miei progetti poiché questo modello è così comune.

## 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 
6

Non pensare troppo:

bool_or_string.to_s == "true" 

Quindi,

"true".to_s == "true" #true 
"false".to_s == "true" #false 
true.to_s == "true"  #true 
false.to_s == "true" #false 

Si potrebbe anche aggiungere ".downcase," se siete preoccupati per le lettere maiuscole.

+1

'nil.to_s == 'true' # false ' – juliangonzalez

Problemi correlati