在Ruby中实现枚举习语的最佳方法是什么?我正在寻找一些东西,我可以使用(几乎)像Java/ c#枚举。


当前回答

有人走在前面,写了一个红宝石宝石叫Renum。它声称获得了最接近Java/ c#的行为。就我个人而言,我仍然在学习Ruby,当我想让一个特定的类包含一个静态枚举(可能是一个散列)时,我有点震惊,因为它不太容易通过谷歌找到。

其他回答

这是我在Ruby中处理枚举的方法。我想要的是简短而甜蜜的,不一定是最像c的。任何想法吗?

module Kernel
  def enum(values)
    Module.new do |mod|
      values.each_with_index{ |v,i| mod.const_set(v.to_s.capitalize, 2**i) }

      def mod.inspect
        "#{self.name} {#{self.constants.join(', ')}}"
      end
    end
  end
end

States = enum %w(Draft Published Trashed)
=> States {Draft, Published, Trashed} 

States::Draft
=> 1

States::Published
=> 2

States::Trashed
=> 4

States::Draft | States::Trashed
=> 5

大多数人使用符号(即:foo_bar语法)。它们是一种独特的不透明值。符号不属于任何枚举类型,所以它们不是C的枚举类型的忠实表示,但这几乎是最好的。

也许最好的轻量级方法是

module MyConstants
  ABC = Class.new
  DEF = Class.new
  GHI = Class.new
end

这样,值就有了关联的名称,就像在Java/ c#中一样:

MyConstants::ABC
=> MyConstants::ABC

要获得所有的值,可以这样做

MyConstants.constants
=> [:ABC, :DEF, :GHI] 

如果你想要枚举的序号值,你可以这样做

MyConstants.constants.index :GHI
=> 2

另一种使用一致的平等处理来模拟枚举的方法(无耻地采用了Dave Thomas)。允许打开枚举(很像符号)和关闭(预定义的)枚举。

class Enum
  def self.new(values = nil)
    enum = Class.new do
      unless values
        def self.const_missing(name)
          const_set(name, new(name))
        end
      end

      def initialize(name)
        @enum_name = name
      end

      def to_s
        "#{self.class}::#@enum_name"
      end
    end

    if values
      enum.instance_eval do
        values.each { |e| const_set(e, enum.new(e)) }
      end
    end

    enum
  end
end

Genre = Enum.new %w(Gothic Metal) # creates closed enum
Architecture = Enum.new           # creates open enum

Genre::Gothic == Genre::Gothic        # => true
Genre::Gothic != Architecture::Gothic # => true

另一种方法是使用带有包含名称和值的散列的Ruby类,如下面的RubyFleebie博客文章所述。这允许您轻松地在值和常量之间进行转换(特别是如果您添加了一个类方法来查找给定值的名称)。