読者です 読者をやめる 読者になる 読者になる

Tbpgr Blog

Ruby プログラマ tbpgr(てぃーびー) のブログ

Ruby | Delivering Output | Return Status Object

Confident Ruby Ruby

概要

Return Status Object

前提

Confident Rubyではメソッド内の処理を次のように分類しています。
・Collecting Inputs(引数チェック、変換など)
・Performing Work(主処理)
・Delivering Output(戻り値に関わる処理)
・Handling Failure(例外処理)

当記事は上記のうち、Delivering Outputに関する話です。

詳細

状況

コマンドメソッドが成功・失敗以上の成果物を欲しがるかもしれない。

概要

Statusオブジェクトでメソッドの成果を表す

理由

Statusオブジェクトは単純な成功・失敗より微妙な差異を表すことができる。

サンプルコード仕様

信号を表すクラスSignalを作成します。
Signal#signal_statusでランダムに信号の状態を返却します。

サンプル1
Signal#signal_statusの戻り値を赤=:red, 青=:green, 消灯=:vanishedで返却します。
この場合、利用側は戻り値のシンボルのつづりを正確に知っている必要があります。

サンプル2
SignalStatusクラスを作成します。信号の状態を保持するとともに、
・信号の状態確認用メソッド(SignalStatus#red?, SignalStatus#green?, SignalStatus#vanished?)
・信号の状態別用インスタンス取得メソッド(SignalStatus.red, SignalStatus.green, SignalStatus.vanished)
を持ちます。

Signal#signal_statusの戻り値をSignalStatusクラスの各状態別インスタンスで返却します。
この場合、利用側はSignalStatusが外部公開している振る舞いを元に条件を記述することができます。

サンプルコードその1

module Traffic
  class Signal
    def self.signal_status
      begin
        case signal_random
        when 1
          :red
        when 2
          :green
        end
      rescue
        :vanished
      end
    end

    def self.signal_random
      ret = rand(3).to_i + 1
      raise 'invalid' if ret == 3
      ret
    end
  end
end

10.times do
  color = Traffic::Signal.signal_status
  case color
  when :green
    puts "信号が青なので渡ります"
  when :red
    puts "信号が赤なので待ちます"
  when :vanished
    puts "信号がついていないが渡ります"
  end
end

出力(ランダム)

信号が青なので渡ります
信号が赤なので待ちます
信号が青なので渡ります
信号が青なので渡ります
信号が赤なので待ちます
信号が青なので渡ります
信号が青なので渡ります
信号が赤なので待ちます
信号がついていないが渡ります
信号が赤なので待ちます

サンプルコードその2

require 'pp'

module Traffic
  class SignalStatus
    RED = ""
    GREEN = ""
    VANISHED = "消灯"

    attr_reader :color

    def self.green
      new(GREEN)
    end

    def self.red
      new(RED)
    end

    def self.vanished
      new(VANISHED)
    end

    def initialize(color)
      @color = color
    end

    def green?
      @color == GREEN
    end

    def red?
      @color == RED
    end

    def vanished?
      @color == VANISHED
    end
  end

  class Signal
    def self.signal_status
      begin
        case signal_random
        when 1
          SignalStatus.red
        when 2
          SignalStatus.green
        end
      rescue => e
        return SignalStatus.vanished
      end
    end

    def self.signal_random
      ret = rand(3).to_i + 1
      raise 'invalid' if ret == 3
      ret
    end
  end
end

10.times do
  signal_status = Traffic::Signal.signal_status
  if signal_status.green?
    puts "信号が青なので渡ります"
  elsif signal_status.red?
    puts "信号が赤なので待ちます"
  elsif signal_status.vanished?
    puts "信号がついていないが渡ります"
  end
end

出力(ランダム)

信号が赤なので待ちます
信号が赤なので待ちます
信号がついていないが渡ります
信号が赤なので待ちます
信号が赤なので待ちます
信号がついていないが渡ります
信号が赤なので待ちます
信号が赤なので待ちます
信号が青なので渡ります
信号が赤なので待ちます