enumerize 2.4.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -2,6 +2,34 @@
2
2
 
3
3
  Enumerated attributes with I18n and ActiveRecord/Mongoid/MongoMapper/Sequel support
4
4
 
5
+ ## Table of Contents
6
+
7
+ - [Installation](#installation)
8
+ - [Supported Versions](#supported-versions)
9
+ - [Usage](#usage)
10
+ - [Database support](#database-support)
11
+ - [ActiveRecord](#activerecord)
12
+ - [Mongoid](#mongoid)
13
+ - [MongoMapper](#mongomapper)
14
+ - [I18n Support](#i18n-support)
15
+ - [I18n Helper Methods](#i18n-helper-methods)
16
+ - [Boolean Helper Methods](#boolean-helper-methods)
17
+ - [Basic](#basic)
18
+ - [Predicate Methods](#predicate-methods)
19
+ - [Optimzations and Tips](#optimzations-and-tips)
20
+ - [Extendable Module](#extendable-module)
21
+ - [Customizing Enumerize Value](#customizing-enumerize-value)
22
+ - [ActiveRecord scopes](#activerecord-scopes)
23
+ - [Array-like Attributes](#array-like-attributes)
24
+ - [Forms](#forms)
25
+ - [SimpleForm](#simpleform)
26
+ - [Formtastic](#formtastic)
27
+ - [Testing](#testing)
28
+ - [RSpec](#rspec)
29
+ - [Minitest with Shoulda](#minitest-with-shoulda)
30
+ - [Other Integrations](#other-integrations)
31
+ - [Contributing](#contributing)
32
+
5
33
  ## Installation
6
34
 
7
35
  Add this line to your application's Gemfile:
@@ -17,7 +45,8 @@ Or install it yourself as:
17
45
  $ gem install enumerize
18
46
 
19
47
  ## Supported Versions
20
- - Ruby 2.5+
48
+
49
+ - Ruby 2.6+
21
50
  - Rails 5.2+
22
51
 
23
52
  ## Usage
@@ -28,20 +57,23 @@ Basic:
28
57
  class User
29
58
  extend Enumerize
30
59
 
31
- enumerize :sex, in: [:male, :female]
60
+ enumerize :role, in: [:user, :admin]
32
61
  end
33
62
  ```
34
63
 
35
- Note that enumerized values are just identificators so if you want to use multi-word, etc. values you should use `I18n` feature.
64
+ Note that enumerized values are just identificators so if you want to use multi-word, etc. values then you should use `I18n` feature.
36
65
 
66
+ ---
37
67
 
38
- ActiveRecord:
68
+ ## Database support
69
+
70
+ ### ActiveRecord
39
71
 
40
72
  ```ruby
41
73
  class CreateUsers < ActiveRecord::Migration
42
74
  def change
43
75
  create_table :users do |t|
44
- t.string :sex
76
+ t.string :status
45
77
  t.string :role
46
78
 
47
79
  t.timestamps
@@ -52,7 +84,7 @@ end
52
84
  class User < ActiveRecord::Base
53
85
  extend Enumerize
54
86
 
55
- enumerize :sex, in: [:male, :female], default: lambda { |user| SexIdentifier.sex_for_name(user.name).to_sym }
87
+ enumerize :status, in: [:student, :employed, :retired], default: lambda { |user| StatusIdentifier.status_for_age(user.age).to_sym }
56
88
 
57
89
  enumerize :role, in: [:user, :admin], default: :user
58
90
  end
@@ -64,13 +96,13 @@ end
64
96
  class User < ActiveRecord::Base
65
97
  extend Enumerize
66
98
 
67
- enumerize :sex, in: [:male, :female], skip_validations: lambda { |user| user.new_record? }
99
+ enumerize :status, in: [:student, :employed, :retired], skip_validations: lambda { |user| user.new_record? }
68
100
 
69
101
  enumerize :role, in: [:user, :admin], skip_validations: true
70
102
  end
71
103
  ```
72
104
 
73
- Mongoid:
105
+ ### Mongoid
74
106
 
75
107
  ```ruby
76
108
  class User
@@ -82,7 +114,7 @@ class User
82
114
  end
83
115
  ```
84
116
 
85
- MongoMapper:
117
+ ### MongoMapper
86
118
 
87
119
  ```ruby
88
120
  class User
@@ -94,50 +126,54 @@ class User
94
126
  end
95
127
  ```
96
128
 
97
- I18n:
129
+ ---
130
+
131
+ ## I18n Support
98
132
 
99
133
  ```ruby
100
134
  en:
101
135
  enumerize:
102
136
  user:
103
- sex:
104
- male: "Male"
105
- female: "Female"
137
+ status:
138
+ student: "Student"
139
+ employed: "Employed"
140
+ retired: "Retiree"
106
141
  ```
107
142
 
108
- or if you use `sex` attribute across several models you can use `defaults` scope:
143
+ or if you use `status` attribute across several models you can use `defaults` scope:
109
144
 
110
145
  ```ruby
111
146
  en:
112
147
  enumerize:
113
148
  defaults:
114
- sex:
115
- male: "Male"
116
- female: "Female"
149
+ status:
150
+ student: "Student"
151
+ employed: "Employed"
152
+ retired: "Retiree"
117
153
  ```
118
154
 
119
155
  You can also pass `i18n_scope` option to specify scope (or array of scopes) storing the translations.
120
156
 
121
-
122
157
  ```ruby
123
158
  class Person
124
159
  extend Enumerize
125
160
  extend ActiveModel::Naming
126
161
 
127
- enumerize :sex, in: %w[male female], i18n_scope: "sex"
128
- enumerize :color, in: %w[black white], i18n_scope: ["various.colors", "colors"]
162
+ enumerize :status, in: %w[student employed retired], i18n_scope: "status"
163
+ enumerize :roles, in: %w[user admin], i18n_scope: ["user.roles", "roles"]
129
164
  end
130
165
 
131
166
  # localization file
132
167
  en:
133
- sex:
134
- male: "Male"
135
- female: "Female"
136
- various:
137
- colors:
138
- black: "Black"
139
- colors:
140
- white: "White"
168
+ status:
169
+ student: "Student"
170
+ employed: "Employed"
171
+ retired: "Retiree"
172
+ user:
173
+ roles:
174
+ user: "User"
175
+ roles:
176
+ admin: "Admin"
141
177
  ```
142
178
 
143
179
  Note that if you want to use I18n feature with plain Ruby object don't forget to extend it with `ActiveModel::Naming`:
@@ -149,88 +185,120 @@ class User
149
185
  end
150
186
  ```
151
187
 
152
- get attribute value:
188
+ ### I18n Helper Methods
189
+
190
+ #### \*\_text / .text
191
+
192
+ Attribute's I18n text value:
193
+
194
+ ```ruby
195
+ @user.status_text # or @user.status.text
196
+ ```
197
+
198
+ #### values
199
+
200
+ List of possible values for an enumerized attribute:
153
201
 
154
202
  ```ruby
155
- @user.sex_text # or @user.sex.text
203
+ User.status.values # or User.enumerized_attributes[:status].values
204
+ # => ['student', 'employed', 'retired']
156
205
  ```
157
206
 
158
- get all values for enumerized attribute:
207
+ #### I18n text values
208
+
209
+ List of possible I18n text values for an enumerized attribute:
159
210
 
160
211
  ```ruby
161
- User.sex.values # or User.enumerized_attributes[:sex].values
212
+ User.status.values.collect(&:text)
213
+ # => ['Student', 'Employed', 'Retiree']
162
214
  ```
163
215
 
164
- use it with forms (it supports `:only` and `:except` options):
216
+ #### Form example
217
+
218
+ Use it with forms (it supports `:only` and `:except` options):
165
219
 
166
220
  ```erb
167
221
  <%= form_for @user do |f| %>
168
- <%= f.select :sex, User.sex.options %>
222
+ <%= f.select :status, User.status.options %>
169
223
  <% end %>
170
224
  ```
171
225
 
172
- Boolean methods:
226
+ ---
227
+
228
+ ## Boolean Helper Methods
229
+
230
+ ### Basic
173
231
 
174
232
  ```ruby
175
- user.sex = :male
176
- user.sex.male? #=> true
177
- user.sex.female? #=> false
233
+ user.status = :student
234
+ user.status.student? #=> true
235
+ user.status.retired? #=> false
178
236
  ```
179
237
 
180
- Predicate methods:
238
+ ### Predicate Methods
181
239
 
182
240
  ```ruby
183
241
  class User
184
242
  extend Enumerize
185
243
 
186
- enumerize :sex, in: %w(male female), predicates: true
244
+ enumerize :status, in: %w(student employed retired), predicates: true
187
245
  end
188
246
 
189
247
  user = User.new
190
248
 
191
- user.male? # => false
192
- user.female? # => false
249
+ user.student? # => false
250
+ user.employed? # => false
193
251
 
194
- user.sex = 'male'
252
+ user.status = :student
195
253
 
196
- user.male? # => true
197
- user.female? # => false
254
+ user.student? # => true
255
+ user.employed? # => false
198
256
  ```
257
+
199
258
  :warning: If `enumerize` is used with Mongoid, it's not recommended to use `"writer"` as a field value since `writer?` is defined by Mongoid. [See more](https://github.com/brainspec/enumerize/issues/235). :warning:
200
259
 
201
- Using prefix:
260
+ #### Predicate Prefixes
202
261
 
203
262
  ```ruby
204
263
  class User
205
264
  extend Enumerize
206
265
 
207
- enumerize :sex, in: %w(male female), predicates: { prefix: true }
266
+ enumerize :status, in: %w(student employed retired), predicates: { prefix: true }
208
267
  end
209
268
 
210
269
  user = User.new
211
- user.sex = 'female'
212
- user.sex_female? # => true
270
+ user.status = 'student'
271
+ user.status_student? # => true
213
272
  ```
273
+
214
274
  Use `:only` and `:except` options to specify what values create predicate methods for.
215
275
 
276
+ ---
277
+
278
+ ## Optimzations and Tips
279
+
280
+ ### Extendable Module
281
+
216
282
  To make some attributes shared across different classes it's possible to define them in a separate module and then include it into classes:
217
283
 
218
284
  ```ruby
219
- module PersonEnumerations
285
+ module RoleEnumerations
220
286
  extend Enumerize
221
287
 
222
- enumerize :sex, in: %w[male female]
288
+ enumerize :roles, in: %w[user admin]
223
289
  end
224
290
 
225
- class Person
226
- include PersonEnumerations
291
+ class Buyer
292
+ include RoleEnumerations
227
293
  end
228
294
 
229
- class User
230
- include PersonEnumerations
295
+ class Seller
296
+ include RoleEnumerations
231
297
  end
232
298
  ```
233
299
 
300
+ ### Customizing Enumerize Value
301
+
234
302
  It's also possible to store enumerized attribute value using custom values (e.g. integers). You can pass a hash as `:in` option to achieve this:
235
303
 
236
304
  ```ruby
@@ -249,45 +317,49 @@ User.role.find_value(:user).value #=> 1
249
317
  User.role.find_value(:admin).value #=> 2
250
318
  ```
251
319
 
252
- ActiveRecord scopes:
320
+ ### ActiveRecord scopes:
321
+
322
+ #### Basic
253
323
 
254
324
  ```ruby
255
325
  class User < ActiveRecord::Base
256
326
  extend Enumerize
257
- enumerize :sex, :in => [:male, :female], scope: true
258
- enumerize :status, :in => { active: 1, blocked: 2 }, scope: :having_status
327
+ enumerize :role, :in => [:user, :admin], scope: true
328
+ enumerize :status, :in => { student: 1, employed: 2, retired: 3 }, scope: :having_status
259
329
  end
260
330
 
261
- User.with_sex(:female)
262
- # SELECT "users".* FROM "users" WHERE "users"."sex" IN ('female')
331
+ User.with_role(:admin)
332
+ # SELECT "users".* FROM "users" WHERE "users"."role" IN ('admin')
263
333
 
264
- User.without_sex(:male)
265
- # SELECT "users".* FROM "users" WHERE "users"."sex" NOT IN ('male')
334
+ User.without_role(:admin)
335
+ # SELECT "users".* FROM "users" WHERE "users"."role" NOT IN ('admin')
266
336
 
267
- User.having_status(:blocked).with_sex(:male, :female)
268
- # SELECT "users".* FROM "users" WHERE "users"."status" IN (2) AND "users"."sex" IN ('male', 'female')
337
+ User.having_status(:employed).with_role(:user, :admin)
338
+ # SELECT "users".* FROM "users" WHERE "users"."status" IN (2) AND "users"."role" IN ('user', 'admin')
269
339
  ```
270
340
 
271
- Shallow scopes:
341
+ #### Shallow Scopes
272
342
 
273
- Adds named scopes to the class directly
343
+ Adds named scopes to the class directly.
274
344
 
275
345
  ```ruby
276
346
  class User < ActiveRecord::Base
277
347
  extend Enumerize
278
- enumerize :sex, :in => [:male, :female], scope: :shallow
279
- enumerize :status, :in => { active: 1, blocked: 2 }, scope: :shallow
348
+ enumerize :status, :in => [:student, :employed, :retired], scope: :shallow
349
+ enumerize :role, :in => { user: 1, admin: 2 }, scope: :shallow
280
350
  end
281
351
 
282
- User.male
283
- # SELECT "users".* FROM "users" WHERE "users"."sex" = 'male'
352
+ User.student
353
+ # SELECT "users".* FROM "users" WHERE "users"."status" = 'student'
284
354
 
285
- User.active
286
- # SELECT "users".* FROM "users" WHERE "users"."status" = 1
355
+ User.admin
356
+ # SELECT "users".* FROM "users" WHERE "users"."role" = 2
287
357
  ```
288
358
 
289
359
  :warning: It is not possible to define a scope when using the `:multiple` option. :warning:
290
360
 
361
+ ### Array-like Attributes
362
+
291
363
  Array-like attributes with plain ruby objects:
292
364
 
293
365
  ```ruby
@@ -322,22 +394,26 @@ get an array of all text values:
322
394
  Also, the reader method can be overridden, referencing the enumerized attribute value using `super`:
323
395
 
324
396
  ```ruby
325
- def sex
397
+ def status
326
398
  if current_user.admin?
327
- "Super#{super}"
399
+ "Super #{super}"
328
400
  else
329
401
  super
330
402
  end
331
403
  end
332
404
  ```
333
405
 
406
+ ---
407
+
408
+ ## Forms
409
+
334
410
  ### SimpleForm
335
411
 
336
412
  If you are using SimpleForm gem you don't need to specify input type (`:select` by default) and collection:
337
413
 
338
414
  ```erb
339
415
  <%= simple_form_for @user do |f| %>
340
- <%= f.input :sex %>
416
+ <%= f.input :status %>
341
417
  <% end %>
342
418
  ```
343
419
 
@@ -345,7 +421,7 @@ and if you want it as radio buttons:
345
421
 
346
422
  ```erb
347
423
  <%= simple_form_for @user do |f| %>
348
- <%= f.input :sex, :as => :radio_buttons %>
424
+ <%= f.input :status, :as => :radio_buttons %>
349
425
  <% end %>
350
426
  ```
351
427
 
@@ -357,7 +433,7 @@ If you are using Formtastic gem you also don't need to specify input type (`:sel
357
433
 
358
434
  ```erb
359
435
  <%= semantic_form_for @user do |f| %>
360
- <%= f.input :sex %>
436
+ <%= f.input :status %>
361
437
  <% end %>
362
438
  ```
363
439
 
@@ -365,10 +441,14 @@ and if you want it as radio buttons:
365
441
 
366
442
  ```erb
367
443
  <%= semantic_form_for @user do |f| %>
368
- <%= f.input :sex, :as => :radio %>
444
+ <%= f.input :status, :as => :radio %>
369
445
  <% end %>
370
446
  ```
371
447
 
448
+ ---
449
+
450
+ ## Testing
451
+
372
452
  ### RSpec
373
453
 
374
454
  Also you can use builtin RSpec matcher:
@@ -377,14 +457,14 @@ Also you can use builtin RSpec matcher:
377
457
  class User
378
458
  extend Enumerize
379
459
 
380
- enumerize :sex, in: [:male, :female]
460
+ enumerize :status, in: [:student, :employed, :retired]
381
461
  end
382
462
 
383
463
  describe User do
384
- it { should enumerize(:sex) }
464
+ it { should enumerize(:status) }
385
465
 
386
466
  # or with RSpec 3 expect syntax
387
- it { is_expected.to enumerize(:sex) }
467
+ it { is_expected.to enumerize(:status) }
388
468
  end
389
469
  ```
390
470
 
@@ -398,11 +478,11 @@ Use `in` to test usage of the `:in` option.
398
478
  class User
399
479
  extend Enumerize
400
480
 
401
- enumerize :sex, in: [:male, :female]
481
+ enumerize :status, in: [:student, :employed, :retired]
402
482
  end
403
483
 
404
484
  describe User do
405
- it { should enumerize(:sex).in(:male, :female) }
485
+ it { should enumerize(:status).in(:student, :employed, :retired) }
406
486
  end
407
487
  ```
408
488
 
@@ -413,11 +493,11 @@ qualifier.
413
493
  class User
414
494
  extend Enumerize
415
495
 
416
- enumerize :sex, in: { male: 0, female: 1 }
496
+ enumerize :role, in: { user: 0, admin: 1 }
417
497
  end
418
498
 
419
499
  describe User do
420
- it { should enumerize(:sex).in(male: 0, female: 1) }
500
+ it { should enumerize(:role).in(user: 0, admin: 1) }
421
501
  end
422
502
  ```
423
503
 
@@ -429,11 +509,11 @@ Use `with_default` to test usage of the `:default` option.
429
509
  class User
430
510
  extend Enumerize
431
511
 
432
- enumerize :sex, in: [:male, :female], default: :female
512
+ enumerize :role, in: [:user, :admin], default: :user
433
513
  end
434
514
 
435
515
  describe User do
436
- it { should enumerize(:sex).in(:male, :female).with_default(:female) }
516
+ it { should enumerize(:user).in(:user, :admin).with_default(:user) }
437
517
  end
438
518
  ```
439
519
 
@@ -445,11 +525,11 @@ Use `with_i18n_scope` to test usage of the `:i18n_scope` option.
445
525
  class User
446
526
  extend Enumerize
447
527
 
448
- enumerize :sex, in: [:male, :female], i18n_scope: 'sex'
528
+ enumerize :status, in: [:student, :employed, :retired], i18n_scope: 'status'
449
529
  end
450
530
 
451
531
  describe User do
452
- it { should enumerize(:sex).in(:male, :female).with_i18n_scope('sex') }
532
+ it { should enumerize(:status).in(:student, :employed, :retired).with_i18n_scope('status') }
453
533
  end
454
534
  ```
455
535
 
@@ -461,11 +541,11 @@ Use `with_predicates` to test usage of the `:predicates` option.
461
541
  class User
462
542
  extend Enumerize
463
543
 
464
- enumerize :sex, in: [:male, :female], predicates: true
544
+ enumerize :status, in: [:student, :employed, :retired], predicates: true
465
545
  end
466
546
 
467
547
  describe User do
468
- it { should enumerize(:sex).in(:male, :female).with_predicates(true) }
548
+ it { should enumerize(:status).in(:student, :employed, :retired).with_predicates(true) }
469
549
  end
470
550
  ```
471
551
 
@@ -475,11 +555,11 @@ You can text prefixed predicates with the `with_predicates` qualifiers.
475
555
  class User
476
556
  extend Enumerize
477
557
 
478
- enumerize :sex, in: [:male, :female], predicates: { prefix: true }
558
+ enumerize :status, in: [:student, :employed, :retired], predicates: { prefix: true }
479
559
  end
480
560
 
481
561
  describe User do
482
- it { should enumerize(:sex).in(:male, :female).with_predicates(prefix: true) }
562
+ it { should enumerize(:status).in(:student, :employed, :retired).with_predicates(prefix: true) }
483
563
  end
484
564
  ```
485
565
 
@@ -491,25 +571,25 @@ Use `with_scope` to test usage of the `:scope` option.
491
571
  class User
492
572
  extend Enumerize
493
573
 
494
- enumerize :sex, in: [:male, :female], scope: true
574
+ enumerize :status, in: [:student, :employed, :retired], scope: true
495
575
  end
496
576
 
497
577
  describe User do
498
- it { should enumerize(:sex).in(:male, :female).with_scope(true) }
578
+ it { should enumerize(:status).in(:student, :employed, :retired).with_scope(true) }
499
579
  end
500
580
  ```
501
581
 
502
- You can text custom scope with the `with_scope` qualifiers.
582
+ You can test a custom scope with the `with_scope` qualifiers.
503
583
 
504
584
  ```ruby
505
585
  class User
506
586
  extend Enumerize
507
587
 
508
- enumerize :sex, in: [:male, :female], scope: :having_sex
588
+ enumerize :status, in: [:student, :employed], scope: :employable
509
589
  end
510
590
 
511
591
  describe User do
512
- it { should enumerize(:sex).in(:male, :female).with_scope(scope: :having_sex) }
592
+ it { should enumerize(:status).in(:student, :employed, :retired).with_scope(scope: :employable) }
513
593
  end
514
594
  ```
515
595
 
@@ -521,11 +601,11 @@ Use `with_multiple` to test usage of the `:multiple` option.
521
601
  class User
522
602
  extend Enumerize
523
603
 
524
- enumerize :sex, in: [:male, :female], multiple: true
604
+ enumerize :status, in: [:student, :employed, :retired], multiple: true
525
605
  end
526
606
 
527
607
  describe User do
528
- it { should enumerize(:sex).in(:male, :female).with_multiple(true) }
608
+ it { should enumerize(:status).in(:student, :employed, :retired).with_multiple(true) }
529
609
  end
530
610
  ```
531
611
 
@@ -548,8 +628,9 @@ end
548
628
 
549
629
  Enumerize integrates with the following automatically:
550
630
 
551
- * [RailsAdmin](https://github.com/sferik/rails_admin/)
631
+ - [RailsAdmin](https://github.com/sferik/rails_admin/)
552
632
 
633
+ ---
553
634
 
554
635
  ## Contributing
555
636
 
@@ -21,7 +21,11 @@ module Enumerize
21
21
  require 'enumerize/hooks/uniqueness'
22
22
 
23
23
  unless options[:multiple]
24
- if ::ActiveRecord.version >= ::Gem::Version.new("6.1.0.alpha")
24
+ if ::ActiveRecord.version >= ::Gem::Version.new("7.0.0.alpha")
25
+ attribute(name) do |subtype|
26
+ Type.new(enumerized_attributes[name], subtype)
27
+ end
28
+ elsif ::ActiveRecord.version >= ::Gem::Version.new("6.1.0.alpha")
25
29
  decorate_attribute_type(name.to_s) do |subtype|
26
30
  Type.new(enumerized_attributes[name], subtype)
27
31
  end
@@ -65,7 +69,7 @@ module Enumerize
65
69
  reloaded.class.enumerized_attributes.each do |attr|
66
70
  begin
67
71
  # Checks first if the enumerized attribute is in ActiveRecord::Store
68
- store_attr, _ = reloaded.class.stored_attributes.detect do |store_attr, keys|
72
+ store_attr, _ = reloaded.class.stored_attributes.detect do |_store_attr, keys|
69
73
  keys.include?(attr.name)
70
74
  end
71
75
 
@@ -42,6 +42,10 @@ module Enumerize
42
42
  define_singleton_method(value_obj) do
43
43
  where(attribute_name => value_obj.value)
44
44
  end
45
+
46
+ define_singleton_method("not_#{value_obj}") do
47
+ where.not(attribute_name => value_obj.value)
48
+ end
45
49
  end
46
50
  end
47
51
  end
@@ -39,6 +39,10 @@ module Enumerize
39
39
  define_singleton_method(value_obj) do
40
40
  self.in(attribute_name => value_obj.value)
41
41
  end
42
+
43
+ define_singleton_method("not_#{value_obj}") do
44
+ self.not_in(attribute_name => value_obj.value)
45
+ end
42
46
  end
43
47
  end
44
48
  end
@@ -45,6 +45,10 @@ module Enumerize
45
45
  def_dataset_method(value_obj) do
46
46
  where(attribute_name => value_obj.value.to_s)
47
47
  end
48
+
49
+ def_dataset_method("not_#{value_obj}") do
50
+ exclude(attribute_name => value_obj.value.to_s)
51
+ end
48
52
  end
49
53
  end
50
54
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Enumerize
4
- VERSION = '2.4.0'
4
+ VERSION = '2.5.0'
5
5
  end