diff --git a/README.md b/README.md index 047a67d..8ab3fa0 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,24 @@ Thanks to the translation support, forms just work as you expect. Pass an invert = f.select :gender, User.human_genders.invert ``` +## Define Start Index + +Normal enum_accessor properties start at an index of 0 +```ruby +enum_accessor :currency, [:usd, :eur] + +> Business.currencies +=> {"usd"=>0, "eur"=>1} +``` +If you need to change the starting index, you can configure EnumAccessor to start the index at either 0 or 1. + +```ruby +EnumAccessor.configuration.start_index = 1 + +> Business.currencies +=> {"usd"=>1, "eur"=>2} +``` + ## Changelog - v2.0.0: diff --git a/lib/enum_accessor.rb b/lib/enum_accessor.rb index f7b9961..5b2d7e6 100644 --- a/lib/enum_accessor.rb +++ b/lib/enum_accessor.rb @@ -1,16 +1,28 @@ require 'enum_accessor/version' require 'enum_accessor/railtie' +require 'enum_accessor/configuration' require 'active_support' module EnumAccessor extend ActiveSupport::Concern + class << self + attr_accessor :configuration + end + + def self.configure + yield(configuration) + end + + self.configuration = EnumAccessor::Configuration.new + module ClassMethods + def enum_accessor(column, keys, options={}) # Normalize keys dict = case keys when Array - Hash[keys.map.with_index{|i,index| [i, index] }] + Hash[keys.map.with_index{|i,index| [i, (index + EnumAccessor.configuration.start_index)] }] when Hash keys else diff --git a/lib/enum_accessor/configuration.rb b/lib/enum_accessor/configuration.rb new file mode 100644 index 0000000..dc5bf22 --- /dev/null +++ b/lib/enum_accessor/configuration.rb @@ -0,0 +1,15 @@ +module EnumAccessor + class Configuration + + attr_accessor :start_index + + def initialize + @start_index = 0 + end + + def start_index=(index) + @start_index = index.to_i == 1 ? 1 : 0 + end + + end +end diff --git a/spec/enum_accessor_spec.rb b/spec/enum_accessor_spec.rb index 5255ace..322d0af 100644 --- a/spec/enum_accessor_spec.rb +++ b/spec/enum_accessor_spec.rb @@ -1,125 +1,165 @@ # encoding: UTF-8 require 'spec_helper' - ActiveRecord::Base.connection.create_table :users, force: true do |t| t.column :gender, :integer, default: 0 end -class User < ActiveRecord::Base - enum_accessor :gender, [:female, :male] -end - describe EnumAccessor do - before do - @user = User.new + + let (:create_user_class) do + class User < ActiveRecord::Base + enum_accessor :gender, [:female, :male] + end end after do User.delete_all end - it 'adds checker' do - expect(@user.gender_female?).to eq(true) - expect(@user.gender_male?).to eq(false) - end + describe 'with an invalid offset' do + before do + EnumAccessor.configuration.start_index = 2 + create_user_class + @user = User.new + end - it 'adds getter' do - expect(@user.gender).to eq('female') + describe "#configure" do + it 'resets the index offset to 0 if the request is greater than 1' do + expect(@user.genders.invert.keys.first).to eq(0) + end + end end - it 'adds setter' do - @user.gender = :male - expect(@user.gender_male?).to eq(true) + describe 'with index offset' do + before do + EnumAccessor.configuration.start_index = 1 + create_user_class + @user = User.new + end - @user.gender = nil - expect(@user.gender.nil?).to eq(true) + describe "#configure" do + it 'offsets the array index by one' do + expect(@user.genders.invert.keys.first).to eq(1) + end + end end - it 'adds raw value getter' do - expect(@user.gender_raw).to eq(0) - end + describe 'without index offset' do - it 'adds humanized methods' do - I18n.locale = :ja - expect(User.human_attribute_name(:gender)).to eq('性別') - expect(User.human_genders).to eq({ 'female' => '女', 'male' => '男' }) - expect(User.human_genders[:female]).to eq('女') - expect(@user.human_gender).to eq('女') - - I18n.locale = :en - expect(User.human_attribute_name(:gender)).to eq('Gender') - expect(User.human_genders).to eq({ 'female' => 'Female', 'male' => 'Male' }) - expect(User.human_genders[:female]).to eq('Female') - expect(@user.human_gender).to eq('Female') - end + before do + EnumAccessor.configuration.start_index = 0 + create_user_class + @user = User.new + end - it 'adds class methods' do - expect(User.genders).to eq({ 'female' => 0, 'male' => 1 }) - expect(User.genders[:female]).to eq(0) - end + describe "#configure" do + it 'starts the array with an index of 0' do + expect(@user.genders.invert.keys.first).to eq(0) + end + end + it 'adds checker' do + expect(@user.gender_female?).to eq(true) + expect(@user.gender_male?).to eq(false) + end - it 'supports manual coding' do - class UserManualCoding < ActiveRecord::Base - self.table_name = :users - enum_accessor :gender, female: 100, male: 200 + it 'adds getter' do + expect(@user.gender).to eq('female') end - user = UserManualCoding.new - user.gender = :male - expect(user.gender_male?).to eq(true) - expect(user.gender_raw).to eq(200) - end + it 'adds setter' do + @user.gender = :male + expect(@user.gender_male?).to eq(true) - it 'adds validation' do - class UserNoValidate < ActiveRecord::Base - self.table_name = :users - enum_accessor :gender, [:female, :male], validates: false - end - - class UserValidateAllowNil < ActiveRecord::Base - self.table_name = :users - enum_accessor :gender, [:female, :male], validates: { allow_nil: true } - end - - user = User.new - user.gender = 'male' - expect(user.valid?).to be_truthy - user.gender = nil - expect(user.valid?).to be_falsey - user.gender = 'bogus' # Becomes nil - expect(user.valid?).to be_falsey - - user = UserNoValidate.new - user.gender = 'male' - expect(user.valid?).to be_truthy - user.gender = nil - expect(user.valid?).to be_truthy - user.gender = 'bogus' # Becomes nil - expect(user.valid?).to be_truthy - - user = UserValidateAllowNil.new - user.gender = 'male' - expect(user.valid?).to be_truthy - user.gender = nil - expect(user.valid?).to be_truthy - user.gender = 'bogus' # Becomes nil - expect(user.valid?).to be_truthy - end + @user.gender = nil + expect(@user.gender.nil?).to eq(true) + end - it 'supports find_or_create_by' do - # `find_or_create_by` uses where-based raw value for find, - # then passes the raw value to the setter method for create. - expect { - User.find_or_create_by(gender: User.genders[:female]) - }.to change{ User.count }.by(1) - end + it 'adds raw value getter' do + expect(@user.gender_raw).to eq(0) + end + + it 'adds humanized methods' do + I18n.locale = :ja + expect(User.human_attribute_name(:gender)).to eq('性別') + expect(User.human_genders).to eq({ 'female' => '女', 'male' => '男' }) + expect(User.human_genders[:female]).to eq('女') + expect(@user.human_gender).to eq('女') + + I18n.locale = :en + expect(User.human_attribute_name(:gender)).to eq('Gender') + expect(User.human_genders).to eq({ 'female' => 'Female', 'male' => 'Male' }) + expect(User.human_genders[:female]).to eq('Female') + expect(@user.human_gender).to eq('Female') + end + + it 'adds class methods' do + expect(User.genders).to eq({ 'female' => 0, 'male' => 1 }) + expect(User.genders[:female]).to eq(0) + end - it 'supports scope' do - user = User.create!(gender: :female) + it 'supports manual coding' do + class UserManualCoding < ActiveRecord::Base + self.table_name = :users + enum_accessor :gender, female: 100, male: 200 + end + + user = UserManualCoding.new + user.gender = :male + expect(user.gender_male?).to eq(true) + expect(user.gender_raw).to eq(200) + end + + it 'adds validation' do + class UserNoValidate < ActiveRecord::Base + self.table_name = :users + enum_accessor :gender, [:female, :male], validates: false + end + + class UserValidateAllowNil < ActiveRecord::Base + self.table_name = :users + enum_accessor :gender, [:female, :male], validates: { allow_nil: true } + end + + user = User.new + user.gender = 'male' + expect(user.valid?).to be_truthy + user.gender = nil + expect(user.valid?).to be_falsey + user.gender = 'bogus' # Becomes nil + expect(user.valid?).to be_falsey + + user = UserNoValidate.new + user.gender = 'male' + expect(user.valid?).to be_truthy + user.gender = nil + expect(user.valid?).to be_truthy + user.gender = 'bogus' # Becomes nil + expect(user.valid?).to be_truthy + + user = UserValidateAllowNil.new + user.gender = 'male' + expect(user.valid?).to be_truthy + user.gender = nil + expect(user.valid?).to be_truthy + user.gender = 'bogus' # Becomes nil + expect(user.valid?).to be_truthy + end + + it 'supports find_or_create_by' do + # `find_or_create_by` uses where-based raw value for find, + # then passes the raw value to the setter method for create. + expect { + User.find_or_create_by(gender: User.genders[:female]) + }.to change{ User.count }.by(1) + end + + it 'supports scope' do + User.create!(gender: :female) + expect(User.where_gender(:female).count).to eq(1) + expect(User.where_gender(:male, :female).count).to eq(1) + expect(User.where_gender(:male).count).to eq(0) + end - expect(User.where_gender(:female).count).to eq(1) - expect(User.where_gender(:male, :female).count).to eq(1) - expect(User.where_gender(:male).count).to eq(0) end end