First of all, this is not a duplicate of Enums in Ruby :)
The accepted answer of that question suggests this as a good way to represent enums in Ruby:
cl
This is my suggested code...
EnumModule.rb
module EnumModule
CONVERT_PROC = Proc.new do
@values = constants.collect{|c| const_get(c)}.freeze
@values.each_with_index do |value, idx|
the_symbol = constants.find{|c| const_get(c) == value}
sig = class << value ; self end
sig.send :define_method, :name, proc{the_symbol}
sig.send :define_method, :ordinal, proc{idx}
if value.is_a? Hash
value.each do |k, v|
sig.send :define_method, k, (v.is_a?(Proc) ? v : proc{v})
end
end
value.freeze
end
class << self
alias :value_of :const_get
end
module_function
def each
@values.each { |v| yield v }
end
def values
@values
end
extend Enumerable
freeze
end
def self.extended extending_obj
extending_obj.module_eval &CONVERT_PROC
end
end
SampleEnum.rb
require 'EnumModule'
module SampleEnum
VALUE_1 = {
to_s: 'Value_1_str',
get_value: proc{'Value 1'}
}
VALUE_2 = {
to_s: 'Value_2_str',
get_value: proc{'Value 2'}
}
extend EnumModule
end
#defined method
p SampleEnum::VALUE_1.get_value #=> "Value 1"
p SampleEnum::VALUE_2.get_value #=> "Value 2"
p SampleEnum::VALUE_1.to_s #=> "Value_1_str"
#name (returns the symbol of the constant)
p SampleEnum::VALUE_1.name #=> :VALUE_1
p SampleEnum::VALUE_2.name #=> :VALUE_2
#ordinal
p SampleEnum::VALUE_1.ordinal #=> 0
p SampleEnum::VALUE_2.ordinal #=> 1
#emulates Java Enum's valueOf(is an alias of const_get)
p SampleEnum.value_of('VALUE_1').get_value #=> "Value 1"
p SampleEnum.value_of(:VALUE_1).get_value #=> "Value 1"
p SampleEnum.const_get('VALUE_1').get_value #=> "Value 1"
#emulates Java Enum's values
SampleEnum.values.each do |m|
p m.ordinal, m.name, m.get_value, m.to_s
end
#an Enumerable
p SampleEnum.map{|m| m.get_value} #=> ["Value 1","Value 2"]
By extending the EnumModule
, Hash
constants' contents (key & value) become Singleton methods.