enumerize 0.8.0 → 2.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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +11 -12
  5. data/CHANGELOG.md +112 -0
  6. data/Gemfile +5 -22
  7. data/Gemfile.global +19 -0
  8. data/Gemfile.mongo_mapper +6 -0
  9. data/Gemfile.rails42 +6 -0
  10. data/README.md +185 -9
  11. data/Rakefile +2 -4
  12. data/enumerize.gemspec +1 -0
  13. data/lib/enumerize/activerecord.rb +17 -28
  14. data/lib/enumerize/attribute.rb +41 -9
  15. data/lib/enumerize/base.rb +28 -17
  16. data/lib/enumerize/hooks/formtastic.rb +3 -8
  17. data/lib/enumerize/hooks/sequel_dataset.rb +15 -0
  18. data/lib/enumerize/hooks/simple_form.rb +5 -11
  19. data/lib/enumerize/hooks/uniqueness.rb +3 -8
  20. data/lib/enumerize/integrations/rspec/matcher.rb +107 -26
  21. data/lib/enumerize/mongoid.rb +13 -0
  22. data/lib/enumerize/predicatable.rb +7 -16
  23. data/lib/enumerize/predicates.rb +3 -1
  24. data/lib/enumerize/scope/activerecord.rb +37 -0
  25. data/lib/enumerize/scope/mongoid.rb +35 -0
  26. data/lib/enumerize/scope/sequel.rb +40 -0
  27. data/lib/enumerize/sequel.rb +57 -0
  28. data/lib/enumerize/set.rb +18 -8
  29. data/lib/enumerize/value.rb +10 -9
  30. data/lib/enumerize/version.rb +1 -1
  31. data/lib/enumerize.rb +23 -1
  32. data/spec/enumerize/integrations/rspec/matcher_spec.rb +258 -0
  33. data/spec/spec_helper.rb +28 -0
  34. data/test/activerecord_test.rb +143 -7
  35. data/test/attribute_test.rb +22 -0
  36. data/test/base_test.rb +2 -2
  37. data/test/formtastic_test.rb +3 -12
  38. data/test/mongo_mapper_test.rb +6 -0
  39. data/test/mongoid_test.rb +62 -6
  40. data/test/multiple_test.rb +21 -0
  41. data/test/predicates_test.rb +6 -0
  42. data/test/sequel_test.rb +291 -0
  43. data/test/set_test.rb +14 -0
  44. data/test/simple_form_test.rb +0 -1
  45. data/test/support/view_test_helper.rb +4 -0
  46. data/test/test_helper.rb +23 -2
  47. data/test/value_test.rb +51 -21
  48. metadata +39 -9
  49. data/Gemfile.rails4 +0 -23
  50. data/lib/enumerize/form_helper.rb +0 -23
  51. data/test/rspec_matcher_test.rb +0 -76
  52. data/test/rspec_spec.rb +0 -13
@@ -15,13 +15,13 @@ ActiveRecord::Base.connection.instance_eval do
15
15
  t.string :lambda_role
16
16
  t.string :name
17
17
  t.string :interests
18
- t.string :status
18
+ t.integer :status
19
19
  t.string :account_type, :default => :basic
20
20
  end
21
21
 
22
22
  create_table :documents do |t|
23
23
  t.string :visibility
24
- t.timestamps
24
+ t.timestamps null: true
25
25
  end
26
26
  end
27
27
 
@@ -53,10 +53,19 @@ class User < ActiveRecord::Base
53
53
  enumerize :status, :in => { active: 1, blocked: 2 }, scope: true
54
54
 
55
55
  enumerize :account_type, :in => [:basic, :premium]
56
+
57
+ # There is no column for relationship enumeration for testing purposes: model
58
+ # should not be broken even if the associated column does not exist yet.
59
+ enumerize :relationship, :in => [:single, :married]
56
60
  end
57
61
 
58
62
  class UniqStatusUser < User
59
63
  validates :status, uniqueness: true
64
+ validates :sex, presence: true
65
+ end
66
+
67
+ class InterestsRequiredUser < User
68
+ validates :interests, presence: true
60
69
  end
61
70
 
62
71
  describe Enumerize::ActiveRecordSupport do
