simple_enum 1.6.9 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -0
  3. data/LICENSE +1 -1
  4. data/README.md +248 -0
  5. data/Rakefile +4 -21
  6. data/lib/simple_enum/accessors/accessor.rb +55 -0
  7. data/lib/simple_enum/accessors/ignore_accessor.rb +11 -0
  8. data/lib/simple_enum/accessors/whiny_accessor.rb +12 -0
  9. data/lib/simple_enum/accessors.rb +18 -0
  10. data/lib/simple_enum/attribute.rb +77 -0
  11. data/lib/simple_enum/enum.rb +37 -0
  12. data/lib/simple_enum/hasher.rb +26 -0
  13. data/lib/simple_enum/mongoid.rb +11 -15
  14. data/lib/simple_enum/translation.rb +17 -0
  15. data/lib/simple_enum/version.rb +2 -2
  16. data/lib/simple_enum.rb +19 -276
  17. data/simple_enum.gemspec +9 -9
  18. data/spec/simple_enum/accessors_spec.rb +212 -0
  19. data/spec/simple_enum/attribute_spec.rb +208 -0
  20. data/spec/simple_enum/enum_spec.rb +96 -0
  21. data/spec/simple_enum/hasher_spec.rb +63 -0
  22. data/spec/simple_enum/mongoid_spec.rb +44 -0
  23. data/spec/simple_enum/translation_spec.rb +66 -0
  24. data/spec/spec_helper.rb +27 -0
  25. data/spec/support/active_record_support.rb +23 -0
  26. data/spec/support/i18n_support.rb +12 -0
  27. data/spec/support/model_support.rb +47 -0
  28. data/spec/support/mongoid_support.rb +21 -0
  29. metadata +50 -56
  30. data/README.rdoc +0 -293
  31. data/lib/simple_enum/enum_hash.rb +0 -64
  32. data/lib/simple_enum/validation.rb +0 -58
  33. data/locales/en.yml +0 -10
  34. data/test/array_conversions_test.rb +0 -21
  35. data/test/class_methods_test.rb +0 -114
  36. data/test/dirty_attributes_test.rb +0 -37
  37. data/test/enum_hash_test.rb +0 -73
  38. data/test/finders_test.rb +0 -45
  39. data/test/locales.yml +0 -25
  40. data/test/mongoid_test.rb +0 -66
  41. data/test/object_backed_test.rb +0 -61
  42. data/test/orm/active_record.rb +0 -114
  43. data/test/orm/common.rb +0 -23
  44. data/test/orm/mongoid.rb +0 -114
  45. data/test/poro_test.rb +0 -20
  46. data/test/prefixes_test.rb +0 -36
  47. data/test/simple_enum_test.rb +0 -314
  48. data/test/test_helper.rb +0 -40
  49. data/test/without_shortcuts_test.rb +0 -39
