diff --git a/README.rdoc b/README.rdoc index 1b31511..d4a80da 100644 --- a/README.rdoc +++ b/README.rdoc @@ -43,6 +43,13 @@ 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 + 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. diff --git a/lib/active_enum/acts_as_enum.rb b/lib/active_enum/acts_as_enum.rb index f88fdc5..d6bec9b 100644 --- a/lib/active_enum/acts_as_enum.rb +++ b/lib/active_enum/acts_as_enum.rb @@ -29,7 +29,7 @@ def to_select end def [](index) - if index.is_a?(Fixnum) + if index.is_a?(Integer) v = lookup_by_id(index) v.send(active_enum_options[:name_column]) unless v.blank? else diff --git a/lib/active_enum/base.rb b/lib/active_enum/base.rb index 29bf7fb..97092be 100644 --- a/lib/active_enum/base.rb +++ b/lib/active_enum/base.rb @@ -55,13 +55,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?(Integer) || 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)) && value.nil? row = store.get_by_name(index) - row[0] if row + value = row[0] if row end + + value end alias_method :[], :get @@ -71,12 +75,17 @@ 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?(Integer) || 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)) && value.nil? + row = store.get_by_name(index) + value = row[2] if row + end + + value || {} end private @@ -87,7 +96,7 @@ def id_and_name_and_meta(hash) name = hash.delete(:name) meta = hash return id, name, (meta.empty? ? nil : meta) - elsif hash.keys.first.is_a?(Fixnum) + elsif hash.keys.first.is_a?(Integer) return *Array(hash).first else raise ActiveEnum::InvalidValue, "The value supplied, #{hash}, is not a valid format." diff --git a/spec/active_enum/base_spec.rb b/spec/active_enum/base_spec.rb index 98c3df5..4d9da79 100644 --- a/spec/active_enum/base_spec.rb +++ b/spec/active_enum/base_spec.rb @@ -95,13 +95,28 @@ class NewEnum < ActiveEnum::Base; end end describe ".meta" do - it 'should return meta values hash for a given index value' do + it 'should return meta values hash for a given integer index value' do enum = define_enum do value :id => 1, :name => 'Name', :description => 'extra' end enum.meta(1).should == {:description => 'extra'} end + it 'should return meta values hash for a given symbol index value' do + enum = define_enum do + value :id => :one, :name => 'Name 1', :description => 'extra' + end + enum.meta(:one).should == {:description => 'extra'} + end + + it 'should match on id before name and return meta values hash' do + enum = define_enum do + value :id => :one, :name => 'Name 1', :description => 'extra' + value :id => :name_1, :name => 'Name 2', :description => 'extra2' + end + enum.meta(:name_1).should == {:description => 'extra2'} + end + it 'should return empty hash for index with no meta defined' do enum = define_enum do value :id => 1, :name => 'Name' @@ -161,24 +176,63 @@ class NewEnum < ActiveEnum::Base; end end context "element reference method" do - let(:enum) { - define_enum do - value :id => 1, :name => 'Name 1' - value :id => 2, :name => 'Name 2' + context 'integer ids' do + let(:enum) { + define_enum do + value :id => 1, :name => 'Name 1' + value :id => 2, :name => 'Name 2' + end + } + + it 'should return name when given an id' do + enum[1].should == 'Name 1' end - } - it 'should return name when given an id' do - enum[1].should == 'Name 1' - end + it 'should return id when given a name' do + enum['Name 1'].should == 1 + end - it 'should return id when given a name' do - enum['Name 1'].should == 1 + it 'should return id when given a symbol of the name' do + enum[:Name_1].should == 1 + enum[:name_1].should == 1 + end end - it 'should return id when given a symbol of the name' do - enum[:Name_1].should == 1 - enum[:name_1].should == 1 + context 'symbol ids' do + let(:enum) { + define_enum do + value :id => :one, :name => 'Name 1' + value :id => :two, :name => 'Name 2' + end + } + + it 'should return name when given an id' do + enum[:one].should == 'Name 1' + end + + it 'should return id when given a name' do + enum['Name 1'].should == :one + end + + it 'should return id when given a symbol of the name' do + enum[:Name_1].should == :one + enum[:name_1].should == :one + end + + context 'ids and names are similar' do + let(:enum) { + define_enum do + value :id => :one, :name => 'two' + value :id => :two, :name => 'three' + end + } + + it 'should match on id before name' do + enum[:one].should == 'two' + enum[:two].should == 'three' + enum[:three].should == :two + end + end end end diff --git a/spec/active_enum/form_helpers/formtastic2_spec.rb b/spec/active_enum/form_helpers/formtastic2_spec.rb index 7ef3b79..7373b6f 100644 --- a/spec/active_enum/form_helpers/formtastic2_spec.rb +++ b/spec/active_enum/form_helpers/formtastic2_spec.rb @@ -36,6 +36,35 @@ output.should have_xpath('//option[@value=2]', :content => 'Female') end + context 'with ids as symbols' do + before do + reset_class Person do + enumerate :sex do + value :id => :m, :name => 'Male' + value :id => :f, :name => 'Female' + end + end + end + + it "should use enum input type for enumerated attribute" do + output = semantic_form_for(Person.new, :url => people_path) do |f| + concat f.input(:sex) + end + output.should have_selector('select#person_sex') + output.should have_xpath("//option[@value='m']", :content => 'Male') + output.should have_xpath("//option[@value='f']", :content => 'Female') + end + + it "should use explicit :enum input type" do + output = semantic_form_for(Person.new, :url => people_path) do |f| + concat f.input(:sex, :as => :enum) + end + output.should have_selector('select#person_sex') + output.should have_xpath("//option[@value='m']", :content => 'Male') + output.should have_xpath("//option[@value='f']", :content => 'Female') + end + end + it "should not use enum input type if :as option indicates other type" do output = semantic_form_for(Person.new, :url => people_path) do |f| concat f.input(:sex, :as => :string) diff --git a/spec/active_enum/form_helpers/simple_form_spec.rb b/spec/active_enum/form_helpers/simple_form_spec.rb index fd19fb4..eb988fd 100644 --- a/spec/active_enum/form_helpers/simple_form_spec.rb +++ b/spec/active_enum/form_helpers/simple_form_spec.rb @@ -34,6 +34,36 @@ output.should have_xpath('//option[@value=2]', :content => 'Female') end + context 'with ids as symbols' do + before do + controller.stub!(:action_name).and_return('new') + reset_class Person do + enumerate :sex do + value :id => :m, :name => 'Male' + value :id => :f, :name => 'Female' + end + end + end + + it "should use enum input type for enumerated attribute" do + output = simple_form_for(Person.new, :url => people_path) do |f| + concat f.input(:sex) + end + output.should have_selector('select#person_sex') + output.should have_xpath("//option[@value='m']", :content => 'Male') + output.should have_xpath("//option[@value='f']", :content => 'Female') + end + + it "should use explicit :enum input type" do + output = simple_form_for(Person.new, :url => people_path) do |f| + concat f.input(:sex, :as => :enum) + end + output.should have_selector('select#person_sex') + output.should have_xpath("//option[@value='m']", :content => 'Male') + output.should have_xpath("//option[@value='f']", :content => 'Female') + end + end + it "should not use enum input type if :as option indicates other type" do output = simple_form_for(Person.new, :url => people_path) do |f| concat f.input(:sex, :as => :string) diff --git a/spec/active_enum/storage/i18n_store_spec.rb b/spec/active_enum/storage/i18n_store_spec.rb index d4f7033..578eb13 100644 --- a/spec/active_enum/storage/i18n_store_spec.rb +++ b/spec/active_enum/storage/i18n_store_spec.rb @@ -81,11 +81,16 @@ class TestI18nStoreEnum < ActiveEnum::Base; end I18n.locale = :en end - it 'should return the value for a given id' do + it 'should return the value for a given integer id' do store.set 1, 'test' store.get_by_id(1).should == [1, 'Testing'] end + it 'should return the value for a given symbol id' do + store.set :abc, 'test' + store.get_by_id(:abc).should == [:abc, 'Testing'] + end + it 'should return the value with meta for a given id' do store.set 1, 'test', :description => 'meta' store.get_by_id(1).should == [1, 'Testing', { :description => 'meta' }] @@ -93,6 +98,7 @@ class TestI18nStoreEnum < ActiveEnum::Base; end it 'should return nil when id not found' do store.get_by_id(1).should be_nil + store.get_by_id(:abc).should be_nil end it 'should return key when translation missing' do diff --git a/spec/active_enum/storage/memory_store_spec.rb b/spec/active_enum/storage/memory_store_spec.rb index 638f962..0deb4c6 100644 --- a/spec/active_enum/storage/memory_store_spec.rb +++ b/spec/active_enum/storage/memory_store_spec.rb @@ -53,13 +53,19 @@ class TestOtherAREnum < ActiveEnum::Base; end end describe "#get_by_id" do - it 'should return the value for a given id' do + it 'should return the value for a given integer id' do store.set 1, 'test name', :description => 'meta' store.get_by_id(1).should == [1, 'test name', {:description => "meta"}] end + it 'should return the value for a given symbol id' do + store.set :abc, 'test name', :description => 'meta' + store.get_by_id(:abc).should == [:abc, 'test name', {:description => "meta"}] + end + it 'should return nil when id not found' do store.get_by_id(1).should be_nil + store.get_by_id(:abc).should be_nil end end