ar-enums

This is a simple solution for defining enumerations in your Rails models.

Description

It provides two forms of enumerations:

  • Internal, i.e. defined within the owner of the enum, for the simple cases.

  • External, i.e. defined on it’s own class, for the complex ones.

In both cases the enum values are stored in-memory. Let’s see some examples of both kinds.

Internal enumerations

Can be defined in three flavours:

Array of values style

This is the simplest and probably the most frecuent case:

class TrafficLight < ActiveRecord::Base
  enum :state, %w[red green yellow]
end

tl = TrafficLight.new(:state => :green)
tl.state          # => #<TrafficLight::State @name="green", @id=2>
tl.state_id       # => 2
tl.state.green?   # => true

As you can see each enum value is an instance of a dinamically generated class (which inherits from ActiveRecord::Enum) and has an ordinal value, id, autogenerated staring on 1.

The enumerations array is accessed with a class method:

TrafficLight.states  # => [#<TrafficLight::State @name="red", @id=1>, #<TrafficLight::State @name="green", @id=2>, ...]

By default when #to_s is called on a Enum instance it returns the name titleized, but this behaviour can be overrided. See Displaying Enums section below.

Array of hashes style

This allows you to define new columns in the Enum value. If the :id is not specified is generated for you.

class TrafficLight < ActiveRecord::Base
  enum :state, [
    { :name => :red, :stop_traffic => true, :rgb => 0xF00 },
    { :name => :green, :stop_traffic => false, :rgb => 0x0F0 }
  ]
end

tl = TrafficLight.new(:state => :green)
tl.state_id              # => 2    
tl.state.stop_traffic    # => false
tl.state.rgb             # => 0x0F0

Block style

class TrafficLight < ActiveRecord::Base
  enum :state do
    red :stop_traffic => true, :rgb => 0xF00
    green :stop_traffic => false, :rgb => 0x0F0
  end
end

External enumerations

When you have shared enumerations or just don’t want to clutter the owner model with enums definitions, the enumeration can be on it’s own class, as the State enum in the following example:

class TrafficLight < ActiveRecord::Base
  enum :state
end

class State < ActiveRecord::Enum
  enumeration do
    red :stop_traffic => true, :rgb => 0xF00, :desc => 'Rojo'
    green :stop_traffic => false, :rgb => 0x0F0, :desc => 'Verde'
  end
end

State[:red]         # => #<State @name="red", @id=1, ...>
State[:red].to_s    # => "Rojo"

Note the block style sintax is exactly the same as in the internal enumerations. In fact any of the 3 styles mencioned above can be used on external enumerations.

Also note the #to_s by default return the value of the :desc column. Of course you can override the #to_s method as usual.

Then you can access the enumerations collection from both places:

TrafficLight.states  # => [#<State @name="red", @id=1, ...>, #<State @name="green", @id=2, ...>]
States.all           # => [#<State @name="red", @id=1, ...>, #<State @name="green", @id=2, ...>]

The enum method accept a :class_method option similar to the one in belongs_to and others to specify the class of the enum.

Displaying Enums

In the array of values style the default is the name titleized but you can pass a :label options to override:

class TrafficLight < ActiveRecord::Base
  enum :state, %w[red green yellow], :label => :upcase
end

TrafficLight.states.map(&:to_s)   # => ["RED", "GREEN", "YELLOW"]

If you use the block o array of hashes sintax and add a :desc column it will be used as #to_s, unless a :label option is passed.

TODO

  • Remove the dependency with ActiveRecord so it can be used outside Rails.

  • Allow to store enums in the database.

Note on Patches/Pull Requests

  • Fork the project.

  • Make your feature addition or bug fix.

  • Add tests for it. This is important so I don’t break it in a future version unintentionally.

  • Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)

  • Send me a pull request. Bonus points for topic branches.

Copyright © 2010 Emmanuel Nicolau. See LICENSE for details.