@@ -0,0 +1,208 @@
1
+ require 'spec_helper'
2
+
3
+ describe SimpleEnum::Attribute do
4
+ fake_model(:klass) { as_enum :gender, %w{male female}, with: [] }
5
+ let(:accessor) { subject.class.genders_accessor }
6
+
7
+ context '.as_enum' do
8
+ it 'returns a SimpleEnum::Enum' do
9
+ expect(klass.as_enum(:gender, %w{male female})).to be_a(SimpleEnum::Enum)
10
+ end
11
+ end
12
+
13
+ context 'generate_enum_class_accessors_for' do
14
+ context '.genders' do
15
+ subject { klass.genders }
16
+
17
+ it 'returns a SimpleEnum::Enum' do
18
+ expect(subject).to be_a(SimpleEnum::Enum)
19
+ end
20
+ end
21
+
22
+ context '.genders_accessor' do
23
+ subject { klass.genders_accessor }
24
+
25
+ it 'returns a SimpleEnum::Accessor' do
26
+ expect(subject).to be_a(SimpleEnum::Accessors::Accessor)
27
+ end
28
+ end
29
+ end
30
+
31
+ context 'generate_enum_instance_accessors_for' do
32
+ subject { klass.new(1) }
33
+
34
+ context '#gender' do
35
+ it 'delegates to accessor' do
36
+ expect(accessor).to receive(:read).with(subject) { :female }
37
+ expect(subject.gender).to eq :female
38
+ end
39
+ end
40
+
41
+ context '#gender=' do
42
+ it 'delegates to accessor' do
43
+ expect(accessor).to receive(:write).with(subject, :male) { 0 }
44
+ subject.gender = :male
45
+ end
46
+ end
47
+ end
48
+
49
+ context 'generate_enum_dirty_methods_for' do
50
+ subject { klass.new }
51
+
52
+ it 'does not respond to #gender_changed?' do
53
+ expect(subject).to_not respond_to(:gender_changed?)
54
+ end
55
+
56
+ it 'does not responds to #gender_was' do
57
+ expect(subject).to_not respond_to(:gender_was)
58
+ end
59
+
60
+ context 'with: :dirty' do
61
+ fake_model(:klass_with_dirty) { as_enum :gender, %w{male female}, with: [:dirty] }
62
+ subject { klass_with_dirty.new }
63
+
64
+ it 'delegates #gender_changed? to accessor' do
65
+ expect(accessor).to receive(:changed?).with(subject) { true }
66
+ expect(subject.gender_changed?).to be_true
67
+ end
68
+
69
+ it 'delegates #gender_was to accesso' do
70
+ expect(accessor).to receive(:was).with(subject) { :female }
71
+ expect(subject.gender_was).to eq :female
72
+ end
73
+ end
74
+ end
75
+
76
+ context 'generate_enum_attribute_methods_for' do
77
+ subject { klass.new }
78
+
79
+ it 'does not respond to #gender?' do
80
+ expect(subject).to_not respond_to(:gender?)
81
+ end
82
+
83
+ it 'does not respond to #male? or #female?' do
84
+ expect(subject).to_not respond_to(:male?)
85
+ expect(subject).to_not respond_to(:female?)
86
+ end
87
+
88
+ it 'does not respond to #male! or #female!' do
89
+ expect(subject).to_not respond_to(:male!)
90
+ expect(subject).to_not respond_to(:female!)
91
+ end
92
+
93
+ context 'with: :attribute' do
94
+ fake_model(:klass_with_attributes) { as_enum :gender, %w{male female}, with: [:attribute] }
95
+ subject { klass_with_attributes.new }
96
+
97
+ it 'delegates #gender? to accessor' do
98
+ expect(accessor).to receive(:selected?).with(subject, nil) { :female }
99
+ expect(subject.gender?).to be_true
100
+ end
101
+
102
+ it 'delegates #male? to accessor' do
103
+ expect(accessor).to receive(:selected?).with(subject, 'male') { true }
104
+ expect(subject.male?).to be_true
105
+ end
106
+
107
+ it 'delegates #female? to accessor' do
108
+ expect(accessor).to receive(:selected?).with(subject, 'female') { false }
109
+ expect(subject.female?).to be_false
110
+ end
111
+
112
+ it 'delegates #male! to accessor' do
113
+ expect(accessor).to receive(:write).with(subject, 'male') { 0 }
114
+ expect(subject.male!).to eq 0
115
+ end
116
+
117
+ it 'delegates #female! to accessor' do
118
+ expect(accessor).to receive(:write).with(subject, 'female') { 1 }
119
+ expect(subject.female!).to eq 1
120
+ end
121
+ end
122
+
123
+ context 'with a prefix' do
124
+ fake_model(:klass_with_prefix) { as_enum :gender, %w{male female}, with: [:attribute], prefix: true }
125
+ subject { klass_with_prefix.new }
126
+
127
+ it 'delegates #gender? to accessor' do
128
+ expect(accessor).to receive(:selected?).with(subject, nil) { :female }
129
+ expect(subject.gender?).to be_true
130
+ end
131
+
132
+ it 'delegates #gender_male? to accessor' do
133
+ expect(accessor).to receive(:selected?).with(subject, 'male') { true }
134
+ expect(subject.gender_male?).to be_true
135
+ end
136
+
137
+ it 'delegates #gender_female? to accessor' do
138
+ expect(accessor).to receive(:selected?).with(subject, 'female') { false }
139
+ expect(subject.gender_female?).to be_false
140
+ end
141
+
142
+ it 'delegates #gender_male! to accessor' do
143
+ expect(accessor).to receive(:write).with(subject, 'male') { 0 }
144
+ expect(subject.gender_male!).to eq 0
145
+ end
146
+
147
+ it 'delegates #gender_female! to accessor' do
148
+ expect(accessor).to receive(:write).with(subject, 'female') { 1 }
149
+ expect(subject.gender_female!).to eq 1
150
+ end
151
+ end
152
+ end
153
+
154
+ context 'generate_enum_scope_methods_for', active_record: true do
155
+ fake_active_record(:klass) {
156
+ as_enum :gender, [:male, :female], with: [:scope]
157
+ }
158
+
159
+ shared_examples_for 'returning a relation' do |value|
160
+ it 'returns an ActiveRecord::Relation' do
161
+ expect(subject).to be_a(ActiveRecord::Relation)
162
+ end
163
+
164
+ it "queries for gender_cd = #{value}" do
165
+ values_hash = { "gender_cd" => value }
166
+ expect(subject.where_values_hash).to eq values_hash
167
+ end
168
+ end
169
+
170
+ context '.male' do
171
+ subject { klass.male }
172
+ it_behaves_like 'returning a relation', 0
173
+ end
174
+
175
+ context '.female' do
176
+ subject { klass.female }
177
+ it_behaves_like 'returning a relation', 1
178
+ end
179
+
180
+ context 'with prefix' do
181
+ fake_active_record(:klass) {
182
+ as_enum :gender, [:male, :female], with: [:scope], prefix: true
183
+ }
184
+
185
+ context '.gender_male' do
186
+ subject { klass.gender_male }
187
+ it_behaves_like 'returning a relation', 0
188
+ end
189
+
190
+ context '.gender_female' do
191
+ subject { klass.gender_female }
192
+ it_behaves_like 'returning a relation', 1
193
+ end
194
+ end
195
+
196
+ context 'without scope method' do
197
+ fake_model(:klass_without_scope_method) {
198
+ as_enum :gender, [:male, :female], with: [:scope]
199
+ }
200
+ subject { klass_without_scope_method }
201
+
202
+ it 'does not add .male nor .female' do
203
+ expect(subject).to_not respond_to(:male)
204
+ expect(subject).to_not respond_to(:female)
205
+ end
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+
3
+ describe SimpleEnum::Enum do
4
+ let(:hash) do
5
+ { "male" => 0, "female" => 1 }
6
+ end
7
+
8
+ fake_model(:klass)
9
+ let(:object) { klass.new }
10
+
11
+ subject { described_class.new(:gender, hash) }
12
+
13
+ context '#name' do
14
+ it 'returns the enum name as string' do
15
+ expect(subject.name).to eq 'gender'
16
+ end
17
+ end
18
+
19
+ context '#to_s' do
20
+ it 'returns the name' do
21
+ expect(subject.to_s).to eq 'gender'
22
+ end
23
+ end
24
+
25
+ context '#hash' do
26
+ subject { described_class.new(:gender, hash).hash }
27
+
28
+ it 'returns hash that was set in the constructor' do
29
+ expect(subject).to be_a(Hash)
30
+ expect(subject.keys).to eq %w{male female}
31
+ expect(subject.values).to eq [0, 1]
32
+ end
33
+ end
34
+
35
+ context '#each_pair (aliased to #each)' do
36
+ it 'yields twice with #each_pair' do
37
+ expect { |b| subject.each_pair(&b) }.to yield_control.exactly(2).times
38
+ end
39
+
40
+ it 'yields twice with #each' do
41
+ expect { |b| subject.each(&b) }.to yield_control.exactly(2).times
42
+ end
43
+ end
44
+
45
+ context '#value (aliased to #[])' do
46
+ it 'looks up by string' do
47
+ expect(subject.value('male')).to eq 0
48
+ expect(subject['male']).to eq 0
49
+ end
50
+
51
+ it 'looks up by symbol' do
52
+ expect(subject.value(:female)).to eq 1
53
+ expect(subject[:female]).to eq 1
54
+ end
55
+
56
+ it 'looks up by value' do
57
+ expect(subject.value(0)).to be 0
58
+ expect(subject[0]).to be 0
59
+ end
60
+
61
+ it 'returns nil when key is not found' do
62
+ expect(subject.value(:inexistent)).to be_nil
63
+ expect(subject[:inexistent]).to be_nil
64
+ end
65
+ end
66
+
67
+ context '#key' do
68
+ it 'returns symbolized key for supplied value' do
69
+ expect(subject.key(0)).to eq :male
70
+ expect(subject.key(1)).to eq :female
71
+ end
72
+
73
+ it 'returns nil if value is not found' do
74
+ expect(subject.key(12)).to be_nil
75
+ end
76
+ end
77
+
78
+ context '#include?' do
79
+ it 'returns true by string' do
80
+ expect(subject.include?('male')).to be_true
81
+ end
82
+
83
+ it 'returns true by symbol' do
84
+ expect(subject.include?(:female)).to be_true
85
+ end
86
+
87
+ it 'returns true by checking actual value' do
88
+ expect(subject.include?(1)).to be_true
89
+ end
90
+
91
+ it 'returns false when neither in keys nor values' do
92
+ expect(subject.include?(:other)).to be_false
93
+ expect(subject.include?(2)).to be_false
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+ require 'simple_enum/hasher'
3
+
4
+ describe SimpleEnum::Hasher do
5
+ subject { described_class }
6
+
7
+ context '.map' do
8
+ subject { described_class.map(%w{male female}, map: :string) }
9
+
10
+ it 'uses DefaultHasher by default' do
11
+ result = { "male" => 0, "female" => 1 }
12
+ expect(described_class.map(%w{male female})).to eq result
13
+ end
14
+
15
+ it 'returns a frozen Hash' do
16
+ expect(subject).to be_a(Hash)
17
+ expect(subject).to be_frozen
18
+ end
19
+
20
+ it 'uses the builder supplied if available' do
21
+ result = { "male" => "male", "female" => "female" }
22
+ expect(subject).to eq result
23
+ end
24
+
25
+ it 'accepts a Proc as well' do
26
+ proc = ->(hash) { { "static" => 1 } }
27
+ result = { "static" => 1 }
28
+ expect(described_class.map(%w{male female}, map: proc) ).to eq result
29
+ end
30
+ end
31
+
32
+ context 'DefaultHasher.call' do
33
+ let(:result) do; { "male" => 0, "female" => 1 } end
34
+
35
+ it 'returns string => index for Array of strings' do
36
+ expect(subject::DefaultHasher.call(%w{male female})).to eq result
37
+ end
38
+
39
+ it 'returns string => index for Array of symbols' do
40
+ expect(subject::DefaultHasher.call([:male, :female])).to eq result
41
+ end
42
+
43
+ it 'returns string => number for Hash with symbolized keys' do
44
+ expect(subject::DefaultHasher.call(male: 0, female: 1)).to eq result
45
+ end
46
+
47
+ it 'returns string => number for hash with string keys' do
48
+ expect(subject::DefaultHasher.call('male' => 0, 'female' => 1)).to eq result
49
+ end
50
+ end
51
+
52
+ context 'StringHasher.call' do
53
+ let(:result) do; { "male" => "male", "female" => "female" } end
54
+
55
+ it 'retuns string => string for Array of strings' do
56
+ expect(subject::StringHasher.call(%w{male female})).to eq result
57
+ end
58
+
59
+ it 'returns string => string for Array of symbols' do
60
+ expect(subject::StringHasher.call([:male, :female])).to eq result
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+ require 'simple_enum/mongoid'
3
+
4
+ describe SimpleEnum::Mongoid, mongoid: true do
5
+ fake_mongoid_model(:klass) {
6
+ as_enum :gender, %w{male female}
7
+ }
8
+
9
+ let(:field) { klass.fields['gender_cd'] }
10
+
11
+ context '.as_enum' do
12
+ subject { klass }
13
+
14
+ it 'has the genders enum' do
15
+ expect(klass.genders).to be_a(SimpleEnum::Enum)
16
+ end
17
+
18
+ it 'creates the :gender_cd field' do
19
+ expect(field).to_not be_nil
20
+ expect(field.type).to eq Object
21
+ end
22
+
23
+ context 'field: { type: Integer }' do
24
+ fake_mongoid_model(:klass) {
25
+ as_enum :gender, %w{male female}, field: { type: Integer }
26
+ }
27
+
28
+ it 'creates the :gender_cd field as Integer' do
29
+ expect(field).to_not be_nil
30
+ expect(field.type).to eq Integer
31
+ end
32
+ end
33
+
34
+ context 'field: false' do
35
+ fake_mongoid_model(:klass) {
36
+ as_enum :gender, %w{male female}, field: false
37
+ }
38
+
39
+ it 'does not create the field' do
40
+ expect(field).to be_nil
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ describe SimpleEnum::Translation do
4
+ context '.human_enum_name', i18n: true do
5
+ fake_model(:klass) { extend SimpleEnum::Translation }
6
+ subject { klass }
7
+
8
+ shared_examples_for 'translating gender' do
9
+ it 'translates :male to "Mr."' do
10
+ expect(subject.human_enum_name(:gender, :male)).to eq 'Mr.'
11
+ end
12
+
13
+ it 'translates :female to "Mrs."' do
14
+ expect(subject.human_enum_name(:gender, :female)).to eq 'Mrs.'
15
+ end
16
+ end
17
+
18
+ context '{i18n_scope}.enums.{i18n_key}.gender.{key}' do
19
+ before do
20
+ store_translations :en, 'activemodel' => {
21
+ 'enums' => {
22
+ 'fake_model' => {
23
+ 'gender' => { 'male' => 'Mr.', 'female' => 'Mrs.' }
24
+ }
25
+ }
26
+ }
27
+ end
28
+
29
+ it_behaves_like 'translating gender'
30
+ end
31
+
32
+ context 'enums.{i18n_key}.gender.{key}' do
33
+ before do
34
+ store_translations :en, 'enums' => {
35
+ 'fake_model' => {
36
+ 'gender' => { 'male' => 'Mr.', 'female' => 'Mrs.' }
37
+ }
38
+ }
39
+ end
40
+
41
+ it_behaves_like 'translating gender'
42
+ end
43
+
44
+ context 'enums.gender.{key}' do
45
+ before do
46
+ store_translations :en, 'enums' => {
47
+ 'gender' => { 'male' => 'Mr.', 'female' => 'Mrs.' }
48
+ }
49
+ end
50
+
51
+ it_behaves_like 'translating gender'
52
+ end
53
+
54
+ context 'uses :default if available' do
55
+ it 'translates :female to "Frau" using default:' do
56
+ expect(subject.human_enum_name(:gender, :female, default: 'Frau')).to eq 'Frau'
57
+ end
58
+ end
59
+
60
+ context 'falls back to titleize' do
61
+ it 'translates using .titleize if no translations found' do
62
+ expect(subject.human_enum_name(:gender, :female)).to eq 'Female'
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,27 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'rspec'
5
+ require 'active_record'
6
+ require 'mongoid'
7
+
8
+ if ENV['CODECLIMATE_REPO_TOKEN']
9
+ require "codeclimate-test-reporter"
10
+ CodeClimate::TestReporter.start
11
+ end
12
+
13
+ require 'simple_enum'
14
+
15
+ require 'support/active_record_support'
16
+ require 'support/i18n_support'
17
+ require 'support/model_support'
18
+ require 'support/mongoid_support'
19
+
20
+ I18n.enforce_available_locales = false
21
+
22
+ RSpec.configure do |config|
23
+ config.include ModelSupport
24
+ config.include I18nSupport, i18n: true
25
+ config.include ActiveRecordSupport, active_record: true
26
+ config.include MongoidSupport, mongoid: true
27
+ end
@@ -0,0 +1,23 @@
1
+ module ActiveRecordSupport
2
+ def self.connection
3
+ @connection_pool ||= ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:'
4
+ ActiveRecord::Base.connection
5
+ end
6
+
7
+ def self.included(base)
8
+ base.before(:each) { self.reset_active_record }
9
+ end
10
+
11
+ def reset_active_record
12
+ ActiveRecordSupport.connection.create_table :dummies, :force => true do |t|
13
+ t.column :name, :string
14
+ t.column :gender_cd, :integer
15
+ t.column :word_cd, :string, :limit => 5
16
+ t.column :role_cd, :string
17
+ t.column :other, :integer
18
+ t.column :numeric_cd, :string
19
+ t.column :nilish_cd, :string
20
+ t.column :style_cd, :integer
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,12 @@
1
+ module I18nSupport
2
+ def self.included(base)
3
+ base.let!(:i18n_previous_backend) { I18n.backend }
4
+ base.let(:i18n_backend) { I18n::Backend::KeyValue.new({}) }
5
+ base.before { I18n.backend = i18n_backend }
6
+ base.after { I18n.backend = i18n_previous_backend }
7
+ end
8
+
9
+ def store_translations(lang, translations)
10
+ i18n_backend.store_translations lang, translations
11
+ end
12
+ end
@@ -0,0 +1,47 @@
1
+ require 'active_record'
2
+ require 'mongoid'
3
+
4
+ module ModelSupport
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ end
8
+
9
+ module ClassMethods
10
+
11
+ def fake_active_record(name, &block)
12
+ let(name) {
13
+ Class.new(ActiveRecord::Base) do
14
+ self.table_name = 'dummies'
15
+ instance_eval &block
16
+ end
17
+ }
18
+ end
19
+
20
+ def fake_mongoid_model(name, &block)
21
+ let(name) {
22
+ Class.new do
23
+ include Mongoid::Document
24
+ include SimpleEnum::Mongoid
25
+
26
+ store_in collection: 'dummies'
27
+ instance_eval &block
28
+ end
29
+ }
30
+ end
31
+
32
+ def fake_model(name, *fields, &block)
33
+ fields << :gender_cd
34
+ let(name) {
35
+ Struct.new(*fields) do
36
+ extend ActiveModel::Translation
37
+ extend SimpleEnum::Attribute
38
+ instance_eval &block if block_given?
39
+
40
+ def self.model_name
41
+ @model_name ||= ActiveModel::Name.new(self, nil, "FakeModel")
42
+ end
43
+ end
44
+ }
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,21 @@
1
+ require 'mongoid'
2
+
3
+ module MongoidSupport
4
+ def self.connection
5
+ @connection ||= begin
6
+ Mongoid.configure.connect_to("simple_enum_mongoid_test")
7
+ Mongoid.default_session.options[:max_retries] = 0
8
+ end
9
+ Mongoid.default_session
10
+ end
11
+
12
+ def self.included(base)
13
+ base.before {
14
+ begin
15
+ MongoidSupport.connection.collection_names
16
+ rescue Moped::Errors::ConnectionFailure
17
+ pending "Start MongoDB server to run Mongoid integration tests..."
18
+ end
19
+ }
20
+ end
21
+ end