@@ -92,7 +101,8 @@ describe Enumerize::ActiveRecordSupport do
92
101
  it 'does not set default value for not selected attributes' do
93
102
  User.delete_all
94
103
  User.create!(:sex => :male)
95
- User.select(:id).collect(&:id)
104
+
105
+ assert_equal ['id'], User.select(:id).first.attributes.keys
96
106
  end
97
107
 
98
108
  it 'has default value with lambda' do
@@ -128,9 +138,18 @@ describe Enumerize::ActiveRecordSupport do
128
138
  user.errors[:role].must_include 'is not included in the list'
129
139
  end
130
140
 
131
- it 'validates inclusion when using write_attribute' do
141
+ it 'validates inclusion when using write_attribute with string attribute' do
142
+ user = User.new
143
+ user.send(:write_attribute, 'role', 'wrong')
144
+ user.read_attribute_for_validation(:role).must_equal 'wrong'
145
+ user.wont_be :valid?
146
+ user.errors[:role].must_include 'is not included in the list'
147
+ end
148
+
149
+ it 'validates inclusion when using write_attribute with symbol attribute' do
132
150
  user = User.new
133
151
  user.send(:write_attribute, :role, 'wrong')
152
+ user.read_attribute_for_validation(:role).must_equal 'wrong'
134
153
  user.wont_be :valid?
135
154
  user.errors[:role].must_include 'is not included in the list'
136
155
  end
@@ -143,7 +162,7 @@ describe Enumerize::ActiveRecordSupport do
143
162
 
144
163
  it "uses persisted value for validation if it hasn't been set" do
145
164
  user = User.create! :sex => :male
146
- User.find(user).read_attribute_for_validation(:sex).must_equal 'male'
165
+ User.find(user.id).read_attribute_for_validation(:sex).must_equal 'male'
147
166
  end
148
167
 
149
168
  it 'is valid with empty string assigned' do
@@ -179,6 +198,13 @@ describe Enumerize::ActiveRecordSupport do
179
198
  interests.must_equal %w(music dancing)
180
199
  end
181
200
 
201
+ it 'stores multiple value passed passed to new' do
202
+ user = User.new(interests: [:music, :dancing])
203
+ user.save!
204
+ user.interests.must_equal %w(music dancing)
205
+ User.find(user.id).interests.must_equal %w(music dancing)
206
+ end
207
+
182
208
  it 'returns invalid multiple value for validation' do
183
209
  user = User.new
184
210
  user.interests << :music
@@ -199,6 +225,22 @@ describe Enumerize::ActiveRecordSupport do
199
225
  user.must_be :valid?
200
226
  end
201
227
 
228
+ it 'stores custom values for multiple attributes' do
229
+ User.delete_all
230
+
231
+ klass = Class.new(User)
232
+ klass.enumerize :interests, in: { music: 0, sports: 1, dancing: 2, programming: 3}, multiple: true
233
+
234
+ user = klass.new
235
+ user.interests << :music
236
+ user.read_attribute(:interests).must_equal [0]
237
+ user.interests.must_equal %w(music)
238
+ user.save
239
+
240
+ user = klass.find(user.id)
241
+ user.interests.must_equal %w(music)
242
+ end
243
+
202
244
  it 'adds scope' do
203
245
  User.delete_all
204
246
 
@@ -215,6 +257,12 @@ describe Enumerize::ActiveRecordSupport do
215
257
  User.having_role(:admin).must_equal [user_1]
216
258
  end
217
259
 
260
+ it 'ignores not enumerized values that passed to the scope method' do
261
+ User.delete_all
262
+
263
+ User.with_status(:foo).must_equal []
264
+ end
265
+
218
266
  it 'allows either key or value as valid' do
219
267
  user_1 = User.new(status: :active)
220
268
  user_2 = User.new(status: 1)
@@ -258,6 +306,36 @@ describe Enumerize::ActiveRecordSupport do
258
306
  user.errors[:status].wont_be :empty?
259
307
  end
260
308
 
