Ruby
Rails
module
enum
Swift

[Ruby] moduleをSwiftのenumみたいに使ってみる

環境関連

$ ruby -v 
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin17]

$ rails -v
Rails 5.2.0

参考にしたサイト

@yuch_i さんの記事↓
https://qiita.com/yuch_i/items/fa823a5ee3d569859137

やりたいこと

Swiftだとこんなイメージ

enum Type {
  case typeA
  case typeB
  case typeC
}

class Hoge: UIViewController {

  //.....

  func hogeeee(type: Type) {
    switch type {
    case .typeA:
      // typeAの時にしたい処理
      print("typeA !!")      
    case .typeB:
      // typeBの時にしたい処理
      print("typeB !!")
    case .typeC:
      // typeCの時にしたい処理
      print("typeC !!")
    default:
      // 例外とか
    }
  }  

  //.....  
}

んー、美しい。

何がしたいのか整理してみる

  • 引数の値が、決められた値の中のどれかを判別し、該当の処理を行いたい
  • 決められた値、が変動する際に修正が容易になるようにしたい
  • 見た目をスタイリッシュにしたい(固定文字列とか使いたくない)

元々のRubyでの処理

# name ==> 'hoge', 'huga', 'foo' の3種類
# location ==> 'japan', 'usa', 'italy' の3種類

class xxxUtil
  def send_url(name, location)
    # TODO: nameのパターンが増えたらどうする!?
    case name
    when 'hoge' then
      # TODO: locationのパターンが増えたらどうする!?
      case location
      when 'japan' then
        # 'hoge' かつ 'japan'の時の処理
      when 'usa' then
        # 'hoge' かつ 'usa'の時の処理
      when 'italy' then
        # 'hoge' かつ 'italy'の時の処理
      end
    when 'huga' then
      # 同上
    when 'foo' then
      # 同上
    else
      # 例外の時の処理
    end
  end
end

こんな感じに、固定文字列をそのまま記載していた感じ。
name/locationのパターンがずっと固定ならば、イケてはいないですが、まだ許せるかもと思って見て見ぬ振りをしてました...
ただ、今回パターンが増えることになってしまい、今後のことも考えるとやはり不便だったので、整理してみようと思ったのが経緯です。

最終的に

module Name
  HOGE = 'hoge'
  HUGA = 'huga'
  FOO  = 'foo'
end

module Location
  JAPAN = 'japan'
  USA   = 'usa'
  ITALY = 'italy'
end

class xxxUtil
  def send_url(name, location)
    # TODO: nameのパターンが増えたらここ増やす
    case name
    when Name::HOGE then
      # TODO: locationのパターンが増えたらここ増やす
      case location
      when Location::JAPAN then
        # 'hoge' かつ 'japan'の時の処理
      when Location::USA then
        # 'hoge' かつ 'usa'の時の処理
      when Location::ITALY then
        # 'hoge' かつ 'italy'の時の処理
      end
    when Name::HUGA then
      # 同上
    when Name::FOO then
      # 同上
    else
      # 例外の時の処理
    end
  end
end

これに変えると何がうまいのか

  • Name/Locationの既存の各値が変更になった時に容易(特に複数箇所から参照されて同じような判別処理が必要になる場合)
  • Name/Locationに項目が追加になった時、case文も修正することになるが、修正箇所を追いやすくなる('Location'で検索して、対応のcase文を直せば良くなる)

※ 今回は、似たような判別式が複数箇所に必要になる場合だったので、特にありがたみを感じました。

注意点

・moduleの記載が別ファイルの場合、moduleを記載しているファイルをrequire_relative(インポート)しないと参照出来ないっぽい

まとめ

今回のアプローチが正しいのかは、わかりませんが....
なんとなく見やすくなって、コードも気分もスッキリしました。
この修正後、項目追加しても修正範囲がわかりやすくて、作業しやすくなった気がします。