脳汁portal

アメリカ在住(だった)新米エンジニアがその日学んだIT知識を書き綴るブログ

Rubyで文字列で帰ってきた"true"や"false"をBooleanに変換するto_boolメソッドを実装

前提

  • rubyの条件文ではnilとfalse以外はすべてtrueとして扱われてしまう
condition = 'false'
puts "TRUE" if condition # => TRUE

condition = 0
puts "TRUE" if condition # => TRUE

condition = 'nil'
puts "TRUE" if condition # => TRUE

# ちなみにnullはない
condition = null
# =>
#NameError: undefined local variable or method `null' for main:Object
#        from (irb):8
#        from /usr/local/rvm/rubies/ruby-2.1.2/bin/irb:11:in `<main> 

だが処理によってはfalseが文字列の'false'であっても条件文ではfalseとして扱いたい場合があるかもしれない。
しかし、falseから'false'へは変換可能だが、現在のrubyには'false'からfalseにするメソッドが存在しない。

puts false.to_s # => false
puts false.to_s.class # => String

puts 'false'.to_bool # => NoMethodError: undefined method `to_bool' for "false":String
puts 'false'.to_boolean # => NoMethodError: undefined method `to_boolean' for "false":String

対策

Stringクラスにto_boolメソッドを作ってしまおう!
class String
  def to_bool
    return self if self.class.kind_of?(TrueClass) || self.class.kind_of?(FalseClass)

    if self =~ /^(true|false)$/
      return true if $1 == 'true'
      return false if $1 == 'false'
    else
      raise NoMethodError.new("undefined method `to_bool' for '#{self}'")
    end
  end
end
  1. 既にBoolean(RubyではTrueClassとFalseClass)の場合はそのまま返します
  2. 対象の文字列が'true'か'false'場合はそれぞれtrue(TrueClass)とfalse(FalseClass)を返します
  3. それ以外の文字列が来た場合は例外を発生させます。
  4. (今回はStringクラスにしかメソッドを追加していないので、他の型(Intとか)でto_boolメソッドを使おうとしても同じくNoMethodErrorになります)

確認

condition = 'false'

if condition
  puts "TRUE"
else
  puts "FALSE"
end
# => TRUE


if condition.to_bool
  puts "TRUE"
else
  puts "FALSE"
end
# => FALSE


if 'foobar'.to_bool
  puts "TRUE"
else
  puts "FALSE"
end
# => bool.rb:9:in `to_bool': undefined method `to_bool' for 'foobar' (NoMethodError)

追記(2015/11/06)

gem化して公開しましたportaltan.hatenablog.com