309
+ it 'validates presence with multiple attributes' do
310
+ user = InterestsRequiredUser.new
311
+ user.interests = []
312
+ user.valid?
313
+
314
+ user.errors[:interests].wont_be :empty?
315
+
316
+ user.interests = ['']
317
+ user.valid?
318
+
319
+ user.errors[:interests].wont_be :empty?
320
+
321
+ user.interests = [:dancing, :programming]
322
+ user.valid?
323
+
324
+ user.errors[:interests].must_be_empty
325
+ end
326
+
327
+ it 'is valid after #becomes' do
328
+ User.delete_all
329
+ user = User.new
330
+ user.sex = :male
331
+ user.save!
332
+
333
+ uniq_user = User.find(user.id).becomes(UniqStatusUser)
334
+ uniq_user.valid?
335
+
336
+ uniq_user.errors.must_be_empty
337
+ end
338
+
261
339
  it 'supports multiple attributes in #becomes' do
262
340
  User.delete_all
263
341
 
@@ -291,7 +369,65 @@ describe Enumerize::ActiveRecordSupport do
291
369
  user = User.create(:status => :active)
292
370
  user.status = :blocked
293
371
 
294
- expected = ActiveSupport::HashWithIndifferentAccess.new(status: [1, 2]).to_yaml
295
- assert_equal expected, user.changes.to_yaml
372
+ assert_equal [1, 2], YAML.load(user.changes.to_yaml)[:status]
373
+ end
374
+
375
+ it 'allows using update_all' do
376
+ User.delete_all
377
+
378
+ user = User.create(status: :active, account_type: :premium)
379
+
380
+ User.update_all(status: :blocked)
381
+ user.reload
382
+ user.status.must_equal 'blocked'
383
+
384
+ User.update_all(status: :active, account_type: :basic)
385
+ user.reload
386
+ user.status.must_equal 'active'
387
+ user.account_type.must_equal 'basic'
388
+ end
389
+
390
+ it 'allows using update_all for multiple enumerize' do
391
+ User.delete_all
392
+
393
+ klass = Class.new(User)
394
+ klass.enumerize :interests, in: { music: 0, sports: 1, dancing: 2, programming: 3}, multiple: true
395
+
396
+ user = klass.create(status: :active)
397
+ klass.update_all(status: :blocked, interests: [:music, :dancing])
398
+
399
+ user = klass.find(user.id)
400
+ user.status.must_equal 'blocked'
401
+ user.interests.must_equal %w(music dancing)
402
+ end
403
+
404
+ it 'allows using update_all with values' do
405
+ User.delete_all
406
+
407
+ user = User.create(status: :active)
408
+
409
+ User.update_all(status: 2)
410
+ user.reload
411
+ user.status.must_equal 'blocked'
412
+ end
413
+
414
+ it 'preserves string usage of update_all' do
415
+ User.delete_all
416
+
417
+ user = User.create(name: "Fred")
418
+
419
+ User.update_all("name = 'Frederick'")
420
+ user.reload
421
+ user.name.must_equal 'Frederick'
422
+ end
423
+
424
+ it 'preserves interpolated array usage of update_all' do
425
+ User.delete_all
426
+
427
+ user = User.create(name: "Fred")
428
+
429
+ User.update_all(["name = :name", {name: 'Frederick'}])
430
+ user.reload
431
+ user.name.must_equal 'Frederick'
296
432
  end
297
433
  end
@@ -19,6 +19,12 @@ describe Enumerize::Attribute do
19
19
  attr.name.must_equal :foo
20
20
  end
21
21
 
22
+ it 'uses custom value class' do
23
+ value_class = Class.new(Enumerize::Value)
24
+ build_attr nil, 'foo', :in => %w[a b], :value_class => value_class
25
+ attr.values.first.must_be_instance_of value_class
26
+ end
27
+
22
28
  describe 'i18n scopes' do
23
29
  it 'returns scopes from options' do
24
30
  build_attr nil, 'foo', :in => %w[a b], :i18n_scope => %w[bar buzz]
@@ -79,6 +85,18 @@ describe Enumerize::Attribute do
79
85
  end
80
86
  end
81
87
 
88
+ it 'sets up shortcut methods for each value' do
89
+ build_attr nil, :foo, :in => {:a => 1, :b => 2}
90
+
91
+ attr.must_respond_to :a
92
+ attr.must_respond_to :b
93
+
94
+ attr.a.value.must_equal 1
95
+ attr.b.value.must_equal 2
96
+ attr.a.text.must_equal 'A'
97
+ attr.b.text.must_equal 'B'
98
+ end
99
+
82
100
  describe 'values hash with zero' do
