classy_enum 2.3.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/CHANGELOG.md +12 -0
- data/README.md +22 -58
- data/classy_enum.gemspec +1 -1
- data/gemfiles/Gemfile.rails-3.0.x +2 -4
- data/gemfiles/Gemfile.rails-3.1.x +2 -4
- data/gemfiles/Gemfile.rails-3.2.x +2 -4
- data/lib/classy_enum/active_record.rb +58 -0
- data/lib/classy_enum/base.rb +83 -3
- data/lib/classy_enum/collection.rb +76 -0
- data/lib/classy_enum/conversion.rb +69 -0
- data/lib/classy_enum/predicate.rb +35 -0
- data/lib/classy_enum/version.rb +1 -1
- data/lib/classy_enum.rb +5 -8
- data/lib/generators/classy_enum/templates/enum.rb +0 -1
- data/spec/classy_enum/active_record_spec.rb +156 -0
- data/spec/classy_enum/base_spec.rb +50 -0
- data/spec/classy_enum/collection_spec.rb +32 -0
- data/spec/classy_enum/conversion_spec.rb +55 -0
- data/spec/classy_enum/predicate_spec.rb +19 -0
- data/spec/classy_enum_inheritance_spec.rb +28 -0
- data/spec/spec_helper.rb +0 -29
- metadata +21 -16
- data/lib/classy_enum/attributes.rb +0 -72
- data/lib/classy_enum/class_methods.rb +0 -141
- data/lib/classy_enum/instance_methods.rb +0 -122
- data/spec/active_record_spec.rb +0 -70
- data/spec/classy_enum_attributes_spec.rb +0 -97
- data/spec/classy_enum_owner_reference_spec.rb +0 -53
- data/spec/classy_enum_spec.rb +0 -105
@@ -0,0 +1,156 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
class Breed < ClassyEnum::Base; end
|
4
|
+
class Breed::GoldenRetriever < Breed; end
|
5
|
+
class Breed::Snoop < Breed; end
|
6
|
+
class Breed::Husky < Breed; end
|
7
|
+
|
8
|
+
class Color < ClassyEnum::Base; end
|
9
|
+
class Color::White < Color; end;
|
10
|
+
class Color::Black < Color; end;
|
11
|
+
|
12
|
+
class CatBreed < ClassyEnum::Base
|
13
|
+
owner :cat
|
14
|
+
|
15
|
+
def breed_color
|
16
|
+
"#{cat.color} #{self}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class CatBreed::Abyssian < CatBreed; end
|
21
|
+
class CatBreed::Bengal < CatBreed; end
|
22
|
+
class CatBreed::Birman < CatBreed; end
|
23
|
+
class CatBreed::Persian < CatBreed; end
|
24
|
+
|
25
|
+
class Dog < ActiveRecord::Base
|
26
|
+
classy_enum_attr :breed
|
27
|
+
end
|
28
|
+
|
29
|
+
class AllowBlankBreedDog < ActiveRecord::Base
|
30
|
+
classy_enum_attr :breed, :allow_blank => true
|
31
|
+
end
|
32
|
+
|
33
|
+
class AllowNilBreedDog < ActiveRecord::Base
|
34
|
+
classy_enum_attr :breed, :allow_nil => true
|
35
|
+
end
|
36
|
+
|
37
|
+
class OtherDog < ActiveRecord::Base
|
38
|
+
classy_enum_attr :other_breed, :enum => 'Breed'
|
39
|
+
end
|
40
|
+
|
41
|
+
describe Dog do
|
42
|
+
specify { Dog.new(:breed => nil).should_not be_valid }
|
43
|
+
specify { Dog.new(:breed => '').should_not be_valid }
|
44
|
+
|
45
|
+
context "with valid breed options" do
|
46
|
+
subject { Dog.new(:breed => :golden_retriever) }
|
47
|
+
it { should be_valid }
|
48
|
+
its(:breed) { should be_a(Breed::GoldenRetriever) }
|
49
|
+
its('breed.allow_blank') { should be_false }
|
50
|
+
end
|
51
|
+
|
52
|
+
context "with invalid breed options" do
|
53
|
+
subject { Dog.new(:breed => :fake_breed) }
|
54
|
+
it { should_not be_valid }
|
55
|
+
it { should have(1).error_on(:breed) }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "A ClassyEnum that allows blanks" do
|
60
|
+
specify { AllowBlankBreedDog.new(:breed => nil).should be_valid }
|
61
|
+
specify { AllowBlankBreedDog.new(:breed => '').should be_valid }
|
62
|
+
|
63
|
+
context "with valid breed options" do
|
64
|
+
subject { AllowBlankBreedDog.new(:breed => :golden_retriever) }
|
65
|
+
it { should be_valid }
|
66
|
+
its('breed.allow_blank') { should be_true }
|
67
|
+
end
|
68
|
+
|
69
|
+
context "with invalid breed options" do
|
70
|
+
subject { AllowBlankBreedDog.new(:breed => :fake_breed) }
|
71
|
+
it { should_not be_valid }
|
72
|
+
it { should have(1).error_on(:breed) }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "A ClassyEnum that allows nils" do
|
77
|
+
specify { AllowNilBreedDog.new(:breed => nil).should be_valid }
|
78
|
+
specify { AllowNilBreedDog.new(:breed => '').should_not be_valid }
|
79
|
+
|
80
|
+
context "with valid breed options" do
|
81
|
+
subject { AllowNilBreedDog.new(:breed => :golden_retriever) }
|
82
|
+
it { should be_valid }
|
83
|
+
its('breed.allow_blank') { should be_true }
|
84
|
+
end
|
85
|
+
|
86
|
+
context "with invalid breed options" do
|
87
|
+
subject { AllowNilBreedDog.new(:breed => :fake_breed) }
|
88
|
+
it { should_not be_valid }
|
89
|
+
it { should have(1).error_on(:breed) }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "A ClassyEnum that has a different field name than the enum" do
|
94
|
+
subject { OtherDog.new(:other_breed => :snoop) }
|
95
|
+
its(:other_breed) { should be_a(Breed::Snoop) }
|
96
|
+
end
|
97
|
+
|
98
|
+
class ActiveDog < ActiveRecord::Base
|
99
|
+
classy_enum_attr :color
|
100
|
+
validates_uniqueness_of :name, :scope => :color
|
101
|
+
scope :goldens, where(:breed => 'golden_retriever')
|
102
|
+
end
|
103
|
+
|
104
|
+
describe ActiveDog do
|
105
|
+
context 'uniqueness on name' do
|
106
|
+
subject { ActiveDog.new(:name => 'Kitteh', :breed => :golden_retriever, :color => :black) }
|
107
|
+
it { should be_valid }
|
108
|
+
|
109
|
+
context 'with existing kitteh' do
|
110
|
+
before do
|
111
|
+
ActiveDog.create!(:name => 'Kitteh', :breed => :husky, :color => :black)
|
112
|
+
end
|
113
|
+
|
114
|
+
it { should have(1).error_on(:name) }
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context 'scopes' do
|
119
|
+
let!(:golden) { ActiveDog.create!(:name => 'Sebastian', :breed => :golden_retriever, :color => :white) }
|
120
|
+
let!(:husky) { ActiveDog.create!(:name => 'Sirius', :breed => :husky, :color => :black) }
|
121
|
+
|
122
|
+
after { ActiveDog.destroy_all }
|
123
|
+
|
124
|
+
it 'should know all dogs' do
|
125
|
+
ActiveDog.all.should include(golden, husky)
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'should have a working scope' do
|
129
|
+
ActiveDog.goldens.should include(golden)
|
130
|
+
ActiveDog.goldens.should_not include(husky)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
class Cat < ActiveRecord::Base
|
137
|
+
classy_enum_attr :breed, :enum => 'CatBreed'
|
138
|
+
attr_accessor :color
|
139
|
+
delegate :breed_color, :to => :breed
|
140
|
+
end
|
141
|
+
|
142
|
+
class OtherCat < ActiveRecord::Base
|
143
|
+
classy_enum_attr :breed, :enum => 'CatBreed', :serialize_as_json => true
|
144
|
+
attr_accessor :color
|
145
|
+
delegate :breed_color, :to => :breed
|
146
|
+
end
|
147
|
+
|
148
|
+
describe Cat do
|
149
|
+
let(:abyssian) { Cat.new(:breed => :abyssian, :color => 'black') }
|
150
|
+
let(:persian) { OtherCat.new(:breed => :persian, :color => 'white') }
|
151
|
+
|
152
|
+
it 'should delegate breed color to breed with an ownership reference' do
|
153
|
+
abyssian.breed_color { should eql('black Abyssian') }
|
154
|
+
persian.breed_color { should eql('white Persian') }
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
class ClassyEnumBase < ClassyEnum::Base
|
4
|
+
end
|
5
|
+
|
6
|
+
class ClassyEnumBase::One < ClassyEnumBase
|
7
|
+
end
|
8
|
+
|
9
|
+
class ClassyEnumBase::Two < ClassyEnumBase
|
10
|
+
end
|
11
|
+
|
12
|
+
describe ClassyEnum::Base do
|
13
|
+
context '.build' do
|
14
|
+
context 'invalid option' do
|
15
|
+
it 'should return the option' do
|
16
|
+
ClassyEnumBase.build(:invalid_option).should == :invalid_option
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'string option' do
|
21
|
+
subject { ClassyEnumBase.build("one") }
|
22
|
+
it { should be_a(ClassyEnumBase::One) }
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'symbol option' do
|
26
|
+
subject { ClassyEnumBase.build(:two) }
|
27
|
+
it { should be_a(ClassyEnumBase::Two) }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context '#new' do
|
32
|
+
subject { ClassyEnumBase::One }
|
33
|
+
its(:new) { should be_a(ClassyEnumBase::One) }
|
34
|
+
its(:new) { should == ClassyEnumBase::One.new }
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'Subclass naming' do
|
38
|
+
it 'should raise an error when invalid' do
|
39
|
+
lambda {
|
40
|
+
class WrongSublcassName < ClassyEnumBase; end
|
41
|
+
}.should raise_error(ClassyEnum::SubclassNameError)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe ClassyEnum::Base, 'Arel visitor' do
|
47
|
+
specify do
|
48
|
+
Arel::Visitors::ToSql.instance_methods.map(&:to_sym).should include(:'visit_ClassyEnumBase_One', :'visit_ClassyEnumBase_Two')
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
class ClassyEnumCollection < ClassyEnum::Base
|
4
|
+
end
|
5
|
+
|
6
|
+
class ClassyEnumCollection::One < ClassyEnumCollection
|
7
|
+
end
|
8
|
+
|
9
|
+
class ClassyEnumCollection::Two < ClassyEnumCollection
|
10
|
+
end
|
11
|
+
|
12
|
+
class ClassyEnumCollection::Three < ClassyEnumCollection
|
13
|
+
end
|
14
|
+
|
15
|
+
describe ClassyEnum::Collection do
|
16
|
+
subject { ClassyEnumCollection }
|
17
|
+
|
18
|
+
its(:enum_options) { should == [ClassyEnumCollection::One, ClassyEnumCollection::Two, ClassyEnumCollection::Three] }
|
19
|
+
its(:all) { should == [ClassyEnumCollection::One.new, ClassyEnumCollection::Two.new, ClassyEnumCollection::Three.new] }
|
20
|
+
its(:select_options) { should == [['One', 'one'],['Two', 'two'], ['Three', 'three']] }
|
21
|
+
end
|
22
|
+
|
23
|
+
describe ClassyEnum::Collection, Comparable do
|
24
|
+
let(:one) { ClassyEnumCollection::One.new }
|
25
|
+
let(:two) { ClassyEnumCollection::Two.new }
|
26
|
+
let(:three) { ClassyEnumCollection::Three.new }
|
27
|
+
|
28
|
+
subject { [one, three, two] }
|
29
|
+
its(:sort) { should eql([one, two, three]) }
|
30
|
+
its(:max) { should eql(three) }
|
31
|
+
its(:min) { should eql(one) }
|
32
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
class ClassyEnumConversion < ClassyEnum::Base
|
4
|
+
end
|
5
|
+
|
6
|
+
class ClassyEnumConversion::One < ClassyEnumConversion
|
7
|
+
end
|
8
|
+
|
9
|
+
class ClassyEnumConversion::Two < ClassyEnumConversion
|
10
|
+
end
|
11
|
+
|
12
|
+
describe ClassyEnum::Conversion do
|
13
|
+
context '#to_i' do
|
14
|
+
specify { ClassyEnumConversion::One.new.to_i.should == 1 }
|
15
|
+
specify { ClassyEnumConversion::Two.new.to_i.should == 2 }
|
16
|
+
end
|
17
|
+
|
18
|
+
context '#index' do
|
19
|
+
specify { ClassyEnumConversion::One.new.index.should == 1 }
|
20
|
+
specify { ClassyEnumConversion::Two.new.index.should == 2 }
|
21
|
+
end
|
22
|
+
|
23
|
+
context '#to_s' do
|
24
|
+
specify { ClassyEnumConversion::One.new.to_s.should == 'one' }
|
25
|
+
specify { ClassyEnumConversion::Two.new.to_s.should == 'two' }
|
26
|
+
end
|
27
|
+
|
28
|
+
context '#to_sym' do
|
29
|
+
specify { ClassyEnumConversion::One.new.to_sym.should == :one }
|
30
|
+
specify { ClassyEnumConversion::Two.new.to_sym.should == :two }
|
31
|
+
end
|
32
|
+
|
33
|
+
context '#as_json' do
|
34
|
+
context 'serialize_as_json is false' do
|
35
|
+
specify { ClassyEnumConversion::One.new.as_json.should == 'one' }
|
36
|
+
specify { ClassyEnumConversion::Two.new.as_json.should == 'two' }
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'serialize_as_json is true' do
|
40
|
+
specify do
|
41
|
+
enum = ClassyEnumConversion::One.new
|
42
|
+
enum.serialize_as_json = true
|
43
|
+
enum.instance_variable_set('@key', 'value')
|
44
|
+
enum.as_json.should == {'key' => 'value' }
|
45
|
+
end
|
46
|
+
|
47
|
+
specify do
|
48
|
+
enum = ClassyEnumConversion::One.new
|
49
|
+
enum.serialize_as_json = true
|
50
|
+
enum.instance_variable_set('@key', 'value')
|
51
|
+
enum.as_json.should == {'key' => 'value' }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
class ClassyEnumPredicate < ClassyEnum::Base
|
4
|
+
end
|
5
|
+
|
6
|
+
class ClassyEnumPredicate::One < ClassyEnumPredicate
|
7
|
+
end
|
8
|
+
|
9
|
+
class ClassyEnumPredicate::Two < ClassyEnumPredicate
|
10
|
+
end
|
11
|
+
|
12
|
+
describe ClassyEnum::Predicate do
|
13
|
+
context '#attribute?' do
|
14
|
+
specify { ClassyEnumPredicate::One.new.should be_one }
|
15
|
+
specify { ClassyEnumPredicate::One.new.should_not be_two }
|
16
|
+
specify { ClassyEnumPredicate::Two.new.should_not be_one }
|
17
|
+
specify { ClassyEnumPredicate::Two.new.should be_two }
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
class ProjectTier < ClassyEnum::Base
|
4
|
+
class_attribute :inherited_properties
|
5
|
+
end
|
6
|
+
|
7
|
+
class ProjectTier::One < ProjectTier
|
8
|
+
self.inherited_properties = [1,2,3]
|
9
|
+
end
|
10
|
+
|
11
|
+
class ProjectTier::Two < ProjectTier::One
|
12
|
+
self.inherited_properties += [4,5,6]
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'Classy Enum inheritance' do
|
16
|
+
it 'should inherit from the previous class' do
|
17
|
+
ProjectTier::One.inherited_properties.should == [1,2,3]
|
18
|
+
ProjectTier::Two.inherited_properties.should == [1,2,3,4,5,6]
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should instantiate the subclass' do
|
22
|
+
ProjectTier::Two.build(:two).should == ProjectTier::Two.new
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should have the right index' do
|
26
|
+
ProjectTier::Two.new.index.should == 2
|
27
|
+
end
|
28
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -46,32 +46,3 @@ ActiveRecord::Schema.define(:version => 1) do
|
|
46
46
|
t.string :breed
|
47
47
|
end
|
48
48
|
end
|
49
|
-
|
50
|
-
class Breed < ClassyEnum::Base
|
51
|
-
enum_classes :golden_retriever, :snoop, :husky
|
52
|
-
end
|
53
|
-
|
54
|
-
class BreedGoldenRetriever < Breed
|
55
|
-
end
|
56
|
-
|
57
|
-
class BreedSnoop < Breed
|
58
|
-
end
|
59
|
-
|
60
|
-
class BreedHusky < Breed
|
61
|
-
end
|
62
|
-
|
63
|
-
class Dog < ActiveRecord::Base
|
64
|
-
classy_enum_attr :breed
|
65
|
-
end
|
66
|
-
|
67
|
-
class AllowBlankBreedDog < ActiveRecord::Base
|
68
|
-
classy_enum_attr :breed, :allow_blank => true
|
69
|
-
end
|
70
|
-
|
71
|
-
class AllowNilBreedDog < ActiveRecord::Base
|
72
|
-
classy_enum_attr :breed, :allow_nil => true
|
73
|
-
end
|
74
|
-
|
75
|
-
class OtherDog < ActiveRecord::Base
|
76
|
-
classy_enum_attr :other_breed, :enum => :breed
|
77
|
-
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: classy_enum
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -34,7 +34,7 @@ dependencies:
|
|
34
34
|
requirements:
|
35
35
|
- - ~>
|
36
36
|
- !ruby/object:Gem::Version
|
37
|
-
version: 2.
|
37
|
+
version: 2.11.0
|
38
38
|
type: :development
|
39
39
|
prerelease: false
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -42,7 +42,7 @@ dependencies:
|
|
42
42
|
requirements:
|
43
43
|
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
version: 2.
|
45
|
+
version: 2.11.0
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
47
|
name: sqlite3
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
@@ -95,17 +95,20 @@ files:
|
|
95
95
|
- gemfiles/Gemfile.rails-3.2.x
|
96
96
|
- init.rb
|
97
97
|
- lib/classy_enum.rb
|
98
|
-
- lib/classy_enum/
|
98
|
+
- lib/classy_enum/active_record.rb
|
99
99
|
- lib/classy_enum/base.rb
|
100
|
-
- lib/classy_enum/
|
101
|
-
- lib/classy_enum/
|
100
|
+
- lib/classy_enum/collection.rb
|
101
|
+
- lib/classy_enum/conversion.rb
|
102
|
+
- lib/classy_enum/predicate.rb
|
102
103
|
- lib/classy_enum/version.rb
|
103
104
|
- lib/generators/classy_enum/classy_enum_generator.rb
|
104
105
|
- lib/generators/classy_enum/templates/enum.rb
|
105
|
-
- spec/active_record_spec.rb
|
106
|
-
- spec/
|
107
|
-
- spec/
|
108
|
-
- spec/
|
106
|
+
- spec/classy_enum/active_record_spec.rb
|
107
|
+
- spec/classy_enum/base_spec.rb
|
108
|
+
- spec/classy_enum/collection_spec.rb
|
109
|
+
- spec/classy_enum/conversion_spec.rb
|
110
|
+
- spec/classy_enum/predicate_spec.rb
|
111
|
+
- spec/classy_enum_inheritance_spec.rb
|
109
112
|
- spec/spec_helper.rb
|
110
113
|
homepage: http://github.com/beerlington/classy_enum
|
111
114
|
licenses: []
|
@@ -121,7 +124,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
121
124
|
version: '0'
|
122
125
|
segments:
|
123
126
|
- 0
|
124
|
-
hash:
|
127
|
+
hash: 3644506881692123531
|
125
128
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
129
|
none: false
|
127
130
|
requirements:
|
@@ -130,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
130
133
|
version: '0'
|
131
134
|
segments:
|
132
135
|
- 0
|
133
|
-
hash:
|
136
|
+
hash: 3644506881692123531
|
134
137
|
requirements: []
|
135
138
|
rubyforge_project:
|
136
139
|
rubygems_version: 1.8.24
|
@@ -138,8 +141,10 @@ signing_key:
|
|
138
141
|
specification_version: 3
|
139
142
|
summary: A class based enumerator utility for Ruby on Rails
|
140
143
|
test_files:
|
141
|
-
- spec/active_record_spec.rb
|
142
|
-
- spec/
|
143
|
-
- spec/
|
144
|
-
- spec/
|
144
|
+
- spec/classy_enum/active_record_spec.rb
|
145
|
+
- spec/classy_enum/base_spec.rb
|
146
|
+
- spec/classy_enum/collection_spec.rb
|
147
|
+
- spec/classy_enum/conversion_spec.rb
|
148
|
+
- spec/classy_enum/predicate_spec.rb
|
149
|
+
- spec/classy_enum_inheritance_spec.rb
|
145
150
|
- spec/spec_helper.rb
|
@@ -1,72 +0,0 @@
|
|
1
|
-
module ClassyEnum
|
2
|
-
module Attributes
|
3
|
-
|
4
|
-
# Class macro used to associate an enum with an attribute on an ActiveRecord model.
|
5
|
-
# This method is automatically added to all ActiveRecord models when the classy_enum gem
|
6
|
-
# is installed. Accepts an argument for the enum class to be associated with
|
7
|
-
# the model. If the enum class name is different than the field name, then an optional
|
8
|
-
# field name can be passed. ActiveRecord validation is automatically added to ensure
|
9
|
-
# that a value is one of its pre-defined enum members.
|
10
|
-
#
|
11
|
-
# ==== Example
|
12
|
-
# # Associate an enum Priority with Alarm model's priority attribute
|
13
|
-
# class Alarm < ActiveRecord::Base
|
14
|
-
# classy_enum_attr :priority
|
15
|
-
# end
|
16
|
-
#
|
17
|
-
# # Associate an enum Priority with Alarm model's alarm_priority attribute
|
18
|
-
# class Alarm < ActiveRecord::Base
|
19
|
-
# classy_enum_attr :alarm_priority, :enum => :priority
|
20
|
-
# end
|
21
|
-
def classy_enum_attr(*args)
|
22
|
-
options = args.extract_options!
|
23
|
-
|
24
|
-
attribute = args[0]
|
25
|
-
|
26
|
-
enum = options[:enum] || attribute
|
27
|
-
allow_blank = options[:allow_blank] || false
|
28
|
-
allow_nil = options[:allow_nil] || false
|
29
|
-
serialize_as_json = options[:serialize_as_json] || false
|
30
|
-
|
31
|
-
reader_method = attribute.to_s
|
32
|
-
|
33
|
-
if options.has_key? :suffix
|
34
|
-
ActiveSupport::Deprecation.warn(':suffix option for classy_enum_attr is deprecated, and will be removed in ClassyEnum 3.0.', caller)
|
35
|
-
reader_method += "_#{options[:suffix]}"
|
36
|
-
end
|
37
|
-
|
38
|
-
klass = enum.to_s.camelize.constantize
|
39
|
-
|
40
|
-
valid_attributes = reader_method == attribute.to_s ? klass.all : klass.all.map(&:to_s)
|
41
|
-
|
42
|
-
self.instance_eval do
|
43
|
-
|
44
|
-
# Add ActiveRecord validation to ensure it won't be saved unless it's an option
|
45
|
-
validates_inclusion_of attribute,
|
46
|
-
:in => valid_attributes,
|
47
|
-
:message => "must be one of #{klass.valid_options}",
|
48
|
-
:allow_blank => allow_blank,
|
49
|
-
:allow_nil => allow_nil
|
50
|
-
|
51
|
-
# Define getter method that returns a ClassyEnum instance
|
52
|
-
define_method reader_method do
|
53
|
-
klass.build(read_attribute(attribute), :owner => self, :serialize_as_json => serialize_as_json)
|
54
|
-
end
|
55
|
-
|
56
|
-
# Define setter method that accepts either string or symbol for member
|
57
|
-
define_method "#{attribute}=" do |value|
|
58
|
-
value = value.to_s unless value.nil?
|
59
|
-
super(value)
|
60
|
-
end
|
61
|
-
|
62
|
-
# Store the enum options so it can be later retrieved by Formtastic
|
63
|
-
define_method "#{attribute}_options" do
|
64
|
-
{:enum => enum, :allow_blank => allow_blank}
|
65
|
-
end
|
66
|
-
|
67
|
-
end
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
end
|
72
|
-
end
|
@@ -1,141 +0,0 @@
|
|
1
|
-
module ClassyEnum
|
2
|
-
module ClassMethods
|
3
|
-
|
4
|
-
# Macro for defining enum members within a ClassyEnum class.
|
5
|
-
# Accepts an array of symbols or strings which are converted to
|
6
|
-
# ClassyEnum members as descents of their parent class.
|
7
|
-
#
|
8
|
-
# ==== Example
|
9
|
-
# # Define an enum called Priority with three child classes
|
10
|
-
# class Priority < ClassyEnum::Base
|
11
|
-
# enum_classes :low, :medium, :high
|
12
|
-
# end
|
13
|
-
#
|
14
|
-
# The child classes will be defined with the following constants:
|
15
|
-
# PriorityLow, PriorityMedium, and PriorityHigh
|
16
|
-
#
|
17
|
-
# These child classes can be instantiated with either:
|
18
|
-
# Priority.build(:low) or PriorityLow.new
|
19
|
-
#
|
20
|
-
def enum_classes(*enums)
|
21
|
-
ActiveSupport::Deprecation.warn('enum_classes is deprecated, and will be removed in ClassyEnum 3.0. It is no longer needed.', caller)
|
22
|
-
|
23
|
-
self.class_eval do
|
24
|
-
class_attribute :enum_options, :base_class
|
25
|
-
|
26
|
-
self.enum_options = enums.map(&:to_sym)
|
27
|
-
self.base_class = self
|
28
|
-
|
29
|
-
# # Use ActiveModel::AttributeMethods to define attribute? methods
|
30
|
-
attribute_method_suffix '?'
|
31
|
-
define_attribute_methods enums
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def inherited(klass)
|
36
|
-
return if self == ClassyEnum::Base
|
37
|
-
|
38
|
-
# Add visit_EnumMember methods to support validates_uniqueness_of with enum field
|
39
|
-
Arel::Visitors::ToSql.class_eval do
|
40
|
-
define_method "visit_#{klass.name}", lambda {|value| quote(value.to_s) }
|
41
|
-
end
|
42
|
-
|
43
|
-
if klass.name.start_with? "#{base_class.name}::"
|
44
|
-
enum = klass.name.split('::').last.underscore.to_sym
|
45
|
-
else
|
46
|
-
ActiveSupport::Deprecation.warn("The enum class name #{klass} is deprecated. ClassyEnum 3.0 will require subclasses to use the parent class as a namespace. Change it to #{base_class}::#{klass.name.gsub(base_class.name, '')}", caller)
|
47
|
-
enum = klass.name.gsub(klass.base_class.name, '').underscore.to_sym
|
48
|
-
end
|
49
|
-
|
50
|
-
index = self.enum_options.index(enum) + 1
|
51
|
-
|
52
|
-
klass.class_eval do
|
53
|
-
@index = index
|
54
|
-
@option = enum
|
55
|
-
|
56
|
-
attr_accessor :owner, :serialize_as_json
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
# Build a new ClassyEnum child instance
|
61
|
-
#
|
62
|
-
# ==== Example
|
63
|
-
# # Create an Enum with some elements
|
64
|
-
# class Priority < ClassyEnum::Base
|
65
|
-
# enum_classes :low, :medium, :high
|
66
|
-
# end
|
67
|
-
#
|
68
|
-
# Priority.build(:low) # => PriorityLow.new
|
69
|
-
def build(value, options={})
|
70
|
-
return value if value.blank?
|
71
|
-
return TypeError.new("Valid #{self} options are #{self.valid_options}") unless self.enum_options.include? value.to_sym
|
72
|
-
|
73
|
-
# Temp hack until 3.0 to allow both namespaced and non-namespaced classes
|
74
|
-
begin
|
75
|
-
klass = "#{self}::#{value.to_s.camelize}".constantize
|
76
|
-
rescue NameError
|
77
|
-
klass = "#{self}#{value.to_s.camelize}".constantize
|
78
|
-
end
|
79
|
-
|
80
|
-
object = klass.new
|
81
|
-
object.owner = options[:owner]
|
82
|
-
object.serialize_as_json = options[:serialize_as_json]
|
83
|
-
object
|
84
|
-
end
|
85
|
-
|
86
|
-
def find(value, options={})
|
87
|
-
ActiveSupport::Deprecation.warn("find is deprecated, and will be removed in ClassyEnum 3.0. Use build(:member) instead.", caller)
|
88
|
-
build(value, options)
|
89
|
-
end
|
90
|
-
|
91
|
-
# Returns an array of all instantiated enums
|
92
|
-
#
|
93
|
-
# ==== Example
|
94
|
-
# # Create an Enum with some elements
|
95
|
-
# class Priority < ClassyEnum::Base
|
96
|
-
# enum_classes :low, :medium, :high
|
97
|
-
# end
|
98
|
-
#
|
99
|
-
# Priority.all # => [PriorityLow.new, PriorityMedium.new, PriorityHigh.new]
|
100
|
-
def all
|
101
|
-
self.enum_options.map {|e| build(e) }
|
102
|
-
end
|
103
|
-
|
104
|
-
# Returns a 2D array for Rails select helper options.
|
105
|
-
# Also used internally for Formtastic support
|
106
|
-
#
|
107
|
-
# ==== Example
|
108
|
-
# # Create an Enum with some elements
|
109
|
-
# class Priority < ClassyEnum::Base
|
110
|
-
# enum_classes :low, :really_high
|
111
|
-
# end
|
112
|
-
#
|
113
|
-
# Priority.select_options # => [["Low", "low"], ["Really High", "really_high"]]
|
114
|
-
def select_options
|
115
|
-
all.map {|e| [e.name, e.to_s] }
|
116
|
-
end
|
117
|
-
|
118
|
-
# Returns a comma separated list of valid enum options.
|
119
|
-
# Also used internally for ActiveRecord model validation error messages
|
120
|
-
#
|
121
|
-
# ==== Example
|
122
|
-
# # Create an Enum with some elements
|
123
|
-
# class Priority < ClassyEnum::Base
|
124
|
-
# enum_classes :low, :medium, :high
|
125
|
-
# end
|
126
|
-
#
|
127
|
-
# Priority.valid_options # => "low, medium, high"
|
128
|
-
def valid_options
|
129
|
-
ActiveSupport::Deprecation.warn("valid_options is deprecated, and will be removed in ClassyEnum 3.0. Use all.join(', ') instead.", caller)
|
130
|
-
self.enum_options.map(&:to_s).join(', ')
|
131
|
-
end
|
132
|
-
|
133
|
-
private
|
134
|
-
|
135
|
-
# DSL setter method for reference to enum owner
|
136
|
-
def owner(owner)
|
137
|
-
define_method owner, lambda { @owner }
|
138
|
-
end
|
139
|
-
|
140
|
-
end
|
141
|
-
end
|