enumerize-2.1.0で試しています。
value_class
というREADMEに記載されていないオプションを利用すると、Enumerizeの値のクラスをvalue_class
で指定したクラスに差し替えることができる。123
# Enumerize::Valueを継承するとi18n関連のメソッドもついてくるので便利
class Role < Enumerize::Value
end
class User
extend Enumerize
enumerize :sex, in: [:male, :female]
enumerize :role, in: [:user, :admin], value_class: Role
end
User.sex.values.first
# => "male"
User.sex.values.first.class
# => Enumerize::Value
User.role.values.first
# => "user"
User.role.values.first.class
# => Role <- value_classで指定したクラスになっている。
べんりっぽい。
リッチなvalue_classを作る
Enumerize::Valueのコンストラクタを確認してみると次のようになっている
# https://github.com/brainspec/enumerize/blob/v2.1.0/lib/enumerize/value.rb#L9
def initialize(attr, name, value=nil)
end
attr
はEnumerize::Attribute
のインスタンス。name
, value
はenumerize :role, in: [:user, :admin]
で言う所のin:
の値が入る。実装はこんな感じ
# https://github.com/brainspec/enumerize/blob/v2.1.0/lib/enumerize/attribute.rb#L15
@values = Array(options[:in]).map { |v| value_class.new(self, *v) }
この実装からすると、in:
に配列の配列を渡すことによって、valueにいろんな情報を持たせるとこができそうだ。
試しにJava TutorialのEnumのサンプル4をEnumerizeで実装してみる。
class Planet < Enumerize::Value
VALUES = [
# name value mass radius
[ :mercury, 1, 3.303e+23, 2.4397e+6 ],
[ :venus, 2, 4.869e+24, 6.0518e+6 ],
[ :earth, 3, 5.976e+24, 6.37814e+6 ],
[ :mars, 4, 6.421e+23, 3.3972e+6 ],
[ :jupiter, 5, 1.9e+27, 7.1492e+7 ],
[ :saturn, 6, 5.688e+26, 6.0268e+7 ],
[ :uranus, 7, 8.686e+25, 2.5559e+7 ],
[ :neptune, 8, 1.024e+26, 2.4746e+7 ],
]
G = 6.67300e-11
attr_reader :mass, :radius
def initialize(attr, name, value, mass, radius)
@mass = mass
@radius = radius
super(attr, name, value)
end
def surface_gravity
G * mass / (radius * radius)
end
def surface_weight(other_mass)
other_mass * surface_gravity
end
end
class Hoge
extend Enumerize
enumerize :planet,
in: Planet::VALUES, default: :earth, value_class: Planet,
predicates: { prefix: true }
def initialize(planet)
self.planet = planet
end
end
Hoge.new(:jupiter).planet_jupiter?
# => true
Hoge.new(:jupiter).planet.class
# => Planet
earth_weight = 175
mass = earth_weight/Hoge.planet.find_value(:earth).surface_gravity
Hoge.planet.values.map do |planet|
[planet, planet.surface_weight(mass)]
end
# => [["mercury", 66.10758266016366], ["venus", 158.374842472183], ["earth", 175.0], ["mars", 66.27900720649755], ["jupiter", 442.84756696175464], ["saturn", 186.55271929202416], ["uranus", 158.3972598931494], ["neptune", 199.20741268219018]]
うまくいってる。