classy_enum 3.2.0 → 3.2.1
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/.travis.yml +5 -0
- data/CHANGELOG.md +8 -0
- data/Gemfile +1 -1
- data/README.md +3 -2
- data/Rakefile +4 -1
- data/classy_enum.gemspec +4 -3
- data/gemfiles/Gemfile.rails-4.0.x +6 -0
- data/lib/classy_enum/active_record.rb +30 -18
- data/lib/classy_enum/base.rb +24 -9
- data/lib/classy_enum/version.rb +1 -1
- data/spec/classy_enum/active_record_spec.rb +37 -3
- data/spec/classy_enum_inheritance_spec.rb +2 -2
- data/spec/classy_enum_spec.rb +65 -0
- data/spec/spec_helper.rb +1 -0
- metadata +29 -10
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# ClassyEnum Changelog
|
2
2
|
|
3
|
+
## 3.2.1
|
4
|
+
|
5
|
+
* Better support for using `default` and `allow_*` options together
|
6
|
+
* Fixes bug when using `default` option and explicitly setting value to
|
7
|
+
nil if `allow_nil: true` option is not used.
|
8
|
+
* Fixes bug when chaining `count` onto scope that uses enum object in
|
9
|
+
query condition.
|
10
|
+
|
3
11
|
## 3.2.0
|
4
12
|
|
5
13
|
* Default values can now be specified within an ActiveRecord model
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
[](http://travis-ci.org/beerlington/classy_enum)
|
4
4
|
[](http://badge.fury.io/rb/classy_enum)
|
5
5
|
[](https://codeclimate.com/github/beerlington/classy_enum)
|
6
|
+
[](https://gemnasium.com/beerlington/classy_enum)
|
6
7
|
|
7
8
|
ClassyEnum is a Ruby on Rails gem that adds class-based enumerator functionality to ActiveRecord attributes.
|
8
9
|
|
@@ -20,9 +21,9 @@ ClassyEnum is a Ruby on Rails gem that adds class-based enumerator functionality
|
|
20
21
|
|
21
22
|
## Rails & Ruby Versions Supported
|
22
23
|
|
23
|
-
*Rails:* 3.0.x - 4.0.0.
|
24
|
+
*Rails:* 3.0.x - 4.0.0.rc1
|
24
25
|
|
25
|
-
*Ruby:* 1.8.7, 1.9.2
|
26
|
+
*Ruby:* 1.8.7, 1.9.2, 1.9.3 and 2.0.0
|
26
27
|
|
27
28
|
If you need support for Rails 2.3.x, please install [version 0.9.1](https://rubygems.org/gems/classy_enum/versions/0.9.1).
|
28
29
|
Note: This branch is no longer maintained and will not get bug fixes or new features.
|
data/Rakefile
CHANGED
data/classy_enum.gemspec
CHANGED
@@ -16,8 +16,9 @@ Gem::Specification.new do |gem|
|
|
16
16
|
|
17
17
|
gem.add_dependency('rails', '>= 3.0')
|
18
18
|
|
19
|
-
gem.add_development_dependency('rspec-rails', '
|
20
|
-
gem.add_development_dependency('sqlite3', '
|
21
|
-
gem.add_development_dependency('json', '
|
19
|
+
gem.add_development_dependency('rspec-rails', '>= 2.11')
|
20
|
+
gem.add_development_dependency('sqlite3', '>= 1.3')
|
21
|
+
gem.add_development_dependency('json', '>= 1.6')
|
22
|
+
gem.add_development_dependency('debugger')
|
22
23
|
|
23
24
|
end
|
@@ -1,6 +1,32 @@
|
|
1
1
|
module ClassyEnum
|
2
2
|
class InvalidDefault < StandardError; end
|
3
3
|
|
4
|
+
def self._normalize_value(value, default=nil, allow_blank=false) # :nodoc:
|
5
|
+
if value.class == Class && value < ClassyEnum::Base
|
6
|
+
value = value.new.to_s
|
7
|
+
elsif value.present?
|
8
|
+
value = value.to_s
|
9
|
+
elsif value.blank? && allow_blank
|
10
|
+
value
|
11
|
+
else
|
12
|
+
default
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self._normalize_default(value, enum_class) # :nodoc:
|
17
|
+
if value.present?
|
18
|
+
if value.is_a? Proc
|
19
|
+
value = value.call(enum_class)
|
20
|
+
end
|
21
|
+
|
22
|
+
unless enum_class.include? value
|
23
|
+
raise InvalidDefault, "must be one of [#{enum_class.to_a.join(',')}]"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
value
|
28
|
+
end
|
29
|
+
|
4
30
|
module ActiveRecord
|
5
31
|
|
6
32
|
# Class macro used to associate an enum with an attribute on an ActiveRecord model.
|
@@ -31,17 +57,7 @@ module ClassyEnum
|
|
31
57
|
allow_blank = options[:allow_blank] || false
|
32
58
|
allow_nil = options[:allow_nil] || false
|
33
59
|
serialize_as_json = options[:serialize_as_json] || false
|
34
|
-
default = options[:default]
|
35
|
-
|
36
|
-
if default.present?
|
37
|
-
if default.is_a? Proc
|
38
|
-
default = default.call(enum)
|
39
|
-
end
|
40
|
-
|
41
|
-
unless enum.include? default
|
42
|
-
raise InvalidDefault, "must be one of [#{enum.to_a.join(',')}]"
|
43
|
-
end
|
44
|
-
end
|
60
|
+
default = ClassyEnum._normalize_default(options[:default], enum)
|
45
61
|
|
46
62
|
# Add ActiveRecord validation to ensure it won't be saved unless it's an option
|
47
63
|
validates_inclusion_of attribute,
|
@@ -51,7 +67,8 @@ module ClassyEnum
|
|
51
67
|
|
52
68
|
# Define getter method that returns a ClassyEnum instance
|
53
69
|
define_method attribute do
|
54
|
-
value = read_attribute(attribute)
|
70
|
+
value = read_attribute(attribute)
|
71
|
+
value ||= default unless allow_nil
|
55
72
|
|
56
73
|
enum.build(value,
|
57
74
|
:owner => self,
|
@@ -62,12 +79,7 @@ module ClassyEnum
|
|
62
79
|
|
63
80
|
# Define setter method that accepts string, symbol, instance or class for member
|
64
81
|
define_method "#{attribute}=" do |value|
|
65
|
-
|
66
|
-
value = value.new.to_s
|
67
|
-
elsif value.present?
|
68
|
-
value = value.to_s
|
69
|
-
end
|
70
|
-
|
82
|
+
value = ClassyEnum._normalize_value(value, default, (allow_nil || allow_blank))
|
71
83
|
super(value)
|
72
84
|
end
|
73
85
|
end
|
data/lib/classy_enum/base.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module ClassyEnum
|
2
|
-
class SubclassNameError <
|
2
|
+
class SubclassNameError < StandardError; end
|
3
3
|
|
4
4
|
class Base
|
5
5
|
include Comparable
|
@@ -29,8 +29,14 @@ module ClassyEnum
|
|
29
29
|
# database value for validation scopes. A fix will be released in Rails 4, but
|
30
30
|
# this will remain until Rails 3.x is no longer prevalent.
|
31
31
|
if defined?(Arel::Visitors::ToSql)
|
32
|
+
visitor_method = "visit_#{klass.name.split('::').join('_')}"
|
33
|
+
|
32
34
|
Arel::Visitors::ToSql.class_eval do
|
33
|
-
define_method
|
35
|
+
define_method visitor_method, lambda {|value| quote(value.to_s) }
|
36
|
+
end
|
37
|
+
|
38
|
+
Arel::Visitors::DepthFirst.class_eval do
|
39
|
+
define_method visitor_method, lambda {|value| terminal(value.to_s) }
|
34
40
|
end
|
35
41
|
end
|
36
42
|
|
@@ -62,13 +68,11 @@ module ClassyEnum
|
|
62
68
|
object = find(value)
|
63
69
|
|
64
70
|
if object.nil? || (options[:allow_blank] && object.nil?)
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
delegate :blank?, :nil?, :to => :option
|
71
|
-
}.new
|
71
|
+
if value.blank?
|
72
|
+
object = build_null_object(value)
|
73
|
+
else
|
74
|
+
return value
|
75
|
+
end
|
72
76
|
end
|
73
77
|
|
74
78
|
object.owner = options[:owner]
|
@@ -93,6 +97,17 @@ module ClassyEnum
|
|
93
97
|
def owner(owner)
|
94
98
|
define_method owner, lambda { @owner }
|
95
99
|
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
# Subclass the base class and make it behave like the value that it is
|
104
|
+
def build_null_object(value)
|
105
|
+
Class.new(base_class) {
|
106
|
+
@option = value
|
107
|
+
@index = 0
|
108
|
+
delegate :blank?, :nil?, :to => :option
|
109
|
+
}.new
|
110
|
+
end
|
96
111
|
end
|
97
112
|
|
98
113
|
end
|
data/lib/classy_enum/version.rb
CHANGED
@@ -11,6 +11,8 @@ ActiveRecord::Schema.define(:version => 1) do
|
|
11
11
|
|
12
12
|
create_table :cats, :force => true do |t|
|
13
13
|
t.string :breed
|
14
|
+
t.string :other_breed
|
15
|
+
t.string :another_breed
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|
@@ -58,8 +60,8 @@ describe DefaultDog do
|
|
58
60
|
specify { DefaultDog.new(:breed => nil).should_not be_valid }
|
59
61
|
specify { DefaultDog.new(:breed => '').should_not be_valid }
|
60
62
|
|
61
|
-
|
62
|
-
|
63
|
+
[:golden_retriever, 'golden_retriever', Breed::GoldenRetriever.new, Breed::GoldenRetriever].each do |option|
|
64
|
+
context "with a valid breed option" do
|
63
65
|
subject { DefaultDog.new(:breed => option) }
|
64
66
|
it { should be_valid }
|
65
67
|
its(:breed) { should be_a(Breed::GoldenRetriever) }
|
@@ -122,7 +124,7 @@ end
|
|
122
124
|
class ActiveDog < Dog
|
123
125
|
classy_enum_attr :color
|
124
126
|
validates_uniqueness_of :name, :scope => :color
|
125
|
-
scope :goldens, lambda { where(:breed => 'golden_retriever') }
|
127
|
+
scope :goldens, lambda { where(:breed => Breed.build('golden_retriever')) }
|
126
128
|
end
|
127
129
|
|
128
130
|
describe ActiveDog do
|
@@ -153,6 +155,10 @@ describe ActiveDog do
|
|
153
155
|
ActiveDog.goldens.should include(golden)
|
154
156
|
ActiveDog.goldens.should_not include(husky)
|
155
157
|
end
|
158
|
+
|
159
|
+
it 'should have a working scope with count' do
|
160
|
+
ActiveDog.goldens.size.should == 1
|
161
|
+
end
|
156
162
|
end
|
157
163
|
|
158
164
|
end
|
@@ -186,12 +192,15 @@ end
|
|
186
192
|
|
187
193
|
class DefaultCat < Cat
|
188
194
|
classy_enum_attr :breed, :enum => 'CatBreed'
|
195
|
+
classy_enum_attr :other_breed, :enum => 'CatBreed', :default => 'persian'
|
189
196
|
attr_accessor :color
|
190
197
|
delegate :breed_color, :to => :breed
|
191
198
|
end
|
192
199
|
|
193
200
|
class OtherCat < Cat
|
194
201
|
classy_enum_attr :breed, :enum => 'CatBreed', :serialize_as_json => true
|
202
|
+
classy_enum_attr :other_breed, :enum => 'CatBreed', :default => 'persian', :allow_nil => true
|
203
|
+
classy_enum_attr :another_breed, :enum => 'CatBreed', :default => 'persian', :allow_blank => true
|
195
204
|
attr_accessor :color
|
196
205
|
delegate :breed_color, :to => :breed
|
197
206
|
end
|
@@ -204,4 +213,29 @@ describe DefaultCat do
|
|
204
213
|
abyssian.breed_color { should eql('black Abyssian') }
|
205
214
|
persian.breed_color { should eql('white Persian') }
|
206
215
|
end
|
216
|
+
|
217
|
+
it 'uses the default if explictly set to nil and does not allow nil' do
|
218
|
+
abyssian.update_attributes!(:other_breed => nil)
|
219
|
+
DefaultCat.where(:other_breed => nil).count.should be_zero
|
220
|
+
DefaultCat.last.other_breed.should == 'persian'
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'uses the default if explictly set to blank and does not allow blank' do
|
224
|
+
abyssian.update_attributes!(:other_breed => '')
|
225
|
+
DefaultCat.where(:other_breed => '').count.should be_zero
|
226
|
+
DefaultCat.last.other_breed.should == 'persian'
|
227
|
+
end
|
228
|
+
|
229
|
+
it 'allows nil even with a default' do
|
230
|
+
persian.update_attributes!(:other_breed => nil)
|
231
|
+
OtherCat.where(:other_breed => nil).count.should eql(1)
|
232
|
+
OtherCat.last.other_breed.should be_nil
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'allows blank even with a default' do
|
236
|
+
persian.update_attributes!(:another_breed => '')
|
237
|
+
OtherCat.where(:another_breed => '').count.should eql(1)
|
238
|
+
OtherCat.last.another_breed.should be_blank
|
239
|
+
OtherCat.last.another_breed.should_not be_nil
|
240
|
+
end
|
207
241
|
end
|
@@ -14,8 +14,8 @@ end
|
|
14
14
|
|
15
15
|
describe 'Classy Enum inheritance' do
|
16
16
|
it 'should inherit from the previous class' do
|
17
|
-
ProjectTier::One.inherited_properties.should
|
18
|
-
ProjectTier::Two.inherited_properties.should
|
17
|
+
ProjectTier::One.inherited_properties.should eql([1,2,3])
|
18
|
+
ProjectTier::Two.inherited_properties.should eql([1,2,3,4,5,6])
|
19
19
|
end
|
20
20
|
|
21
21
|
it 'should instantiate the subclass' do
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
class Normalize < ClassyEnum::Base; end
|
4
|
+
class Normalize::One < Normalize; end
|
5
|
+
|
6
|
+
describe ClassyEnum do
|
7
|
+
context '._normalize_value' do
|
8
|
+
it 'converts an enum to a string' do
|
9
|
+
value = ClassyEnum._normalize_value(Normalize::One)
|
10
|
+
value.should == 'one'
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'converts a symbol to a string' do
|
14
|
+
value = ClassyEnum._normalize_value(:one)
|
15
|
+
value.should == 'one'
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'leaves a string as a string' do
|
19
|
+
value = ClassyEnum._normalize_value('one')
|
20
|
+
value.should == 'one'
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'does not convert nil' do
|
24
|
+
value = ClassyEnum._normalize_value(nil)
|
25
|
+
value.should be_nil
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'does not convert an empty string if allowed' do
|
29
|
+
value = ClassyEnum._normalize_value('', nil, true)
|
30
|
+
value.should eql('')
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'uses the default value if blank and does not allow blank' do
|
34
|
+
value = ClassyEnum._normalize_value(nil, 'one')
|
35
|
+
value.should eql('one')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context '._normalize_default' do
|
40
|
+
let(:enum) { Normalize }
|
41
|
+
|
42
|
+
it 'returns a string when provided' do
|
43
|
+
default = ClassyEnum._normalize_default('one', enum)
|
44
|
+
default.should eql('one')
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'allows a proc' do
|
48
|
+
value = lambda {|enum| enum.max }
|
49
|
+
default = ClassyEnum._normalize_default(value, enum)
|
50
|
+
default.should == enum.max
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'raises an exception if not an enum value' do
|
54
|
+
expect { ClassyEnum._normalize_default('two', enum) }.to raise_error(ClassyEnum::InvalidDefault)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'returns nil if nil is provided' do
|
58
|
+
ClassyEnum._normalize_default(nil, enum).should be_nil
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'returns empty string if provided' do
|
62
|
+
ClassyEnum._normalize_default('', enum).should eql('')
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/spec/spec_helper.rb
CHANGED
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: 3.2.
|
4
|
+
version: 3.2.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-05-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
none: false
|
34
34
|
requirements:
|
35
|
-
- -
|
35
|
+
- - ! '>='
|
36
36
|
- !ruby/object:Gem::Version
|
37
37
|
version: '2.11'
|
38
38
|
type: :development
|
@@ -40,7 +40,7 @@ dependencies:
|
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
42
42
|
requirements:
|
43
|
-
- -
|
43
|
+
- - ! '>='
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '2.11'
|
46
46
|
- !ruby/object:Gem::Dependency
|
@@ -48,7 +48,7 @@ dependencies:
|
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
49
49
|
none: false
|
50
50
|
requirements:
|
51
|
-
- -
|
51
|
+
- - ! '>='
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: '1.3'
|
54
54
|
type: :development
|
@@ -56,7 +56,7 @@ dependencies:
|
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
none: false
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ! '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '1.3'
|
62
62
|
- !ruby/object:Gem::Dependency
|
@@ -64,7 +64,7 @@ dependencies:
|
|
64
64
|
requirement: !ruby/object:Gem::Requirement
|
65
65
|
none: false
|
66
66
|
requirements:
|
67
|
-
- -
|
67
|
+
- - ! '>='
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '1.6'
|
70
70
|
type: :development
|
@@ -72,9 +72,25 @@ dependencies:
|
|
72
72
|
version_requirements: !ruby/object:Gem::Requirement
|
73
73
|
none: false
|
74
74
|
requirements:
|
75
|
-
- -
|
75
|
+
- - ! '>='
|
76
76
|
- !ruby/object:Gem::Version
|
77
77
|
version: '1.6'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: debugger
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
78
94
|
description: A utility that adds class based enum functionality to ActiveRecord attributes
|
79
95
|
email:
|
80
96
|
- github@lette.us
|
@@ -93,6 +109,7 @@ files:
|
|
93
109
|
- gemfiles/Gemfile.rails-3.0.x
|
94
110
|
- gemfiles/Gemfile.rails-3.1.x
|
95
111
|
- gemfiles/Gemfile.rails-3.2.x
|
112
|
+
- gemfiles/Gemfile.rails-4.0.x
|
96
113
|
- init.rb
|
97
114
|
- lib/classy_enum.rb
|
98
115
|
- lib/classy_enum/active_record.rb
|
@@ -111,6 +128,7 @@ files:
|
|
111
128
|
- spec/classy_enum/predicate_spec.rb
|
112
129
|
- spec/classy_enum/translation_spec.rb
|
113
130
|
- spec/classy_enum_inheritance_spec.rb
|
131
|
+
- spec/classy_enum_spec.rb
|
114
132
|
- spec/spec_helper.rb
|
115
133
|
homepage: http://github.com/beerlington/classy_enum
|
116
134
|
licenses: []
|
@@ -126,7 +144,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
126
144
|
version: '0'
|
127
145
|
segments:
|
128
146
|
- 0
|
129
|
-
hash:
|
147
|
+
hash: 633185140317949872
|
130
148
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
149
|
none: false
|
132
150
|
requirements:
|
@@ -135,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
153
|
version: '0'
|
136
154
|
segments:
|
137
155
|
- 0
|
138
|
-
hash:
|
156
|
+
hash: 633185140317949872
|
139
157
|
requirements: []
|
140
158
|
rubyforge_project:
|
141
159
|
rubygems_version: 1.8.24
|
@@ -150,4 +168,5 @@ test_files:
|
|
150
168
|
- spec/classy_enum/predicate_spec.rb
|
151
169
|
- spec/classy_enum/translation_spec.rb
|
152
170
|
- spec/classy_enum_inheritance_spec.rb
|
171
|
+
- spec/classy_enum_spec.rb
|
153
172
|
- spec/spec_helper.rb
|