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.
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
$ git clone [email protected]:microsage/cenum.git
$ cd cenum
$ gem build cenum.gemspec
$ gem install cenum
- Improve custom value mappings
- Spec
- Prevent collisions
- Allow non-integer value mappings
- Consider using a DSL to improve syntax (gets messy in some cases currently)