首先,这不是Enums in Ruby的重复:)
该问题的公认答案表明这是在Ruby中表示枚举的好方法:
class Foo
BAR = 1
BAZ = 2
BIZ = 4
end
在Java中,可以将多个值和方法附加到枚举值。我想在Ruby中实现相同或类似的东西。
表示此Java枚举的最类似Ruby的方式是什么:
public enum Enum
VALUE_1("Value 1"),
VALUE_2("Value 2"),
VALUE_3("Value 3");
Enum(String value) {
this.value = value;
}
public String getValue() {
return value;
}
private String value;
}
编辑:
我还想保留Java枚举的隐含功能:
示例:
Enum.VALUE_1.getValue(); // "Value 1"
Enum.VALUE_2.name(); // "VALUE_2"
Enum.VALUE_3.ordinal(); // 2
答案 0 :(得分:12)
class MyEnum
attr_accessor :value
def initialize(value)
@value = value
end
VALUE1 = new("Value 1")
VALUE2 = new("Value 2")
class << self
private :new
end
end
MyEnum::VALUE2 # Enum with value "Value 2"
MyEnum.new # Error
更精细的解决方案,允许您定义任意“枚举类”,并为您提供ordinal()
:
def enum(*values, &class_body)
Class.new( Class.new(&class_body) ) do
attr_reader :ordinal
def initialize(ordinal, *args, &blk)
super(*args, &blk)
@ordinal = ordinal
end
values.each_with_index do |(name, *parameters), i|
const_set(name, new(i, *parameters))
end
class <<self
private :new
end
end
end
# Usage:
MyEnum = enum([:VALUE1, "Value 1"], [:VALUE2, "Value 2"]) do
attr_reader :str
def initialize(str)
@str = str
end
end
MyEnum::VALUE1.str #=> "Value 1"
MyEnum::VALUE2.ordinal #=> 1
答案 1 :(得分:3)
您始终可以创建类似于Java版本的系统:
module Foo
class Value
attr_reader :value
def initialize(value)
# Save a frozen, immutable copy
@value = value.dup.freeze
end
# Patch in methods to make it appear more friendly and string-like
alias_method :to_s, :value
alias_method :inspect, :value
end
# Define constants
BAR = Value.new('bar')
BAZ = Value.new('baz')
BIZ = Value.new('biz')
end
puts Foo::BAR
# => bar
答案 2 :(得分:0)
这是我建议的代码......
<强> 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"]
通过扩展EnumModule
,Hash
常量'内容(键和值)成为Singleton方法。