C-style enums for ruby
This project is an attempt to provide c-style enums for ruby. It's obviously impossible (and not even desirable) to capture the exact syntax and semantics of c's enums in a ruby implementation, but the major capabilities and usage patterns are supported.
But ruby has symbols, why do we need enums?
Symbols are great. You should probably keep on using symbols in most of the places that you currently do. There are, however, certain situations that enums are better suited for. For instance:
A variable can take on a finite set of known, named, values.
The set of values that a variable can take on define that variable's type. Rather than just scattering symbols throughout your code that modifes the variable, it is frequently helpful to encapsulate the type information in one place. An enum, being a lightweight, in-line class definition, is an ideal place to do this. Examples of this type of situation would be when you need to represent days-of-the-week or drink sizes available
DayOfWeek = enum :sun, :mon, :tues, :wed, :thurs, :fri, :sat DrinkSize = enum :small, :medium, :large
A dual name/value representation is needed. This is particularly common when you have a set of possible values with an inherent ordering.
Enums have the property of defining both names and values, so you can sometimes get the best of both worlds by using them.
DrinkSize = enum :small, :medium, :large DrinkSize::SMALL < DrinkSize::LARGE # true
require 'cenum' class PetOwner Animals = enum :cat, :dog, :bird def initialize(animal) @animal = animal || Animals::DOG end def pet_says case @animal when Animals::CAT then 'meow' when Animals::DOG then 'woof' when Animals::BIRD then 'tweet' end end end bird_owner = PetOwner.new(PetOwner::Animals::BIRD) bird_owner.pet_says # 'tweet'
Enums contain a list of their values
irb> Directions = enum :up, :down, :left, :right irb> Directions.values [:up, :down, :left, :right]
Enum values map to integers
irb> Directions::UP 0 irb> Directions::DOWN 1
Enum declaration is type declaration
irb> Boolean = enum :true, :false irb> yes = Boolean.new(:true) irb> no = Boolean.new(:false) irb> yes == no false
Value checks and mutators generated automatically
irb> Boolean = enum :true, :false irb> yes = Boolean.new(:true) irb> no = Boolean.new(:false) irb> yes.true? true irb> no.true? false irb> maybe = Boolean.new(:true) irb> maybe == yes true irb> maybe.false! irb> maybe == yes false irb> maybe == no true
Direct comparison of type instances with value names
irb> Boolean = enum :true, :false irb> yes = Boolean.new(:true) irb> yes == Boolean::TRUE true irb> yes != Boolean::FALSE true
Values can be compared
irb> up = Directions.new(:up) irb> down = Directions.new(:down) irb> up < down true
Values can be compared to their names
irb> up == :up true
Custom value mappings
irb> Drinks = enum :small, :medium, :large, :infinite => -1 irb> Drinks::SMALL 0 irb> Drinks::MEDIUM 1 irb> Drinks::INFINITE -1
$ gem install cenum
Building it yourself
$ git clone email@example.com:microsage/cenum.git $ cd cenum $ gem build cenum.gemspec $ gem install cenum
- Improve custom value mappings
- Prevent collisions
- Allow non-integer value mappings
- Consider using a DSL to improve syntax (gets messy in some cases currently)