Skip to content
53 changes: 42 additions & 11 deletions README.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Enum values are stored in memory at the moment but I plan to add database and po

From version 0.7 onwards this plugin will only have Rails 3 support. If you need Rails 2 compatibility, {check the 0.6 branch}[https://github.com/adzap/active_enum/tree/0.6].

gem install active_enum
gem install active_enum

Put this in your Gemfile

Expand Down Expand Up @@ -43,6 +43,17 @@ Define using implicit id values
value :name => 'Female'
end

Define using symbol ids

class Sex < ActiveEnum::Base
value :id => :m, :name => 'Male'
value :id => :f, :name => 'Female'
end

*NOTE*
If you are using ids as symbols, name cannot be used as symbols in all methods. Symbolized name using works only with
integer ids.

Beware that if you change the order of values defined in an enum which don't have explicit ids, then the ids will change.
This could corrupt your data if the enum values have been stored in a model record, as they will no longer map to
the original enum.
Expand All @@ -64,6 +75,18 @@ Enum class usage
Sex.meta(1) # => { :symbol => '♂' }
Sex.to_select # => [['Male', 1], ['Female',2]] for select form helpers

When using symbol ids

class Sex < ActiveEnum::Base
value :id => :m, :name => 'Male', :symbol => '♂'
value :id => :f, :name => 'Female', :symbol => '♀'
end

Sex[:m] # => 'Male'
Sex["Male"] # => :m
Sex[:male] # => nil


=== Ordering

To define the sorting of returned values use the order method. Which is useful for to_select method.
Expand Down Expand Up @@ -149,6 +172,14 @@ You can check if the attribute value matches a particular enum value by passing
user.sex?('Male') # => true
user.sex?('Female') # => false

If you are using symbol ids

user.sex?(:m) # => true
user.sex?('Male') # => true
user.sex?(:male) # => false
user.sex?(:f) # => false


=== Enum lookup

A convenience method on the class is available to the enum class of any enumerated attribute
Expand Down Expand Up @@ -213,7 +244,7 @@ Or, SimpleForm:
The input type will be automatically detected for enumerated attributes. You can override with the :as option as normal.


== Storage Backends
== Storage Backends

The design allows pluggable backends to be used for stories and retrieving the enum values. At present there are two
available, memory or I18n. To change the storage engine you alter the storage config value like so:
Expand All @@ -228,7 +259,7 @@ The memory store is default obviously just stores the values in memory.
=== I18n Storage

The I18n storage backend stores the ids and names is memory still, but retrieves the name text translation any call to
the enum public methods.
the enum public methods.

To set up the locale file, run

Expand All @@ -237,17 +268,17 @@ To set up the locale file, run
This generates the YML locale template in your default language as configured in the application.rb.

Here are some examples of defining enum translations

class Sex < ActiveEnum::Base
value 1 => 'male'
value 2 => 'female'
end
becomes

becomes

sex:
male: Male
female: Female
male: Male
female: Female

For namesapced enums in a model

Expand All @@ -259,11 +290,11 @@ For namesapced enums in a model
end

nest the translations under the underscored model name

person:
sex:
male: Male
female: Female
male: Male
female: Female


== License
Expand Down
34 changes: 24 additions & 10 deletions lib/active_enum/base.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module ActiveEnum
class DuplicateValue < StandardError; end
class InvalidValue < StandardError; end
class InvalidId < StandardError; end

class Base

Expand All @@ -22,7 +23,7 @@ def value(enum_value)
store.set *id_and_name_and_meta(enum_value)
end

# Specify order enum values are returned.
# Specify order enum values are returned.
# Allowed values are :asc, :desc or :natural
#
def order(order)
Expand Down Expand Up @@ -55,13 +56,17 @@ def to_select
# Access id or name value. Pass an id number to retrieve the name or
# a symbol or string to retrieve the matching id.
def get(index)
if index.is_a?(Fixnum)
if index.is_a?(Fixnum) || index.is_a?(Symbol)
row = store.get_by_id(index)
row[1] if row
else
value = row[1] if row
end

if (index.is_a?(String) || (index.is_a?(Symbol) && !symbol_ids?)) && value.nil?
row = store.get_by_name(index)
row[0] if row
value = row[0] if row
end

value
end
alias_method :[], :get

Expand All @@ -71,12 +76,21 @@ def include?(value)

# Access any meta data defined for a given id or name. Returns a hash.
def meta(index)
row = if index.is_a?(Fixnum)
store.get_by_id(index)
else
store.get_by_name(index)
if index.is_a?(Fixnum) || index.is_a?(Symbol)
row = store.get_by_id(index)
value = row[2] if row
end
row[2] || {} if row

if (index.is_a?(String) || (index.is_a?(Symbol) && !symbol_ids?)) && value.nil?
row = store.get_by_name(index)
value = row[2] if row
end

value || {}
end

def symbol_ids?
store.symbol_ids?
end

private
Expand Down
22 changes: 16 additions & 6 deletions lib/active_enum/extensions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,13 @@ def define_active_enum_read_method(attribute)
class_eval <<-DEF
def #{attribute}(arg=nil)
value = super()
return if value.nil? && arg.nil?

enum = self.class.active_enum_for(:#{attribute})


return if arg.nil? && (value.nil? || (enum.symbol_ids? && value.empty?))

value = value.to_sym if enum.symbol_ids? && !value.nil?

case arg
when nil
#{ActiveEnum.use_name_as_value ? 'enum[value]' : 'value' }
Expand All @@ -100,7 +104,7 @@ def #{attribute}(arg=nil)
DEF
end

# Define write method to also handle enum value
# Define write method to also handle enum value (only integer ids)
#
# Examples:
# user.sex = 1
Expand All @@ -109,8 +113,9 @@ def #{attribute}(arg=nil)
def define_active_enum_write_method(attribute)
class_eval <<-DEF
def #{attribute}=(arg)
if arg.is_a?(Symbol)
super self.class.active_enum_for(:#{attribute})[arg]
enum = self.class.active_enum_for(:#{attribute})
if arg.is_a?(Symbol) and !enum.symbol_ids?
super enum[arg]
else
super arg
end
Expand All @@ -127,7 +132,12 @@ def define_active_enum_question_method(attribute)
class_eval <<-DEF
def #{attribute}?(arg=nil)
if arg
self.#{attribute}(:id) == self.class.active_enum_for(:#{attribute})[arg]
enum = self.class.active_enum_for(:#{attribute})
if enum.symbol_ids? and arg.is_a?(Symbol)
self.#{attribute}(:id) == arg
else
self.#{attribute}(:id) == enum[arg]
end
else
super()
end
Expand Down
9 changes: 9 additions & 0 deletions lib/active_enum/storage/memory_store.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
module ActiveEnum
module Storage
class MemoryStore < AbstractStore
attr_accessor :symbol_ids

def set(id, name, meta=nil)
raise ActiveEnum::InvalidId, 'Id cannot be string.' if id.is_a? String
raise ActiveEnum::InvalidId, 'Id types cannot be mixed.' unless symbol_ids.nil? or symbol_ids? == id.is_a?(Symbol)

self.symbol_ids = id.is_a?(Symbol) if self.symbol_ids.nil?

check_duplicate id, name
_values << [id, name.to_s, meta].compact
sort!
Expand Down Expand Up @@ -35,6 +41,9 @@ def _values
@_values ||= []
end

def symbol_ids?
!!symbol_ids
end
end
end
end
Loading