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 CHANGED
@@ -7,3 +7,8 @@ gemfile:
7
7
  - gemfiles/Gemfile.rails-3.0.x
8
8
  - gemfiles/Gemfile.rails-3.1.x
9
9
  - gemfiles/Gemfile.rails-3.2.x
10
+ - gemfiles/Gemfile.rails-4.0.x
11
+ matrix:
12
+ exclude:
13
+ - rvm: 1.8.7
14
+ gemfile: gemfiles/Gemfile.rails-4.0.x
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
@@ -1,3 +1,3 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
data/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![Build Status](https://secure.travis-ci.org/beerlington/classy_enum.png?branch=master)](http://travis-ci.org/beerlington/classy_enum)
4
4
  [![Gem Version](https://badge.fury.io/rb/classy_enum.png)](http://badge.fury.io/rb/classy_enum)
5
5
  [![Code Climate](https://codeclimate.com/github/beerlington/classy_enum.png)](https://codeclimate.com/github/beerlington/classy_enum)
6
+ [![Dependency Status](https://gemnasium.com/beerlington/classy_enum.png)](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.beta
24
+ *Rails:* 3.0.x - 4.0.0.rc1
24
25
 
25
- *Ruby:* 1.8.7, 1.9.2 and 1.9.3
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
@@ -2,5 +2,8 @@
2
2
  require "bundler/gem_tasks"
3
3
  require 'rspec/core/rake_task'
4
4
 
5
- RSpec::Core::RakeTask.new(:spec)
5
+ RSpec::Core::RakeTask.new(:spec) do |t|
6
+ t.ruby_opts = "-w"
7
+ end
8
+
6
9
  task :default => :spec
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', '~> 2.11')
20
- gem.add_development_dependency('sqlite3', '~> 1.3')
21
- gem.add_development_dependency('json', '~> 1.6')
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
@@ -0,0 +1,6 @@
1
+ source :rubygems
2
+
3
+ gem 'rails', '4.0.0.rc1'
4
+ gem 'rspec-rails', '~> 2.11'
5
+ gem 'sqlite3'
6
+ gem 'json', '~> 1.7'
@@ -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) || default
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
- if value.class == Class && value < ClassyEnum::Base
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
@@ -1,5 +1,5 @@
1
1
  module ClassyEnum
2
- class SubclassNameError < Exception; end
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 "visit_#{klass.name.split('::').join('_')}", lambda {|value| quote(value.to_s) }
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
- return value unless value.blank?
66
-
67
- # Subclass the base class and make it behave like the value that it is
68
- object = Class.new(base_class) {
69
- instance_variable_set(:@option, value)
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
@@ -1,3 +1,3 @@
1
1
  module ClassyEnum
2
- VERSION = "3.2.0"
2
+ VERSION = "3.2.1"
3
3
  end
@@ -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
- context "with valid breed options" do
62
- [:golden_retriever, 'golden_retriever', Breed::GoldenRetriever.new, Breed::GoldenRetriever].each do |option|
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 == [1,2,3]
18
- ProjectTier::Two.inherited_properties.should == [1,2,3,4,5,6]
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
@@ -2,6 +2,7 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
2
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
3
 
4
4
  require 'rubygems'
5
+ require 'rails'
5
6
  require 'active_record'
6
7
  require 'action_view'
7
8
  require 'action_controller'
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.0
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-02-08 00:00:00.000000000 Z
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: 3178964087580650038
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: 3178964087580650038
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