8

I just want to know the best way to emulate a C# style enumeration in Ruby.

fooledbyprimes
  • 999
  • 1
  • 11
  • 29
  • Which specific features are you looking for? You could just put some symbols in an array... – p3t0r Oct 02 '08 at 21:47
  • Specifically, I would like to be able to perform logical tests against the set of values given some variable. Example would be the state of a window: "minimized, maximized, closed, open". – fooledbyprimes Oct 02 '08 at 21:59

5 Answers5

5

It's not quite the same, but I'll often build a hash for this kind of thing:

STATES = {:open => 1, :closed => 2, :max => 3, :min => 4}.freeze()

Freezing the hash keeps me from accidentally modifying its contents.

Moreover, if you want to raise an error when accessing something that doesn't exist, you can use a defualt Proc to do this:

STATES = Hash.new { |hash, key| raise NameError, "#{key} is not allowed" }
STATES.merge!({:open => 1, :closed => 2, :max => 3, :min => 4}).freeze()

STATES[:other] # raises NameError
Nate
  • 4,561
  • 2
  • 34
  • 44
5

Specifically, I would like to be able to perform logical tests against the set of values given some variable. Example would be the state of a window: "minimized, maximized, closed, open"

If you need the enumerations to map to values (eg, you need minimized to equal 0, maximised to equal 100, etc) I'd use a hash of symbols to values, like this:

WINDOW_STATES = { :minimized => 0, :maximized => 100 }.freeze

The freeze (like nate says) stops you from breaking things in future by accident. You can check if something is valid by doing this

WINDOW_STATES.keys.include?(window_state)

Alternatively, if you don't need any values, and just need to check 'membership' then an array is fine

WINDOW_STATES = [:minimized, :maximized].freeze

Use it like this

WINDOW_STATES.include?(window_state)

If your keys are going to be strings (like for example a 'state' field in a RoR app), then you can use an array of strings. I do this ALL THE TIME in many of our rails apps.

WINDOW_STATES = %w(minimized maximized open closed).freeze

This is pretty much what rails validates_inclusion_of validator is purpose built for :-)

Personal Note:

I don't like typing include? all the time, so I have this (it's only complicated because of the .in?(1, 2, 3) case:

class Object

    # Lets us write array.include?(x) the other way round
    # Also accepts multiple args, so we can do 2.in?( 1,2,3 ) without bothering with arrays
    def in?( *args )
        # if we have 1 arg, and it is a collection, act as if it were passed as a single value, UNLESS we are an array ourselves.
        # The mismatch between checking for respond_to on the args vs checking for self.kind_of?Array is deliberate, otherwise
        # arrays of strings break and ranges don't work right
        args.length == 1 && args.first.respond_to?(:include?) && !self.kind_of?(Array) ?
            args.first.include?( self ) :
            args.include?( self )
        end
    end
end

This lets you type

window_state.in? WINDOW_STATES
Community
  • 1
  • 1
Orion Edwards
  • 121,657
  • 64
  • 239
  • 328
  • Note: Adding instance methods to Object can be dangerous -- it's a little like adding stuff to the global namespace. Go down the Object#in? road with great caution. – Nate Oct 02 '08 at 22:55
3

I don't think Ruby supports true enums -- though, there are still solutions available.

Enumerations and Ruby

Jonathan Lonowski
  • 121,453
  • 34
  • 200
  • 199
3

The easiest way to define an Enum in ruby to use a class with constant variables.

class WindowState
  Open = 1
  Closed = 2
  Max = 3
  Min = 4
end
Ris Adams
  • 1,345
  • 4
  • 13
  • 25
1

Making a class or hash as others have said will work. However, the Ruby thing to do is to use symbols. Symbols in Ruby start with a colon and look like this:

greetingtype = :hello

They are kind of like objects that consist only of a name.

Neall
  • 26,428
  • 5
  • 49
  • 48