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


当前回答

另一种解决方案是使用OpenStruct。它非常简单明了。

https://ruby-doc.org/stdlib-2.3.1/libdoc/ostruct/rdoc/OpenStruct.html

例子:

# bar.rb
require 'ostruct' # not needed when using Rails

# by patching Array you have a simple way of creating a ENUM-style
class Array
   def to_enum(base=0)
      OpenStruct.new(map.with_index(base).to_h)
   end
end

class Bar

    MY_ENUM = OpenStruct.new(ONE: 1, TWO: 2, THREE: 3)
    MY_ENUM2 = %w[ONE TWO THREE].to_enum

    def use_enum (value)
        case value
        when MY_ENUM.ONE
            puts "Hello, this is ENUM 1"
        when MY_ENUM.TWO
            puts "Hello, this is ENUM 2"
        when MY_ENUM.THREE
            puts "Hello, this is ENUM 3"
        else
            puts "#{value} not found in ENUM"
        end
    end

end

# usage
foo = Bar.new    
foo.use_enum 1
foo.use_enum 2
foo.use_enum 9


# put this code in a file 'bar.rb', start IRB and type: load 'bar.rb'

其他回答

我很惊讶,没有人提供以下内容(从RAPI宝石中收获):

class Enum

  private

  def self.enum_attr(name, num)
    name = name.to_s

    define_method(name + '?') do
      @attrs & num != 0
    end

    define_method(name + '=') do |set|
      if set
        @attrs |= num
      else
        @attrs &= ~num
      end
    end
  end

  public

  def initialize(attrs = 0)
    @attrs = attrs
  end

  def to_i
    @attrs
  end
end

可以这样使用:

class FileAttributes < Enum
  enum_attr :readonly,       0x0001
  enum_attr :hidden,         0x0002
  enum_attr :system,         0x0004
  enum_attr :directory,      0x0010
  enum_attr :archive,        0x0020
  enum_attr :in_rom,         0x0040
  enum_attr :normal,         0x0080
  enum_attr :temporary,      0x0100
  enum_attr :sparse,         0x0200
  enum_attr :reparse_point,  0x0400
  enum_attr :compressed,     0x0800
  enum_attr :rom_module,     0x2000
end

例子:

>> example = FileAttributes.new(3)
=> #<FileAttributes:0x629d90 @attrs=3>
>> example.readonly?
=> true
>> example.hidden?
=> true
>> example.system?
=> false
>> example.system = true
=> true
>> example.system?
=> true
>> example.to_i
=> 7

这在数据库场景中很好,或者在处理C风格的常量/枚举时(就像使用FFI时一样,RAPI广泛使用FFI)。

此外,您不必像使用散列类型解决方案那样,担心拼写错误会导致无声失败。

这是我在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
module Status
  BAD  = 13
  GOOD = 24

  def self.to_str(status)
    for sym in self.constants
      if self.const_get(sym) == status
        return sym.to_s
      end
    end
  end

end


mystatus = Status::GOOD

puts Status::to_str(mystatus)

输出:

GOOD

我认为实现类似类型的枚举的最好方法是使用符号,因为它们的行为非常像整数(当涉及到性能时,object_id用于进行比较);你不需要担心索引,它们在你的代码xD中看起来非常整洁

这似乎有点多余,但这是我使用过几次的方法,特别是在集成xml或类似的方法时。

#model
class Profession
  def self.pro_enum
    {:BAKER => 0, 
     :MANAGER => 1, 
     :FIREMAN => 2, 
     :DEV => 3, 
     :VAL => ["BAKER", "MANAGER", "FIREMAN", "DEV"]
    }
  end
end

Profession.pro_enum[:DEV]      #=>3
Profession.pro_enum[:VAL][1]   #=>MANAGER

这给了我c#枚举的严谨性,并且它与模型绑定。