83
101
  before do
84
102
  build_attr nil, :foo, :in => {:a => 1, :b => 2, :c => 0}
@@ -93,6 +111,10 @@ describe Enumerize::Attribute do
93
111
  attr.find_value(2).must_equal 'b'
94
112
  attr.find_value(0).must_equal 'c'
95
113
  end
114
+
115
+ it 'finds all values by hash values' do
116
+ attr.find_values(1, 2, 0).must_equal ['a', 'b', 'c']
117
+ end
96
118
  end
97
119
 
98
120
  describe 'boolean values hash' do
data/test/base_test.rb CHANGED
@@ -41,7 +41,7 @@ describe Enumerize::Base do
41
41
  end
42
42
  end
43
43
 
44
- it 'scopes translation by i18 key' do
44
+ it 'scopes translation by i18n key' do
45
45
  def klass.model_name
46
46
  name = "ExampleClass"
47
47
  def name.i18n_key
@@ -171,7 +171,7 @@ describe Enumerize::Base do
171
171
 
172
172
  object = klass.new
173
173
  object.foo.must_be_nil
174
- object.attributes.must_equal({:foo => nil})
174
+ object.attributes.must_equal({})
175
175
 
176
176
  object.foo = 'test'
177
177
  object.foo.must_equal 'test'
@@ -1,16 +1,7 @@
1
1
  require 'test_helper'
2
- require 'rails'
3
-
4
- module Formtastic
5
- module Helpers
6
- module InputHelper
7
- remove_method :input_class
8
- def input_class(as)
9
- input_class_with_const_defined(as)
10
- end
11
- end
12
- end
13
- end
2
+
3
+ Formtastic::FormBuilder.action_class_finder = Formtastic::ActionClassFinder
4
+ Formtastic::FormBuilder.input_class_finder = Formtastic::InputClassFinder
14
5
 
15
6
  class FormtasticSpec < MiniTest::Spec
16
7
  include ViewTestHelper
@@ -1,5 +1,7 @@
1
1
  require 'test_helper'
2
2
 
3
+ begin
4
+
3
5
  silence_warnings do
4
6
  require 'mongo_mapper'
5
7
  end
@@ -66,3 +68,7 @@ describe Enumerize do
66
68
  user.sex.must_equal 'female'
67
69
  end
68
70
  end
71
+
72
+ rescue LoadError
73
+ # Skip
74
+ end
data/test/mongoid_test.rb CHANGED
@@ -1,13 +1,14 @@
1
1
  require 'test_helper'
2
2
 
3
+ begin
4
+
3
5
  silence_warnings do
4
6
  require 'mongoid'
5
7
  end
6
8
 
7
9
  Mongoid.configure do |config|
8
- config.sessions = { :default => { :database => 'enumerize-test-suite', hosts: ['127.0.0.1:27017'] } }
9
- config.use_utc = true
10
- config.include_root_in_json = true
10
+ config.connect_to('enumerize-test-suite')
11
+ config.options = { use_utc: true, include_root_in_json: true }
11
12
  end
12
13
 
13
14
  describe Enumerize do
@@ -17,9 +18,10 @@ describe Enumerize do
17
18
 
18
19
  field :sex
19
20
  field :role
20
- enumerize :sex, :in => %w[male female]
21
- enumerize :role, :in => %w[admin user], :default => 'user'
22
- enumerize :mult, :in => %w[one two three four], :multiple => true
21
+ enumerize :sex, :in => %w[male female], scope: true
22
+ enumerize :status, :in => %w[notice warning error], scope: true
23
+ enumerize :role, :in => %w[admin user], :default => 'user', scope: :having_role
24
+ enumerize :mult, :in => %w[one two three four], :multiple => true
23
25
  end
24
26
 
25
27
  before { $VERBOSE = nil }
@@ -55,6 +57,21 @@ describe Enumerize do
55
57
  model.new.role.must_equal 'user'
56
58
  end
57
59
 
