How to implement Enums in Ruby? How to implement Enums in Ruby? ruby ruby

How to implement Enums in Ruby?


Two ways. Symbols (:foo notation) or constants (FOO notation).

Symbols are appropriate when you want to enhance readability without littering code with literal strings.

postal_code[:minnesota] = "MN"postal_code[:new_york] = "NY"

Constants are appropriate when you have an underlying value that is important. Just declare a module to hold your constants and then declare the constants within that.

module Foo  BAR = 1  BAZ = 2  BIZ = 4end flags = Foo::BAR | Foo::BAZ # flags = 3

Added 2021-01-17

If you are passing the enum value around (for example, storing it in a database) and you need to be able to translate the value back into the symbol, there's a mashup of both approaches

COMMODITY_TYPE = {  currency: 1,  investment: 2,}def commodity_type_string(value)  COMMODITY_TYPE.key(value)endCOMMODITY_TYPE[:currency]

This approach inspired by andrew-grimm's answer https://stackoverflow.com/a/5332950/13468

I'd also recommend reading through the rest of the answers here since there are a lot of ways to solve this and it really boils down to what it is about the other language's enum that you care about


I'm surprised that no one has offered something like the following (harvested from the RAPI gem):

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  endend

Which can be used like so:

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,     0x2000end

Example:

>> 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

This plays well in database scenarios, or when dealing with C style constants/enums (as is the case when using FFI, which RAPI makes extensive use of).

Also, you don't have to worry about typos causing silent failures, as you would with using a hash-type solution.


The most idiomatic way to do this is to use symbols. For example, instead of:

enum {  FOO,  BAR,  BAZ}myFunc(FOO);

...you can just use symbols:

# You don't actually need to declare these, of course--this is# just to show you what symbols look like.:foo:bar:bazmy_func(:foo)

This is a bit more open-ended than enums, but it fits well with the Ruby spirit.

Symbols also perform very well. Comparing two symbols for equality, for example, is much faster than comparing two strings.