classy_enum 3.2.0 → 3.2.1

Sign up to get free protection for your applications and to get access to all the features.
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