60
+ it 'uses after_initialize callback to set default value' do
61
+ model.delete_all
62
+ model.create!(sex: 'male', role: nil)
63
+
64
+ user = model.where(sex: 'male').first
65
+ user.role.must_equal 'user'
66
+ end
67
+
68
+ it 'does not set default value for not selected attributes' do
69
+ model.delete_all
70
+ model.create!(sex: :male)
71
+
72
+ assert_equal ['_id'], model.only(:id).first.attributes.keys
73
+ end
74
+
58
75
  it 'validates inclusion' do
59
76
  user = model.new
60
77
  user.role = 'wrong'
@@ -76,4 +93,43 @@ describe Enumerize do
76
93
  user = model.first
77
94
  user.mult.to_a.must_equal ['one', 'two']
78
95
  end
96
+
97
+ it 'adds scope' do
98
+ model.delete_all
99
+
100
+ user_1 = model.create!(sex: :male, role: :admin)
101
+ user_2 = model.create!(sex: :female, role: :user)
102
+
103
+ model.with_sex(:male).to_a.must_equal [user_1]
104
+ model.with_sex(:female).to_a.must_equal [user_2]
105
+ model.with_sex(:male, :female).to_set.must_equal [user_1, user_2].to_set
106
+
107
+ model.without_sex(:male).to_a.must_equal [user_2]
108
+ model.without_sex(:female).to_a.must_equal [user_1]
109
+ model.without_sex(:male, :female).to_a.must_equal []
110
+
111
+ model.having_role(:admin).to_a.must_equal [user_1]
112
+ model.having_role(:user).to_a.must_equal [user_2]
113
+ end
114
+
115
+ it 'chains scopes' do
116
+ model.delete_all
117
+
118
+ user_1 = model.create!(status: :notice)
119
+ user_2 = model.create!(status: :warning)
120
+ user_3 = model.create!(status: :error)
121
+
122
+ model.with_status(:notice, :warning).with_status(:notice, :error).to_a.must_equal [user_1]
123
+ model.with_status(:notice, :warning).union.with_status(:notice, :error).to_a.must_equal [user_1, user_2, user_3]
124
+ end
125
+
126
+ it 'ignores not enumerized values that passed to the scope method' do
127
+ model.delete_all
128
+
129
+ model.with_sex(:foo).must_equal []
130
+ end
131
+ end
132
+
133
+ rescue LoadError
134
+ # Skip
79
135
  end
@@ -24,6 +24,21 @@ describe Enumerize::Base do
24
24
  object.foos.must_equal %w(a c)
25
25
  end
26
26
 
27
+ it 'sets default value as single value' do
28
+ klass.enumerize :foos, in: %w(a b c), default: 'b', multiple: true
29
+ object.foos.must_equal %w(b)
30
+ end
31
+
32
+ it 'sets default value as array of one element' do
33
+ klass.enumerize :foos, in: %w(a b c), default: %w(b), multiple: true
34
+ object.foos.must_equal %w(b)
35
+ end
36
+
37
+ it 'sets default value as array of several elements' do
38
+ klass.enumerize :foos, in: %w(a b c), default: %w(b c), multiple: true
39
+ object.foos.must_equal %w(b c)
40
+ end
41
+
27
42
  it "doesn't define _text method" do
28
43
  klass.enumerize :foos, in: %w(a b c), multiple: true
29
44
  object.wont_respond_to :foos_text
@@ -33,4 +48,10 @@ describe Enumerize::Base do
33
48
  klass.enumerize :foos, in: %w(a b c), multiple: true
34
49
  object.wont_respond_to :foos_value
35
50
  end
51
+
52
+ it "cannot define multiple with scope" do
53
+ assert_raises ArgumentError do
54
+ klass.enumerize :foos, in: %w(a b c), multiple: true, scope: true
55
+ end
56
+ end
36
57
  end
@@ -15,6 +15,12 @@ describe Enumerize::Predicates do
15
15
  object.must_respond_to :b?
16
16
  end
17
17
 
18
+ it 'creates predicate methods when enumerized values have dash in it' do
19
+ klass.enumerize(:foo, in: %w(foo-bar bar-foo), predicates: true)
20
+ object.must_respond_to :foo_bar?
21
+ object.must_respond_to :bar_foo?
22
+ end
23
+
18
24
  it 'creates predicate methods on multiple attribute' do
19
25
  klass.enumerize(:foo, in: %w(a b), predicates: true, multiple: true)
20
26
  object.must_respond_to :a?