Rubyのunless文で条件式が複数ある場合のメモ

unless文で、条件式が複数ある場合の動作がたまに分からなくなるので、備忘録書いておく。
先に結論を書くと、unless文は if文の条件全体にnotをつける のと同じ。

  • ball.rb
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-

class Ball
  def initialize(color)
    @color = color
  end

  def red_or_blue?
    if @color == 'red' or @color == 'blue'
      true
    else
      false
    end
  end

  def not_red_and_not_blue?
    if @color != 'red' and @color != 'blue'
      true
    else
      false
    end
  end
end
  • ball_spec.rb
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
require 'rspec'
require File.dirname(__FILE__) + '/test'

describe "Ball" do
  context "赤いボール" do
    subject { Ball.new('red') }
    it { should be_red_or_blue }
    it { should_not be_not_red_and_not_blue }
  end

  context "青いボール" do
    subject { Ball.new('red') }
    it { should be_red_or_blue }
    it { should_not be_not_red_and_not_blue }
  end

  context "黄色のボール" do
    subject { Ball.new('yellow') }
    it { should_not be_red_or_blue }
    it { should be_not_red_and_not_blue }
  end
end

条件A. このボールは青いか、または赤い

red_or_blue? メソッド内の条件式「@color == 'red' or @color == 'blue'

条件B. このボールは青くもないし赤くもない (条件Aの否定)

not_blue_and_not_red? メソッド内の条件式「@color != 'red' and @color != 'blue'

ド・モルガンの法則でリファクタリング

not_blue_and_not_red? メソッドの条件式をド・モルガンの法則 で書き換える。

if not (@color == 'red' or @color == 'blue')

unless文でリファクタリング

not_blue_and_not_red? メソッドの条件式をunless文にする。

unless @color == 'red' or @color == 'blue'

結論

unless文の条件式は、条件A.で書いてあるif文の条件式と同じになっている。

おまけ

  • 説明用に冗長に書いたけど、本来はif文を書かない。
class Ball
  def initialize(color)
    @color = color
  end

  def red_or_blue?
    @color == 'red' or @color == 'blue'
  end

  def not_red_and_not_blue?
    @color != 'red' and @color != 'blue'
  end
end

spec書いてあれば、リファクタリングできる。

  • ruby1.9ではロードパスに'.'が含まれていないので、File.dirname(__FILE__)が必要
require File.dirname(__FILE__) + '/test'

requireの前に $LOAD_PATH << '.' でも可

$LOAD_PATH << '.'