Skip to content

Add option to define index starting integer #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
14 changes: 13 additions & 1 deletion lib/enum_accessor.rb
Original file line number Diff line number Diff line change
@@ -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
Expand Down
15 changes: 15 additions & 0 deletions lib/enum_accessor/configuration.rb
Original file line number Diff line number Diff line change
@@ -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
228 changes: 134 additions & 94 deletions spec/enum_accessor_spec.rb
Original file line number Diff line number Diff line change
@@ -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