enumerate_it 1.3.1 → 1.4.0.rc1
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +12 -0
- data/.travis.yml +4 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +10 -10
- data/README.md +328 -341
- data/enumerate_it.png +0 -0
- data/gemfiles/rails_3.0.gemfile +1 -1
- data/gemfiles/rails_3.1.gemfile +1 -1
- data/gemfiles/rails_3.2.gemfile +1 -1
- data/gemfiles/rails_4.0.gemfile +1 -1
- data/gemfiles/rails_4.1.gemfile +1 -1
- data/gemfiles/rails_4.2.gemfile +1 -1
- data/gemfiles/rails_5.0.gemfile +1 -1
- data/lib/enumerate_it/base.rb +2 -2
- data/lib/enumerate_it/version.rb +1 -1
- data/lib/generators/enumerate_it/enum/enum_generator.rb +1 -1
- data/spec/enumerate_it/base_spec.rb +10 -2
- data/spec/support/test_classes.rb +8 -18
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75cf6c3f112a2575798bcf189871687e81a46e19
|
4
|
+
data.tar.gz: 31c1f6b460883f3b152c73730e0fed10c9c037e3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b6c4da4b694618f9eedc01f3234469df4d8192beaa431adac5f7e0f0168858e3a6f311f470b10e0b45cc6dcbdbb9662f164cb4193277e9856c9115d2c1dacb75
|
7
|
+
data.tar.gz: 5bfe4f685fc279a834b23946aa25f1aff2435f0dfe3357bf3b4af213c87a02e31de98e81dcd1a362ca21c5cf0f22a88309338a98a00848166844657a81265e66
|
data/.rubocop.yml
CHANGED
@@ -38,3 +38,15 @@ Style/MultilineMethodCallIndentation:
|
|
38
38
|
Style/PredicateName:
|
39
39
|
Exclude:
|
40
40
|
- 'lib/enumerate_it/class_methods.rb'
|
41
|
+
|
42
|
+
Style/GuardClause:
|
43
|
+
MinBodyLength: 3
|
44
|
+
|
45
|
+
RSpec/MultipleExpectations:
|
46
|
+
Enabled: false
|
47
|
+
|
48
|
+
RSpec/NestedGroups:
|
49
|
+
Enabled: false
|
50
|
+
|
51
|
+
RSpec/MessageExpectation:
|
52
|
+
Enabled: false
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
enumerate_it (1.
|
4
|
+
enumerate_it (1.4.0.rc1)
|
5
5
|
activesupport (>= 3.0.0)
|
6
6
|
|
7
7
|
GEM
|
8
|
-
remote:
|
8
|
+
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
10
|
activesupport (5.0.0.1)
|
11
11
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
@@ -22,8 +22,8 @@ GEM
|
|
22
22
|
diff-lcs (1.2.5)
|
23
23
|
i18n (0.7.0)
|
24
24
|
method_source (0.8.2)
|
25
|
-
minitest (5.9.
|
26
|
-
parser (2.3.1.
|
25
|
+
minitest (5.9.1)
|
26
|
+
parser (2.3.1.4)
|
27
27
|
ast (~> 2.2)
|
28
28
|
powerpack (0.1.1)
|
29
29
|
pry (0.10.4)
|
@@ -31,12 +31,12 @@ GEM
|
|
31
31
|
method_source (~> 0.8.1)
|
32
32
|
slop (~> 3.4)
|
33
33
|
rainbow (2.1.0)
|
34
|
-
rake (11.
|
34
|
+
rake (11.3.0)
|
35
35
|
rspec (3.5.0)
|
36
36
|
rspec-core (~> 3.5.0)
|
37
37
|
rspec-expectations (~> 3.5.0)
|
38
38
|
rspec-mocks (~> 3.5.0)
|
39
|
-
rspec-core (3.5.
|
39
|
+
rspec-core (3.5.4)
|
40
40
|
rspec-support (~> 3.5.0)
|
41
41
|
rspec-expectations (3.5.0)
|
42
42
|
diff-lcs (>= 1.2.0, < 2.0)
|
@@ -45,13 +45,13 @@ GEM
|
|
45
45
|
diff-lcs (>= 1.2.0, < 2.0)
|
46
46
|
rspec-support (~> 3.5.0)
|
47
47
|
rspec-support (3.5.0)
|
48
|
-
rubocop (0.
|
48
|
+
rubocop (0.44.1)
|
49
49
|
parser (>= 2.3.1.1, < 3.0)
|
50
50
|
powerpack (~> 0.1)
|
51
51
|
rainbow (>= 1.99.1, < 3.0)
|
52
52
|
ruby-progressbar (~> 1.7)
|
53
53
|
unicode-display_width (~> 1.0, >= 1.0.1)
|
54
|
-
rubocop-rspec (1.
|
54
|
+
rubocop-rspec (1.7.0)
|
55
55
|
rubocop (>= 0.42.0)
|
56
56
|
ruby-progressbar (1.8.1)
|
57
57
|
slop (3.6.0)
|
@@ -59,7 +59,7 @@ GEM
|
|
59
59
|
thread_safe (0.3.5)
|
60
60
|
tzinfo (1.2.2)
|
61
61
|
thread_safe (~> 0.1)
|
62
|
-
unicode-display_width (1.1.
|
62
|
+
unicode-display_width (1.1.1)
|
63
63
|
|
64
64
|
PLATFORMS
|
65
65
|
ruby
|
@@ -75,4 +75,4 @@ DEPENDENCIES
|
|
75
75
|
rubocop-rspec
|
76
76
|
|
77
77
|
BUNDLED WITH
|
78
|
-
1.
|
78
|
+
1.13.2
|
data/README.md
CHANGED
@@ -1,429 +1,401 @@
|
|
1
|
-
|
1
|
+

|
2
|
+
|
3
|
+
Ruby Enumerations
|
2
4
|
|
3
5
|
[](https://travis-ci.org/lucascaton/enumerate_it)
|
4
6
|
[](https://rubygems.org/gems/enumerate_it)
|
7
|
+
[](https://codeclimate.com/github/lucascaton/enumerate_it)
|
8
|
+
[](https://github.com/lucascaton/enumerate_it/releases)
|
5
9
|
|
6
|
-
|
7
|
-
* **Maintainer:** Lucas Caton
|
10
|
+
**EnumerateIt** helps you to declare and use enumerations in a very simple and flexible way.
|
8
11
|
|
9
|
-
|
12
|
+
### Why would I want a gem if Rails already has native enumerations support?
|
10
13
|
|
11
|
-
|
12
|
-
|
13
|
-
application around a legacy database and this database was filled with those
|
14
|
-
small, unchangeable tables used to create foreign key constraints everywhere.
|
14
|
+
Firstly, **EnumerateIt** works amazingly well along with **Rails** but it is not required!
|
15
|
+
It means you can add it to any **Ruby** project! 😀
|
15
16
|
|
16
|
-
|
17
|
+
Secondly, Rails' enumerations has a problem:
|
18
|
+
[`ActiveRecord::Enum`](http://edgeapi.rubyonrails.org/classes/ActiveRecord/Enum.html) uses
|
19
|
+
`integers` instead of `strings`, which means that if you change your enumeration list oder in your
|
20
|
+
model, your database will no longer be consistent.
|
21
|
+
Database storage pricing is not a problem nowadays, so it's recommended to use `strings` columns.
|
17
22
|
|
18
|
-
|
23
|
+
- [Installation](#installation)
|
24
|
+
- [Using with Rails](#using-with-rails)
|
25
|
+
- [Creating enumerations](#creating-enumerations)
|
26
|
+
- [Sorting enumerations](#sorting-enumerations)
|
27
|
+
- [Using enumerations](#using-enumerations)
|
28
|
+
- [I18n](#i18n)
|
29
|
+
- [Using enumerations to handle a legacy database](#using-enumerations-to-handle-a-legacy-database)
|
30
|
+
- [FAQ](#faq)
|
31
|
+
- [Changelog](#changelog)
|
19
32
|
|
20
|
-
|
21
|
-
-------------+---------------+-----------
|
22
|
-
code | character(1) | not null
|
23
|
-
description | character(11) |
|
33
|
+
## Installation
|
24
34
|
|
25
|
-
|
26
|
-
|
35
|
+
```bash
|
36
|
+
gem install enumerate_it
|
37
|
+
```
|
27
38
|
|
28
|
-
|
39
|
+
## Using with Rails
|
29
40
|
|
30
|
-
|
31
|
-
-------+--------------
|
32
|
-
1 | Single
|
33
|
-
2 | Married
|
34
|
-
3 | Widow
|
35
|
-
4 | Divorced
|
41
|
+
Add the gem to your Gemfile:
|
36
42
|
|
37
|
-
|
38
|
-
|
43
|
+
```ruby
|
44
|
+
gem 'enumerate_it'
|
45
|
+
```
|
39
46
|
|
40
|
-
|
41
|
-
managing this values in my tests was very hard. Doing database joins just to
|
42
|
-
get the description of some value was absurd. And, more than this, referencing
|
43
|
-
them in my code using magic numbers was terrible and meaningless: What does it
|
44
|
-
mean when we say that someone or something is '2'?
|
47
|
+
Run the install generator:
|
45
48
|
|
46
|
-
|
49
|
+
```bash
|
50
|
+
rails generate enumerate_it:install
|
51
|
+
```
|
47
52
|
|
48
|
-
|
53
|
+
There is also a Rails Generator which generates enumerations and their locale files:
|
49
54
|
|
50
|
-
|
55
|
+
```bash
|
56
|
+
rails generate enumerate_it:enum --help
|
57
|
+
```
|
51
58
|
|
52
59
|
## Creating enumerations
|
53
60
|
|
54
61
|
Enumerations are created as classes and you should put them inside `app/enumerations` folder.
|
55
62
|
|
63
|
+
You can pass an array of symbols, so that the respective value for each symbol will be the
|
64
|
+
stringified version of the symbol itself:
|
65
|
+
|
56
66
|
```ruby
|
57
67
|
class RelationshipStatus < EnumerateIt::Base
|
58
68
|
associate_values(
|
59
|
-
single
|
60
|
-
married
|
61
|
-
|
62
|
-
divorced: [4, 'Divorced']
|
69
|
+
:single,
|
70
|
+
:married,
|
71
|
+
:divorced
|
63
72
|
)
|
64
73
|
end
|
65
74
|
```
|
66
75
|
|
67
76
|
This will create some nice stuff:
|
68
77
|
|
69
|
-
*
|
78
|
+
* Each enumeration's value will turn into a constant:
|
70
79
|
|
71
|
-
|
72
|
-
|
73
|
-
|
80
|
+
```ruby
|
81
|
+
RelationshipStatus::SINGLE
|
82
|
+
# => 'single'
|
74
83
|
|
75
|
-
|
76
|
-
|
77
|
-
|
84
|
+
RelationshipStatus::MARRIED
|
85
|
+
#=> 'married'
|
86
|
+
```
|
78
87
|
|
79
|
-
*
|
88
|
+
* You can retrieve a list with all the enumeration codes:
|
80
89
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
90
|
+
```ruby
|
91
|
+
RelationshipStatus.list
|
92
|
+
#=> ['divorced', 'married', 'single']
|
93
|
+
```
|
85
94
|
|
86
|
-
*
|
87
|
-
'select_tag', etc family of Rails helpers.
|
95
|
+
* You can retrieve a JSON with all the enumeration codes:
|
88
96
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
97
|
+
```ruby
|
98
|
+
RelationshipStatus.to_json
|
99
|
+
#=> "[{\"value\":\"divorced\",\"label\":\"Divorced\"},{\"value\":\"married\", ...
|
100
|
+
```
|
93
101
|
|
94
|
-
*
|
102
|
+
* You can get an array of options, ready to use with the 'select',
|
103
|
+
'select_tag', etc family of Rails helpers.
|
95
104
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
105
|
+
```ruby
|
106
|
+
RelationshipStatus.to_a
|
107
|
+
#=> [['Divorced', 'divorced'], ['Married', 'married'], ['Single', 'single']]
|
108
|
+
```
|
100
109
|
|
101
|
-
*
|
110
|
+
* You can retrieve a list with values for a group of enumeration constants.
|
102
111
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
112
|
+
```ruby
|
113
|
+
RelationshipStatus.values_for %w(MARRIED SINGLE)
|
114
|
+
#=> ['married', 'single']
|
115
|
+
```
|
107
116
|
|
108
|
-
*
|
117
|
+
* You can retrieve the value for a specific enumeration constant:
|
109
118
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
119
|
+
```ruby
|
120
|
+
RelationshipStatus.value_for('MARRIED')
|
121
|
+
#=> 'married'
|
122
|
+
```
|
114
123
|
|
115
|
-
*
|
124
|
+
* You can retrieve the symbol used to declare a specific enumeration value:
|
116
125
|
|
117
|
-
|
118
|
-
|
119
|
-
|
126
|
+
```ruby
|
127
|
+
RelationshipStatus.key_for(RelationshipStatus::MARRIED)
|
128
|
+
#=> :married
|
129
|
+
```
|
120
130
|
|
121
|
-
*
|
131
|
+
* You can iterate over the list of the enumeration's values:
|
122
132
|
|
123
|
-
|
124
|
-
|
125
|
-
|
133
|
+
```ruby
|
134
|
+
RelationshipStatus.each_value { |value| ... }
|
135
|
+
```
|
126
136
|
|
127
|
-
*
|
137
|
+
* You can iterate over the list of the enumeration's translations:
|
128
138
|
|
129
|
-
|
130
|
-
|
131
|
-
|
139
|
+
```ruby
|
140
|
+
RelationshipStatus.each_translation { |translation| ... }
|
141
|
+
```
|
132
142
|
|
133
|
-
*
|
143
|
+
* You can also retrieve all the translations of the enumeration:
|
134
144
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
```
|
145
|
+
```ruby
|
146
|
+
RelationshipStatus.translations
|
147
|
+
```
|
139
148
|
|
140
|
-
*
|
149
|
+
* You can ask for the enumeration's length:
|
141
150
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
151
|
+
```ruby
|
152
|
+
RelationshipStatus.length
|
153
|
+
#=> 3
|
154
|
+
```
|
146
155
|
|
147
|
-
|
156
|
+
### Sorting enumerations
|
148
157
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
```ruby
|
153
|
-
class RelationshipStatus < EnumerateIt::Base
|
154
|
-
associate_values :married, :single
|
155
|
-
end
|
156
|
-
|
157
|
-
RelationshipStatus::MARRIED
|
158
|
-
#=> "married"
|
159
|
-
```
|
160
|
-
|
161
|
-
* Passing hashes where the value for each key/pair does not include a
|
162
|
-
translation. In this case, the I18n feature will be used (more on this
|
163
|
-
below):
|
164
|
-
|
165
|
-
```ruby
|
166
|
-
class RelationshipStatus < EnumerateIt::Base
|
167
|
-
associate_values married: 1, single: 2
|
168
|
-
end
|
169
|
-
```
|
170
|
-
|
171
|
-
### Defining a default sort mode
|
172
|
-
|
173
|
-
When calling methods like `to_a`, `to_json` and `list`, the returned values
|
174
|
-
will be sorted using the translation for each one of the enumeration values.
|
175
|
-
If you want to overwrite the default sort mode, you can use the `sort_by` class
|
176
|
-
method.
|
158
|
+
When calling methods like `to_a`, `to_json` and `list`, the returned values will be sorted using
|
159
|
+
the translation for each one of the enumeration values. If you want to overwrite the default sort
|
160
|
+
mode, you can use the `sort_by` class method.
|
177
161
|
|
178
162
|
```ruby
|
179
163
|
class RelationshipStatus < EnumerateIt::Base
|
180
164
|
associate_values married: 1, single: 2
|
181
165
|
|
182
|
-
sort_by :
|
166
|
+
sort_by :translation
|
183
167
|
end
|
184
168
|
```
|
185
169
|
|
186
170
|
The `sort_by` methods accept one of the following values:
|
187
171
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
172
|
+
| Value | Behavior |
|
173
|
+
| :------------- | :------------------------------------------------------------------------------------------- |
|
174
|
+
| `:none` | The default behavior, will return values in order that was passed to `associate_values` call |
|
175
|
+
| `:translation` | will sort the returned values based on translations |
|
176
|
+
| `:name` | Will sort the returned values based on the name of each enumeration option |
|
192
177
|
|
193
178
|
## Using enumerations
|
194
179
|
|
195
|
-
The cool part is that you can use these enumerations with any class, be it an
|
196
|
-
|
180
|
+
The cool part is that you can use these enumerations with any class, be it an `ActiveRecord`
|
181
|
+
instance or not.
|
197
182
|
|
198
183
|
```ruby
|
199
184
|
class Person
|
200
185
|
extend EnumerateIt
|
201
186
|
attr_accessor :relationship_status
|
202
187
|
|
203
|
-
has_enumeration_for :relationship_status
|
188
|
+
has_enumeration_for :relationship_status
|
204
189
|
end
|
205
190
|
```
|
206
191
|
|
207
|
-
|
208
|
-
|
192
|
+
> **Note:** **EnumerateIt** will try to load an enumeration class based on the camelized attribute
|
193
|
+
> name. If you have a different name, you can specify it by using the `with` option:
|
194
|
+
>
|
195
|
+
> `has_enumeration_for :relationship_status, with: RelationshipStatus`
|
209
196
|
|
210
197
|
This will create:
|
211
198
|
|
212
|
-
*
|
213
|
-
|
214
|
-
```ruby
|
215
|
-
p = Person.new
|
216
|
-
p.relationship_status = RelationshipStatus::DIVORCED
|
217
|
-
p.relationship_status_humanize
|
218
|
-
#=> 'Divorced'
|
219
|
-
```
|
220
|
-
|
221
|
-
* If you don't supply a humanized string to represent an option, EnumerateIt
|
222
|
-
will use a 'humanized' version of the hash's key to humanize the
|
223
|
-
attribute's value:
|
224
|
-
|
225
|
-
```ruby
|
226
|
-
class RelationshipStatus < EnumerateIt::Base
|
227
|
-
associate_values(
|
228
|
-
married: 1,
|
229
|
-
single: 2
|
230
|
-
)
|
231
|
-
end
|
199
|
+
* A "humanized" version of the hash's key to humanize the attribute's value:
|
232
200
|
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
201
|
+
```ruby
|
202
|
+
p = Person.new
|
203
|
+
p.relationship_status = RelationshipStatus::DIVORCED
|
204
|
+
p.relationship_status_humanize
|
205
|
+
#=> 'Divorced'
|
206
|
+
```
|
238
207
|
|
239
|
-
*
|
240
|
-
|
208
|
+
* A translation for your options, if you include a locale to represent it
|
209
|
+
(see more in the [#i18n](I18n section):
|
241
210
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
211
|
+
```ruby
|
212
|
+
p = Person.new
|
213
|
+
p.relationship_status = RelationshipStatus::DIVORCED
|
214
|
+
p.relationship_status_humanize
|
215
|
+
#=> 'Divorciado'
|
216
|
+
```
|
246
217
|
|
247
|
-
*
|
248
|
-
method for each enumeration option (this option defaults to false):
|
218
|
+
* The associated enumerations, which can be retrieved with the `enumerations` class method:
|
249
219
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
220
|
+
```ruby
|
221
|
+
Person.enumerations
|
222
|
+
#=> { relationship_status: RelationshipStatus }
|
223
|
+
```
|
254
224
|
|
255
|
-
|
256
|
-
p.relationship_status = RelationshipStatus::MARRIED
|
225
|
+
* A helper method for each enumeration option, if you pass the `create_helpers` option as `true`:
|
257
226
|
|
258
|
-
|
259
|
-
|
227
|
+
```ruby
|
228
|
+
class Person < ActiveRecord::Base
|
229
|
+
has_enumeration_for :relationship_status, with: RelationshipStatus, create_helpers: true
|
230
|
+
end
|
260
231
|
|
261
|
-
|
262
|
-
|
263
|
-
```
|
232
|
+
p = Person.new
|
233
|
+
p.relationship_status = RelationshipStatus::MARRIED
|
264
234
|
|
265
|
-
|
266
|
-
|
267
|
-
the enumerations used share the same constants.
|
235
|
+
p.married?
|
236
|
+
#=> true
|
268
237
|
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
create_helpers: { prefix: true }
|
273
|
-
end
|
238
|
+
p.divorced?
|
239
|
+
#=> false
|
240
|
+
```
|
274
241
|
|
275
|
-
|
276
|
-
|
242
|
+
It's also possible to "namespace" the created helper methods, passing a hash to the `create_helpers`
|
243
|
+
option. This can be useful when two or more of the enumerations used share the same constants:
|
277
244
|
|
278
|
-
|
279
|
-
|
245
|
+
```ruby
|
246
|
+
class Person < ActiveRecord::Base
|
247
|
+
has_enumeration_for :relationship_status,
|
248
|
+
with: RelationshipStatus, create_helpers: { prefix: true }
|
249
|
+
end
|
280
250
|
|
281
|
-
|
282
|
-
|
283
|
-
```
|
251
|
+
p = Person.new
|
252
|
+
p.relationship_status = RelationshipStatus::MARRIED
|
284
253
|
|
285
|
-
|
286
|
-
|
254
|
+
p.relationship_status_married?
|
255
|
+
#=> true
|
287
256
|
|
288
|
-
|
289
|
-
|
290
|
-
|
257
|
+
p.relationship_status_divoced?
|
258
|
+
#=> false
|
259
|
+
```
|
291
260
|
|
292
|
-
|
293
|
-
|
294
|
-
"At home with the kids"
|
295
|
-
end
|
296
|
-
end
|
261
|
+
You can define polymorphic behavior for the enumeration values, so you can define a class for each
|
262
|
+
of them:
|
297
263
|
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
264
|
+
```ruby
|
265
|
+
class RelationshipStatus < EnumerateIt::Base
|
266
|
+
associate_values :married, :single
|
267
|
+
|
268
|
+
class Married
|
269
|
+
def saturday_night
|
270
|
+
'At home with the kids'
|
302
271
|
end
|
303
272
|
end
|
304
273
|
|
305
|
-
class
|
306
|
-
|
307
|
-
|
274
|
+
class Single
|
275
|
+
def saturday_night
|
276
|
+
'Party Hard!'
|
277
|
+
end
|
308
278
|
end
|
279
|
+
end
|
280
|
+
|
281
|
+
class Person < ActiveRecord::Base
|
282
|
+
has_enumeration_for :relationship_status,
|
283
|
+
with: RelationshipStatus, create_helpers: { polymorphic: true }
|
284
|
+
end
|
309
285
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
286
|
+
p = Person.new
|
287
|
+
p.relationship_status = RelationshipStatus::MARRIED
|
288
|
+
p.relationship_status_object.saturday_night
|
289
|
+
#=> 'At home with the kids'
|
314
290
|
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
291
|
+
p.relationship_status = RelationshipStatus::SINGLE
|
292
|
+
p.relationship_status_object.saturday_night
|
293
|
+
#=> 'Party Hard!'
|
294
|
+
```
|
319
295
|
|
320
|
-
|
296
|
+
You can also change the suffix `_object`, using the `suffix` option:
|
321
297
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
298
|
+
```ruby
|
299
|
+
class Person < ActiveRecord::Base
|
300
|
+
has_enumeration_for :relationship_status,
|
301
|
+
with: RelationshipStatus, create_helpers: { polymorphic: { suffix: '_mode' } }
|
302
|
+
end
|
327
303
|
|
328
|
-
|
329
|
-
|
304
|
+
p.relationship_status_mode.saturday_night
|
305
|
+
```
|
330
306
|
|
331
|
-
|
332
|
-
|
307
|
+
The `create_helpers` also creates some mutator helper methods, that can be used to change the
|
308
|
+
attribute's value.
|
333
309
|
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
end
|
310
|
+
```ruby
|
311
|
+
p = Person.new
|
312
|
+
p.married!
|
338
313
|
|
339
|
-
|
340
|
-
|
314
|
+
p.married?
|
315
|
+
#=> true
|
316
|
+
```
|
341
317
|
|
342
|
-
|
343
|
-
#=> true
|
318
|
+
* A scope method for each enumeration option if you pass the `create_scopes` option as `true`:
|
344
319
|
|
345
|
-
|
346
|
-
|
347
|
-
|
320
|
+
```ruby
|
321
|
+
class Person < ActiveRecord::Base
|
322
|
+
has_enumeration_for :relationship_status, with: RelationshipStatus, create_scopes: true
|
323
|
+
end
|
348
324
|
|
349
|
-
|
350
|
-
|
325
|
+
Person.married.to_sql
|
326
|
+
#=> SELECT "users".* FROM "users" WHERE "users"."relationship_status" = "married"
|
327
|
+
```
|
351
328
|
|
352
|
-
|
353
|
-
class Person < ActiveRecord::Base
|
354
|
-
has_enumeration_for :relationship_status, with: RelationshipStatus, create_scopes: true
|
355
|
-
end
|
329
|
+
The `:create_scopes` also accepts :prefix option.
|
356
330
|
|
357
|
-
|
358
|
-
|
359
|
-
|
331
|
+
```ruby
|
332
|
+
class Person < ActiveRecord::Base
|
333
|
+
has_enumeration_for :relationship_status,
|
334
|
+
with: RelationshipStatus, create_scopes: { prefix: true }
|
335
|
+
end
|
360
336
|
|
361
|
-
|
337
|
+
Person.relationship_status_married.to_sql
|
338
|
+
```
|
362
339
|
|
363
|
-
|
364
|
-
|
365
|
-
has_enumeration_for :relationship_status, with: RelationshipStatus,
|
366
|
-
create_scopes: { prefix: true }
|
367
|
-
end
|
340
|
+
* An inclustion validation (if your class can manage validations and responds to
|
341
|
+
`validates_inclusion_of`):
|
368
342
|
|
369
|
-
|
370
|
-
|
343
|
+
```ruby
|
344
|
+
class Person < ActiveRecord::Base
|
345
|
+
has_enumeration_for :relationship_status, with: RelationshipStatus
|
346
|
+
end
|
371
347
|
|
372
|
-
|
373
|
-
|
348
|
+
p = Person.new(relationship_status: 'invalid')
|
349
|
+
p.valid?
|
350
|
+
#=> false
|
351
|
+
p.errors[:relationship_status]
|
352
|
+
#=> 'is not included in the list'
|
353
|
+
```
|
374
354
|
|
375
|
-
|
376
|
-
|
377
|
-
has_enumeration_for :relationship_status, with: RelationshipStatus
|
378
|
-
end
|
355
|
+
* An presence validation (if your class can manage validations and responds to
|
356
|
+
`validates_presence_of` and you pass the `required` options as `true`):
|
379
357
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
#=> "is not included in the list"
|
385
|
-
```
|
358
|
+
```ruby
|
359
|
+
class Person < ActiveRecord::Base
|
360
|
+
has_enumeration_for :relationship_status, required: true
|
361
|
+
end
|
386
362
|
|
387
|
-
|
388
|
-
|
389
|
-
|
363
|
+
p = Person.new relationship_status: nil
|
364
|
+
p.valid?
|
365
|
+
#=> false
|
366
|
+
p.errors[:relationship_status]
|
367
|
+
#=> "can't be blank"
|
368
|
+
```
|
390
369
|
|
391
|
-
|
392
|
-
class Person < ActiveRecord::Base
|
393
|
-
has_enumeration_for :relationship_status, required: true
|
394
|
-
end
|
370
|
+
If you pass the `skip_validation` option as `true`, it will not create any validations:
|
395
371
|
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
#=> "can't be blank"
|
401
|
-
```
|
372
|
+
```ruby
|
373
|
+
class Person < ActiveRecord::Base
|
374
|
+
has_enumeration_for :relationship_status, with: RelationshipStatus, skip_validation: true
|
375
|
+
end
|
402
376
|
|
403
|
-
|
377
|
+
p = Person.new(relationship_status: 'invalid')
|
378
|
+
p.valid?
|
379
|
+
#=> true
|
380
|
+
```
|
404
381
|
|
405
|
-
|
406
|
-
|
407
|
-
has_enumeration_for :relationship_status, with: RelationshipStatus, skip_validation: true
|
408
|
-
end
|
382
|
+
Remember that you can add validations to any kind of class and not only to those derived from
|
383
|
+
`ActiveRecord::Base`.
|
409
384
|
|
410
|
-
|
411
|
-
p.valid?
|
412
|
-
#=> true
|
413
|
-
```
|
385
|
+
### Why to define enumerations outside the class that uses them?
|
414
386
|
|
415
|
-
|
416
|
-
|
387
|
+
* It's clearer.
|
388
|
+
* You can add behaviour to the enumeration class.
|
389
|
+
* You can reuse the enumeration inside other classes.
|
417
390
|
|
418
391
|
## I18n
|
419
392
|
|
420
|
-
I18n lookup is provided on both `_humanized` and `Enumeration#to_a` methods,
|
421
|
-
|
422
|
-
`enumerations.<enumeration_name>.<key>`:
|
393
|
+
I18n lookup is provided on both `_humanized` and `Enumeration#to_a` methods, given the hash key is
|
394
|
+
a Symbol. The I18n strings are located on `enumerations.<enumeration_name>.<key>`:
|
423
395
|
|
424
396
|
```yaml
|
425
397
|
# Your locale file
|
426
|
-
pt:
|
398
|
+
pt-BR:
|
427
399
|
enumerations:
|
428
400
|
relationship_status:
|
429
401
|
married: Casado
|
@@ -432,9 +404,8 @@ pt:
|
|
432
404
|
```ruby
|
433
405
|
class RelationshipStatus < EnumerateIt::Base
|
434
406
|
associate_values(
|
435
|
-
married
|
436
|
-
single
|
437
|
-
divorced: [3, "He's divorced"]
|
407
|
+
:married,
|
408
|
+
:single
|
438
409
|
)
|
439
410
|
end
|
440
411
|
|
@@ -444,79 +415,95 @@ p.relationship_status_humanize
|
|
444
415
|
#=> 'Casado'
|
445
416
|
|
446
417
|
p.relationship_status = RelationshipStatus::SINGLE
|
447
|
-
p.relationship_status_humanize #
|
418
|
+
p.relationship_status_humanize # Non-existent key
|
448
419
|
#=> 'Single'
|
449
|
-
|
450
|
-
p.relationship_status = RelationshipStatus::DIVORCED
|
451
|
-
p.relationship_status_humanize # uses the provided string
|
452
|
-
#=> 'He's divorced'
|
453
420
|
```
|
454
421
|
|
455
422
|
You can also translate specific values:
|
456
423
|
|
457
424
|
```ruby
|
458
|
-
RelationshipStatus
|
425
|
+
status = RelationshipStatus::MARRIED
|
426
|
+
RelationshipStatus.t(status)
|
459
427
|
#=> 'Casado'
|
460
428
|
```
|
461
429
|
|
462
|
-
##
|
430
|
+
## Using enumerations to handle a legacy database
|
463
431
|
|
464
|
-
|
465
|
-
|
466
|
-
|
432
|
+
**EnumerateIt** can help you to build a Rails application around a legacy database which was filled
|
433
|
+
with those small and unchangeable tables used to create foreign key constraints everywhere, like the
|
434
|
+
following example:
|
467
435
|
|
468
|
-
|
436
|
+
```sql
|
437
|
+
Table "public.relationship_status"
|
469
438
|
|
470
|
-
|
439
|
+
Column | Type | Modifiers
|
440
|
+
-------------+---------------+-----------
|
441
|
+
code | character(1) | not null
|
442
|
+
description | character(11) |
|
471
443
|
|
472
|
-
|
473
|
-
|
474
|
-
```
|
444
|
+
Indexes:
|
445
|
+
"relationship_status_pkey" PRIMARY KEY, btree (code)
|
475
446
|
|
476
|
-
*
|
447
|
+
SELECT * FROM relationship_status;
|
477
448
|
|
478
|
-
|
479
|
-
|
480
|
-
|
449
|
+
code | description
|
450
|
+
---- +--------------
|
451
|
+
1 | Single
|
452
|
+
2 | Married
|
453
|
+
3 | Divorced
|
454
|
+
```
|
481
455
|
|
482
|
-
|
483
|
-
`
|
456
|
+
You might also have something like a `users` table with a `relationship_status` column and a foreign
|
457
|
+
key pointing to the `relationship_status` table.
|
484
458
|
|
485
|
-
|
486
|
-
|
459
|
+
While this is a good thing from the database normalization perspective, managing these values in
|
460
|
+
tests is very hard. Doing database joins just to get the description of some value is absurd.
|
461
|
+
And, more than this, referencing them in the code using magic numbers was terrible and meaningless:
|
462
|
+
What does it mean when we say that someone or something is `2`?
|
487
463
|
|
488
|
-
|
489
|
-
|
464
|
+
In this case, you can pass a hash:
|
465
|
+
|
466
|
+
```ruby
|
467
|
+
class RelationshipStatus < EnumerateIt::Base
|
468
|
+
associate_values(
|
469
|
+
single: 1,
|
470
|
+
married: 2,
|
471
|
+
divorced: 3
|
472
|
+
)
|
473
|
+
end
|
490
474
|
```
|
491
475
|
|
492
|
-
|
476
|
+
```ruby
|
477
|
+
RelationshipStatus::MARRIED
|
478
|
+
#=> 2
|
479
|
+
```
|
493
480
|
|
494
|
-
|
481
|
+
You can also sort it by its value: `sort_by :value`.
|
495
482
|
|
496
|
-
##
|
483
|
+
## FAQ
|
497
484
|
|
498
|
-
|
499
|
-
find one that worked both with strings and integers as the enumerations'
|
500
|
-
codes. I had both situations in my legacy database.
|
485
|
+
#### What versions of Ruby and Rails are supported?
|
501
486
|
|
502
|
-
|
487
|
+
Please check out [travis config file](https://github.com/lucascaton/enumerate_it/blob/master/.travis.yml).
|
503
488
|
|
504
|
-
|
505
|
-
|
506
|
-
|
489
|
+
#### Can I set a value to always be at the end of a sorted list?
|
490
|
+
|
491
|
+
Yes, please see [issue #60](https://github.com/lucascaton/enumerate_it/issues/60).
|
492
|
+
|
493
|
+
## Changelog
|
494
|
+
|
495
|
+
Changes are maintained under [Releases](https://github.com/lucascaton/enumerate_it/releases).
|
507
496
|
|
508
497
|
## Note on Patches/Pull Requests
|
509
498
|
|
510
|
-
*
|
511
|
-
*
|
512
|
-
*
|
513
|
-
|
514
|
-
*
|
515
|
-
*
|
516
|
-
|
517
|
-
I can ignore when I pull)
|
518
|
-
* Send me a pull request. Bonus points for topic branches.
|
499
|
+
* Fork the project.
|
500
|
+
* Make your feature addition or bug fix.
|
501
|
+
* Add tests for it. This is important so we don't break it in a future version unintentionally.
|
502
|
+
* [Optional] Run the tests agaist a specific Gemfile: `$ appraisal rails_5.0 rake spec`.
|
503
|
+
* Run the tests agaist all supported versions: `$ rake`.
|
504
|
+
* Commit, but please do not mess with `Rakefile`, version, or history.
|
505
|
+
* Send a Pull Request. Bonus points for topic branches.
|
519
506
|
|
520
507
|
## Copyright
|
521
508
|
|
522
|
-
Copyright (c) 2010-2016 Cássio Marques and Lucas Caton. See LICENSE for details.
|
509
|
+
Copyright (c) 2010-2016 Cássio Marques and Lucas Caton. See `LICENSE` file for details.
|
data/enumerate_it.png
ADDED
Binary file
|
data/gemfiles/rails_3.0.gemfile
CHANGED
data/gemfiles/rails_3.1.gemfile
CHANGED
data/gemfiles/rails_3.2.gemfile
CHANGED
data/gemfiles/rails_4.0.gemfile
CHANGED
data/gemfiles/rails_4.1.gemfile
CHANGED
data/gemfiles/rails_4.2.gemfile
CHANGED
data/gemfiles/rails_5.0.gemfile
CHANGED
data/lib/enumerate_it/base.rb
CHANGED
@@ -93,7 +93,7 @@ module EnumerateIt
|
|
93
93
|
private
|
94
94
|
|
95
95
|
def sorted_map
|
96
|
-
return enumeration if sort_mode == :none
|
96
|
+
return enumeration if sort_mode.nil? || sort_mode == :none
|
97
97
|
|
98
98
|
enumeration.sort_by { |k, v| sort_lambda.call(k, v) }
|
99
99
|
end
|
@@ -103,7 +103,7 @@ module EnumerateIt
|
|
103
103
|
value: ->(_k, v) { v[0] },
|
104
104
|
name: ->(k, _v) { k },
|
105
105
|
translation: ->(_k, v) { translate(v[1]) }
|
106
|
-
}[sort_mode
|
106
|
+
}[sort_mode]
|
107
107
|
end
|
108
108
|
|
109
109
|
def normalize_enumeration(values_hash)
|
data/lib/enumerate_it/version.rb
CHANGED
@@ -7,7 +7,7 @@ module EnumerateIt
|
|
7
7
|
|
8
8
|
class_option :singular, type: 'string', desc: 'Singular name for i18n'
|
9
9
|
|
10
|
-
class_option :lang, type: 'string', desc: '
|
10
|
+
class_option :lang, type: 'string', desc: 'Language to use in i18n', default: 'en'
|
11
11
|
|
12
12
|
desc 'Creates a locale file on config/locales'
|
13
13
|
def create_locale
|
@@ -198,7 +198,7 @@ describe EnumerateIt::Base do
|
|
198
198
|
|
199
199
|
context 'associate values with a list' do
|
200
200
|
it 'creates constants for each enumeration value' do
|
201
|
-
expect(TestEnumerationWithList::FIRST).to
|
201
|
+
expect(TestEnumerationWithList::FIRST).to eq('first')
|
202
202
|
expect(TestEnumerationWithList::SECOND).to eq('second')
|
203
203
|
end
|
204
204
|
|
@@ -207,7 +207,15 @@ describe EnumerateIt::Base do
|
|
207
207
|
end
|
208
208
|
end
|
209
209
|
|
210
|
-
context 'specifying a
|
210
|
+
context 'not specifying a sort mode' do
|
211
|
+
subject { create_enumeration_class_with_sort_mode(nil).to_a }
|
212
|
+
|
213
|
+
it 'does not sort' do
|
214
|
+
is_expected.to eq([%w(xyz 1), %w(fgh 2), %w(abc 3), %w(jkl 0)])
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
context 'specifying a sort mode' do
|
211
219
|
subject { create_enumeration_class_with_sort_mode(sort_mode).to_a }
|
212
220
|
|
213
221
|
context 'by value' do
|
@@ -7,17 +7,12 @@ class TestEnumeration < EnumerateIt::Base
|
|
7
7
|
end
|
8
8
|
|
9
9
|
class TestEnumerationWithoutArray < EnumerateIt::Base
|
10
|
-
associate_values
|
11
|
-
value_one: '1',
|
12
|
-
value_two: '2'
|
13
|
-
)
|
10
|
+
associate_values value_one: '1', value_two: '2'
|
14
11
|
end
|
15
12
|
|
16
13
|
class TestEnumerationWithExtendedBehaviour < EnumerateIt::Base
|
17
|
-
associate_values
|
18
|
-
|
19
|
-
second: '2'
|
20
|
-
)
|
14
|
+
associate_values first: '1', second: '2'
|
15
|
+
|
21
16
|
def self.to_a
|
22
17
|
super.reverse
|
23
18
|
end
|
@@ -32,21 +27,15 @@ class TestEnumerationWithReservedWords < EnumerateIt::Base
|
|
32
27
|
end
|
33
28
|
|
34
29
|
class TestEnumerationWithDash < EnumerateIt::Base
|
35
|
-
associate_values
|
36
|
-
'pt-BR'
|
37
|
-
)
|
30
|
+
associate_values 'pt-BR'
|
38
31
|
end
|
39
32
|
|
40
33
|
class TestEnumerationWithCamelCase < EnumerateIt::Base
|
41
|
-
associate_values
|
42
|
-
'iPhone'
|
43
|
-
)
|
34
|
+
associate_values 'iPhone'
|
44
35
|
end
|
45
36
|
|
46
37
|
class Foobar < EnumerateIt::Base
|
47
|
-
associate_values
|
48
|
-
bar: 'foo'
|
49
|
-
)
|
38
|
+
associate_values bar: 'foo'
|
50
39
|
end
|
51
40
|
|
52
41
|
class PolymorphicEnum < EnumerateIt::Base
|
@@ -67,12 +56,13 @@ end
|
|
67
56
|
|
68
57
|
class BaseClass
|
69
58
|
extend EnumerateIt
|
59
|
+
|
70
60
|
has_enumeration_for :foobar, with: TestEnumeration
|
71
61
|
end
|
72
62
|
|
73
63
|
def create_enumeration_class_with_sort_mode(sort_mode)
|
74
64
|
Class.new(EnumerateIt::Base) do
|
75
|
-
sort_by
|
65
|
+
sort_by(sort_mode)
|
76
66
|
|
77
67
|
associate_values(
|
78
68
|
foo: %w(1 xyz),
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: enumerate_it
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cássio Marques
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-
|
12
|
+
date: 2016-10-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -142,6 +142,7 @@ files:
|
|
142
142
|
- README.md
|
143
143
|
- Rakefile
|
144
144
|
- enumerate_it.gemspec
|
145
|
+
- enumerate_it.png
|
145
146
|
- gemfiles/rails_3.0.gemfile
|
146
147
|
- gemfiles/rails_3.1.gemfile
|
147
148
|
- gemfiles/rails_3.2.gemfile
|
@@ -180,12 +181,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
180
181
|
version: 1.9.3
|
181
182
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
182
183
|
requirements:
|
183
|
-
- - "
|
184
|
+
- - ">"
|
184
185
|
- !ruby/object:Gem::Version
|
185
|
-
version:
|
186
|
+
version: 1.3.1
|
186
187
|
requirements: []
|
187
188
|
rubyforge_project:
|
188
|
-
rubygems_version: 2.
|
189
|
+
rubygems_version: 2.5.1
|
189
190
|
signing_key:
|
190
191
|
specification_version: 4
|
191
192
|
summary: Ruby Enumerations
|