Faking it: enums in Ruby

Ruby doesn’t have enums and in Rails I sometimes need it. I’ve come out with my own way of doing after some trial and error. First I want to be able to access these enums as constants in a class, like:

Pizza::RAW
Pizza::COOKED
Pizza::BOXED
Pizza::DELIVERED
Pizza::EATEN

That’s actually quite easy:

class Pizza
  RAW = 1
  COOKED = 2
  BOXED = 3
  DELIVERED = 4
  EATEN = 5
end

If I’m storing those values on the database, I’d like to have my database be more readable, so, I just store strings:

class Pizza
  RAW = "raw"
  COOKED = "cooked"
  BOXED = "boxed"
  DELIVERED = "delivered"
  EATEN = "eaten"
end

That’s not very efficient and there are better ways these days. But it’s simple and premature optimization is the root of all evil. Anyway, back to Ruby, I’d like to be able to get a list of all possible enum values, to be able to populate selections for example:

class Pizza
  RAW = "raw"
  COOKED = "cooked"
  BOXED = "boxed"
  DELIVERED = "delivered"
  EATEN = "eaten"

  STATES = [RAW, COOKED, BOXED, DELIVERED, EATEN]
end

Simple enough except that it doesn’t follow DRY style. In Ruby we can do better:

class Pizza
  STATES = [
    RAW = "raw",
    COOKED = "cooked",
    BOXED = "boxed",
    DELIVERED = "delivered",
    EATEN = "eaten"
  ]
end

That defines the constant and since the result of RAW = "raw" is "raw" we can also add it to an array at the same time.

John, the manager of the Ruby Pizza Shop was concerned that some pizzas were devoured immediately and others took as long as 15 minutes. Decided to improve his business he started investigating the whole procedure and he noticed that as soon as the pizza left the kitchen, some cooks considered delivered and marked them as such. That was wrong so instead of doing a pizza-state training, he decided we should improve the UI. Let’s describe the state.

class Pizza
  STATES = [
    RAW = "raw",
    COOKED = "cooked",
    BOXED = "boxed",
    DELIVERED = "delivered",
    EATEN = "eaten"
  ]

  STATE_EXPLANATIONS {
    RAW => "The pizza is not a pizza yet, just a bunch of ingredients.",
    COOKED => "OMG! That smells good!",
    BOXED => "It's ready to go.",
    DELIVERED => "The pizza has been snatched out of the hands of a delivery boy.",
    EATEN => "The pizza is no more."
  }
end

Of course we can do better than that and merge it in one:

class Pizza
  STATE {
    (RAW = "raw") => "The pizza is not a pizza yet, just a bunch of ingredients.",
    (COOKED = "cooked") => "OMG! That smells good!",
    (BOXED = "boxed") => "It's ready to go.",
    (DELIVERED = "delivery") => "The pizza has been snatched out of the hands of a delivery boy.",
    (EATEN = "eaten") => "The pizza is no more."
  }
end

Stylistically I’m not a fan, but semantically, that’s dryer. Now, we can get the list of states like this:

Pizza::STATE.keys
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.