Swiftのenumが使いやすくて好きです。
Rubyには標準でenumがなく、gemでも同じような動きをしてくれるものがなかったので、自作してみました。
swifty_enum | RubyGems.org
zeero/ruby-swifty_enum | GitHub
インストール
RubyGemsに登録済みなので、bundler経由で。
gem 'swifty_enum'
$ bundle
または直接。
$ gem install swifty_enum
使い方
enumを定義する
- クラスを作成し、SwiftyEnumモジュールをincludeします。(以下、enumクラスと呼びます)
-
def_case 名前 [値]
でenumの要素(Swiftでいうcase)を作成します。(以下、enumケースと呼びます) - 指定した名前のサブクラスが定義されます。
サンプルはこんな感じです。
require 'swifty_enum'
class Flag
include SwiftyEnum
def_case :On, '1'
def_case :Off, '0'
end
Flag::On # => Flag::On
enumケースに定義されるメソッド
Swiftでも用意されているhashvalue、rawvalueをenumケースで使えるようにしています。
Flag::On.hashvalue # => 0
Flag::On.rawvalue # => '1'
def_case
でrawvalueが指定されなかった場合は、hashvalueをrawvalueの代わりに使うようにしています。ここはSwiftと振る舞いが違うことになってしまうので少し悩んでいます。。。
enumケースの生成
rawvalueに指定した値を使って、enumクラスのget
メソッドからenumケースを生成できます。
定義していないrawvalueで呼び出すとnilになります。
Flag.get('1') # => Flag::On
Flag.get('0') # => Flag::Off
Flag.get('2') # => nil
enumケースはスイッチ文で分岐することもできます。
on = Flag.get('1')
case on
when Flag::Off then
puts 'NG'
when Flag::On then
puts 'OK'
else
puts 'NG'
end
# >> OK
enumケースに独自メソッドを追加する
enumクラス定義内でdef_method
を使うことにより、enumケースに独自のメソッドを追加できます。
メソッドの戻り値はメソッドの最後の値になります。return
は使用できません。(LocalJumpErrorになってしまいます)
class Flag
include SwiftyEnum
def_case :On, '1'
def_case :Off, '0'
# メソッドを追加
def_method :status do |enum_case|
case enum_case
when On then
'OK'
when Off then
'NG'
end
end
# 引数をもつメソッドは可変長引数として受け取ることができる
def_method :status_with do |enum_case, args|
if args.empty?
enum_case.status
else
with = args.join(', ')
"#{enum_case.status} with #{with}"
end
end
end
Flag::On.status # => 'OK'
Flag::Off.status # => 'NG'
Flag::On.status_with('foo') # => 'OK with foo'
ブロックの引数に自分自身が渡ってくるのでケースで分岐させることができます。
定義内なのでenumクラスの名前まで(上記例ではFlag::
)は省略することができます。
また注意点ですが、def_method
はすべてのenumケースを定義したあとに呼び出してください。
すべてのenumケースを取得する
Swiftのenumにはない機能ですが、すべてのenumケースを取得するenum_case
メソッドを追加しています。
Flag.enum_cases # => [Flag::On, Flag::Off]
おわり
Swiftのenumの一通りの機能はつけれたかなと思ってます。
要望やご意見などありましたらコメントやGithubイシューをもらえると嬉しいです。