enumerate_it 1.2.0 → 1.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.
- checksums.yaml +15 -0
- data/Gemfile.lock +1 -1
- data/README.markdown +508 -0
- data/lib/enumerate_it/version.rb +1 -1
- metadata +7 -30
- data/README.rdoc +0 -366
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZGI4ZDc1NjJkOTdiODA5Zjg4Y2ExMmMzNGY2OWUzODkxZWVlNmY4Ng==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
M2YxZjM3NjhkYzg5NTVhM2ViODQ1YjU4NzNkNjYxMzYzN2U2YjZkNA==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZmM2MDI1OWRmNzlmNjgwMWI1YzZlMzdhNjg3NzFlOWFmODgxNTQzYzMzOGQz
|
10
|
+
NWQ0YWUzYTQyYzc1MDk2OGE4NDYyMWU5OTA0OTliYzUzNTY0MjFjNmFlMGZk
|
11
|
+
ZjMzODE0Y2VjZjYyM2NhMTM5M2ZiNjdlOTVmODM1MTAwNzUzYTM=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
OWNkZmY1ZTc5YTU4OTdkZmM2YzViMTgxYTI5NWJjNzlkZDQ2ZDMwYmEzZDYx
|
14
|
+
ZTk4YzRmNjg3MTI3MjE0ZjgwNGZjMjVlZTgxNjA0OGQ0NmNjZjM2OWE4OThh
|
15
|
+
Mzk3ZmFhMTc3Zjk0M2EzYjBkMDVlMGUzYTU5ZDQwNGFlMzE0YzA=
|
data/Gemfile.lock
CHANGED
data/README.markdown
ADDED
@@ -0,0 +1,508 @@
|
|
1
|
+
# EnumerateIt - Ruby Enumerations
|
2
|
+
|
3
|
+
[](https://travis-ci.org/cassiomarques/enumerate_it)
|
4
|
+
[](http://badge.fury.io/rb/enumerate_it)
|
5
|
+
|
6
|
+
Author: Cássio Marques - cassiommc at gmail
|
7
|
+
|
8
|
+
## Description
|
9
|
+
|
10
|
+
Ok, I know there are a lot of different solutions to this problem. But none of
|
11
|
+
them solved my problem, so here's EnumerateIt. I needed to build a Rails
|
12
|
+
application around a legacy database and this database was filled with those
|
13
|
+
small, unchangeable tables used to create foreign key constraints everywhere.
|
14
|
+
|
15
|
+
### For example:
|
16
|
+
|
17
|
+
Table "public.relationshipstatus"
|
18
|
+
|
19
|
+
Column | Type | Modifiers
|
20
|
+
-------------+---------------+-----------
|
21
|
+
code | character(1) | not null
|
22
|
+
description | character(11) |
|
23
|
+
|
24
|
+
Indexes:
|
25
|
+
"relationshipstatus_pkey" PRIMARY KEY, btree (code)
|
26
|
+
|
27
|
+
SELECT * FROM relationshipstatus;
|
28
|
+
|
29
|
+
code | description
|
30
|
+
-------+--------------
|
31
|
+
1 | Single
|
32
|
+
2 | Married
|
33
|
+
3 | Widow
|
34
|
+
4 | Divorced
|
35
|
+
|
36
|
+
And then I had things like a people table with a 'relationship_status' column
|
37
|
+
with a foreign key pointing to the relationshipstatus table.
|
38
|
+
|
39
|
+
While this is a good thing from the database normalization perspective,
|
40
|
+
managing this values in my tests was very hard. Doing database joins just to
|
41
|
+
get the description of some value was absurd. And, more than this, referencing
|
42
|
+
them in my code using magic numbers was terrible and meaningless: What does it
|
43
|
+
mean when we say that someone or something is '2'?
|
44
|
+
|
45
|
+
Enter EnumerateIt.
|
46
|
+
|
47
|
+
## About versions compatibility
|
48
|
+
|
49
|
+
Versions 1.x.x are NOT backwards compatible with 0.x.x versions. The biggest
|
50
|
+
difference is that on 1.0.0 you need to `extend` the EnumerateIt module inside
|
51
|
+
classes that are going to have enumerated attributes, while in past versions
|
52
|
+
you would use `include`.
|
53
|
+
|
54
|
+
## Creating enumerations
|
55
|
+
|
56
|
+
Enumerations are created as models, but you can put then anywhere in your
|
57
|
+
application. In Rails applications, you can put them inside models/.
|
58
|
+
|
59
|
+
``` ruby
|
60
|
+
class RelationshipStatus < EnumerateIt::Base
|
61
|
+
associate_values(
|
62
|
+
:single => [1, 'Single'],
|
63
|
+
:married => [2, 'Married'],
|
64
|
+
:widow => [3, 'Widow'],
|
65
|
+
:divorced => [4, 'Divorced']
|
66
|
+
)
|
67
|
+
end
|
68
|
+
```
|
69
|
+
|
70
|
+
This will create some nice stuff:
|
71
|
+
|
72
|
+
* Each enumeration's value will turn into a constant:
|
73
|
+
|
74
|
+
``` ruby
|
75
|
+
RelationshipStatus::SINGLE
|
76
|
+
#=> 1
|
77
|
+
|
78
|
+
RelationshipStatus::MARRIED
|
79
|
+
#=> 2
|
80
|
+
```
|
81
|
+
|
82
|
+
* You can retrieve a list with all the enumeration codes:
|
83
|
+
|
84
|
+
``` ruby
|
85
|
+
RelationshipStatus.list
|
86
|
+
#=> [1, 2, 3, 4]
|
87
|
+
```
|
88
|
+
|
89
|
+
* You can get an array of options, ready to use with the 'select',
|
90
|
+
'select_tag', etc family of Rails helpers.
|
91
|
+
|
92
|
+
``` ruby
|
93
|
+
RelationshipStatus.to_a
|
94
|
+
#=> [["Divorced", 4], ["Married", 2], ["Single", 1], ["Widow", 3]]
|
95
|
+
```
|
96
|
+
|
97
|
+
* You can retrieve a list with values for a group of enumeration constants.
|
98
|
+
|
99
|
+
``` ruby
|
100
|
+
RelationshipStatus.values_for %w(MARRIED SINGLE)
|
101
|
+
#=> [2, 1]
|
102
|
+
```
|
103
|
+
|
104
|
+
* You can retrieve the value for a specific enumeration constant:
|
105
|
+
|
106
|
+
``` ruby
|
107
|
+
RelationshipStatus.value_for("MARRIED")
|
108
|
+
#=> 2
|
109
|
+
```
|
110
|
+
|
111
|
+
* You can retrieve the symbol used to declare a specific enumeration value:
|
112
|
+
|
113
|
+
``` ruby
|
114
|
+
RelationshipStatus.key_for(RelationshipStatus::MARRIED)
|
115
|
+
#=> :married
|
116
|
+
```
|
117
|
+
|
118
|
+
* You can iterate over the list of the enumeration's values:
|
119
|
+
|
120
|
+
``` ruby
|
121
|
+
RelationshipStatus.each_value { |value| ... }
|
122
|
+
```
|
123
|
+
|
124
|
+
* You can iterate over the list of the enumeration's translations:
|
125
|
+
|
126
|
+
``` ruby
|
127
|
+
RelationshipStatus.each_translation { |translation| ... }
|
128
|
+
```
|
129
|
+
|
130
|
+
* You can ask for the enumeration's length:
|
131
|
+
|
132
|
+
``` ruby
|
133
|
+
RelationshipStatus.length
|
134
|
+
#=> 4
|
135
|
+
```
|
136
|
+
|
137
|
+
* You can manipulate the hash used to create the enumeration:
|
138
|
+
|
139
|
+
``` ruby
|
140
|
+
RelationshipStatus.enumeration
|
141
|
+
#=> returns the exact hash used to define the enumeration
|
142
|
+
```
|
143
|
+
|
144
|
+
|
145
|
+
You can also create enumerations in the following ways:
|
146
|
+
|
147
|
+
* Passing an array of symbols, so that the respective value for each symbol
|
148
|
+
will be the stringified version of the symbol itself:
|
149
|
+
|
150
|
+
``` ruby
|
151
|
+
class RelationshipStatus < EnumerateIt::Base
|
152
|
+
associate_values :married, :single
|
153
|
+
end
|
154
|
+
|
155
|
+
RelationshipStatus::MARRIED
|
156
|
+
#=> "married"
|
157
|
+
```
|
158
|
+
|
159
|
+
* Passing hashes where the value for each key/pair does not include a
|
160
|
+
translation. In this case, the I18n feature will be used (more on this
|
161
|
+
below):
|
162
|
+
|
163
|
+
``` ruby
|
164
|
+
class RelationshipStatus < EnumerateIt::Base
|
165
|
+
associate_values :married => 1, :single => 2
|
166
|
+
end
|
167
|
+
```
|
168
|
+
|
169
|
+
|
170
|
+
### Defining a default sort mode
|
171
|
+
|
172
|
+
When calling methods like `to_a` and `to_json`, the returned values will be
|
173
|
+
sorted using the translation for each one of the enumeration values. If you
|
174
|
+
want to overwrite the default sort mode, you can use the `sort_by` class
|
175
|
+
method.
|
176
|
+
|
177
|
+
``` ruby
|
178
|
+
class RelationshipStatus < EnumerateIt::Base
|
179
|
+
associate_values :married => 1, :single => 2
|
180
|
+
|
181
|
+
sort_by :value
|
182
|
+
end
|
183
|
+
```
|
184
|
+
|
185
|
+
The `sort_by` methods accept one of the following values:
|
186
|
+
|
187
|
+
* `:translation`: The default behavior, will sort the returned values based
|
188
|
+
on translations.
|
189
|
+
* `:value`: Will sort the returned values based on values.
|
190
|
+
* `:name`: Will sort the returned values based on the name of each
|
191
|
+
enumeration option.
|
192
|
+
* `:none`: Will return values in order that was passed to associate_values
|
193
|
+
call.
|
194
|
+
|
195
|
+
|
196
|
+
## Using enumerations
|
197
|
+
|
198
|
+
The cool part is that you can use these enumerations with any class, be it an
|
199
|
+
ActiveRecord instance or not.
|
200
|
+
|
201
|
+
``` ruby
|
202
|
+
class Person
|
203
|
+
extend EnumerateIt
|
204
|
+
attr_accessor :relationship_status
|
205
|
+
|
206
|
+
has_enumeration_for :relationship_status, :with => RelationshipStatus
|
207
|
+
end
|
208
|
+
```
|
209
|
+
|
210
|
+
The :with option is not required. If you ommit it, EnumerateIt will try to
|
211
|
+
load an enumeration class based on the camelized attribute name.
|
212
|
+
|
213
|
+
This will create:
|
214
|
+
|
215
|
+
* A humanized description for the values of the enumerated attribute:
|
216
|
+
|
217
|
+
``` ruby
|
218
|
+
p = Person.new
|
219
|
+
p.relationship_status = RelationshipStatus::DIVORCED
|
220
|
+
p.relationship_status_humanize
|
221
|
+
#=> 'Divorced'
|
222
|
+
```
|
223
|
+
|
224
|
+
* If you don't supply a humanized string to represent an option, EnumerateIt
|
225
|
+
will use a 'humanized' version of the hash's key to humanize the
|
226
|
+
attribute's value:
|
227
|
+
|
228
|
+
``` ruby
|
229
|
+
class RelationshipStatus < EnumerateIt::Base
|
230
|
+
associate_values(
|
231
|
+
:married => 1,
|
232
|
+
:single => 2
|
233
|
+
)
|
234
|
+
end
|
235
|
+
|
236
|
+
p = Person.new
|
237
|
+
p.relationship_status = RelationshipStatus::MARRIED
|
238
|
+
p.relationship_status_humanize
|
239
|
+
#=> 'Married'
|
240
|
+
```
|
241
|
+
|
242
|
+
* The associated enumerations can be retrieved with the 'enumerations' class
|
243
|
+
method.
|
244
|
+
|
245
|
+
``` ruby
|
246
|
+
Person.enumerations[:relationship_status]
|
247
|
+
#=> RelationshipStatus
|
248
|
+
```
|
249
|
+
|
250
|
+
* If you pass the :create_helpers option as 'true', it will create a helper
|
251
|
+
method for each enumeration option (this option defaults to false):
|
252
|
+
|
253
|
+
``` ruby
|
254
|
+
class Person < ActiveRecord::Base
|
255
|
+
has_enumeration_for :relationship_status, :with => RelationshipStatus, :create_helpers => true
|
256
|
+
end
|
257
|
+
|
258
|
+
p = Person.new
|
259
|
+
p.relationship_status = RelationshipStatus::MARRIED
|
260
|
+
|
261
|
+
p.married?
|
262
|
+
#=> true
|
263
|
+
|
264
|
+
p.divorced?
|
265
|
+
#=> false
|
266
|
+
```
|
267
|
+
|
268
|
+
* It's also possible to "namespace" the created helper methods, passing a
|
269
|
+
hash to the :create_helpers option. This can be useful when two or more of
|
270
|
+
the enumerations used share the same constants.
|
271
|
+
|
272
|
+
``` ruby
|
273
|
+
class Person < ActiveRecord::Base
|
274
|
+
has_enumeration_for :relationship_status, :with => RelationshipStatus, :create_helpers => { :prefix => true }
|
275
|
+
end
|
276
|
+
|
277
|
+
p = Person.new
|
278
|
+
p.relationship_status = RelationshipStatus::MARRIED
|
279
|
+
|
280
|
+
p.relationship_status_married?
|
281
|
+
#=> true
|
282
|
+
|
283
|
+
p.relationship_status_divoced?
|
284
|
+
#=> false
|
285
|
+
```
|
286
|
+
|
287
|
+
* You can define polymorphic behavior for the enum values, so you can define
|
288
|
+
a class for each of them:
|
289
|
+
|
290
|
+
``` ruby
|
291
|
+
class RelationshipStatus < EnumerateIt::Base
|
292
|
+
associate_values :married, :single
|
293
|
+
|
294
|
+
class Married
|
295
|
+
def saturday_night
|
296
|
+
"At home with the kids"
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
class Single
|
301
|
+
def saturday_night
|
302
|
+
"Party Hard!"
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
class Person < ActiveRecord::Base
|
308
|
+
has_enumeration_for :relationship_status, :with => RelationshipStatus, :create_helpers => { :polymorphic => true }
|
309
|
+
end
|
310
|
+
|
311
|
+
p = Person.new
|
312
|
+
p.relationship_status = RelationshipStatus::MARRIED
|
313
|
+
p.relationship_status_object.saturday_night
|
314
|
+
#=> "At home with the kids"
|
315
|
+
|
316
|
+
p.relationship_status = RelationshipStatus::SINGLE
|
317
|
+
p.relationship_status_object.saturday_night
|
318
|
+
#=> "Party Hard!"
|
319
|
+
```
|
320
|
+
|
321
|
+
You can also change the suffix '_object', using the :suffix option:
|
322
|
+
|
323
|
+
``` ruby
|
324
|
+
class Person < ActiveRecord::Base
|
325
|
+
has_enumeration_for :relationship_status, :with => RelationshipStatus, :create_helpers => { :polymorphic => { :suffix => "_mode" } }
|
326
|
+
end
|
327
|
+
|
328
|
+
p.relationship_status_mode.saturday_night
|
329
|
+
```
|
330
|
+
|
331
|
+
* The :create_helpers also creates some mutator helper methods, that can be
|
332
|
+
used to change the attribute's value.
|
333
|
+
|
334
|
+
``` ruby
|
335
|
+
class Person < ActiveRecord::Base
|
336
|
+
has_enumeration_for :relationship_status, :with => RelationshipStatus, :create_helpers => true
|
337
|
+
end
|
338
|
+
|
339
|
+
p = Person.new
|
340
|
+
p.married!
|
341
|
+
|
342
|
+
p.married?
|
343
|
+
#=> true
|
344
|
+
|
345
|
+
p.divorced?
|
346
|
+
#=> false
|
347
|
+
```
|
348
|
+
|
349
|
+
* If you pass the :create_scopes option as 'true', it will create a scope
|
350
|
+
method for each enumeration option (this option defaults to false):
|
351
|
+
|
352
|
+
``` ruby
|
353
|
+
class Person < ActiveRecord::Base
|
354
|
+
has_enumeration_for :relationship_status, :with => RelationshipStatus, :create_scopes => true
|
355
|
+
end
|
356
|
+
|
357
|
+
Person.married.to_sql
|
358
|
+
#=> SELECT "people".* FROM "people" WHERE "people"."relationship_status" = 1
|
359
|
+
```
|
360
|
+
|
361
|
+
|
362
|
+
NOTE: The :create_scopes option can only be used for Rails.version >= 3.0.0.
|
363
|
+
|
364
|
+
* If your class can manage validations and responds to
|
365
|
+
:validates_inclusion_of, it will create this validation:
|
366
|
+
|
367
|
+
``` ruby
|
368
|
+
class Person < ActiveRecord::Base
|
369
|
+
has_enumeration_for :relationship_status, :with => RelationshipStatus
|
370
|
+
end
|
371
|
+
|
372
|
+
p = Person.new(:relationship_status => 6) # there is no '6' value in the enumeration
|
373
|
+
p.valid?
|
374
|
+
#=> false
|
375
|
+
p.errors[:relationship_status]
|
376
|
+
#=> "is not included in the list"
|
377
|
+
```
|
378
|
+
|
379
|
+
* If your class can manage validations and responds to
|
380
|
+
:validates_presence_of, you can pass the :required options as true and
|
381
|
+
this validation will be created for you (this option defaults to false):
|
382
|
+
|
383
|
+
``` ruby
|
384
|
+
class Person < ActiveRecord::Base
|
385
|
+
has_enumeration_for :relationship_status, :required => true
|
386
|
+
end
|
387
|
+
|
388
|
+
p = Person.new :relationship_status => nil
|
389
|
+
p.valid?
|
390
|
+
#=> false
|
391
|
+
p.errors[:relationship_status]
|
392
|
+
#=> "can't be blank"
|
393
|
+
```
|
394
|
+
|
395
|
+
|
396
|
+
Remember that in Rails 3 you can add validations to any kind of class and not
|
397
|
+
only to those derived from ActiveRecord::Base.
|
398
|
+
|
399
|
+
## I18n
|
400
|
+
|
401
|
+
I18n lookup is provided on both '_humanized' and 'Enumeration#to_a' methods,
|
402
|
+
given the hash key is a Symbol. The I18n strings are located on
|
403
|
+
enumerations.'enumeration_name'.'key' :
|
404
|
+
|
405
|
+
``` yaml
|
406
|
+
# your locale file
|
407
|
+
pt:
|
408
|
+
enumerations:
|
409
|
+
relationship_status:
|
410
|
+
married: Casado
|
411
|
+
```
|
412
|
+
|
413
|
+
``` ruby
|
414
|
+
class RelationshipStatus < EnumerateIt::Base
|
415
|
+
associate_values(
|
416
|
+
:married => 1,
|
417
|
+
:single => 2,
|
418
|
+
:divorced => [3, "He's divorced"]
|
419
|
+
)
|
420
|
+
end
|
421
|
+
|
422
|
+
p = Person.new
|
423
|
+
p.relationship_status = RelationshipStatus::MARRIED
|
424
|
+
p.relationship_status_humanize
|
425
|
+
#=> 'Casado'
|
426
|
+
|
427
|
+
p.relationship_status = RelationshipStatus::SINGLE
|
428
|
+
p.relationship_status_humanize # nonexistent key
|
429
|
+
#=> 'Single'
|
430
|
+
|
431
|
+
p.relationship_status = RelationshipStatus::DIVORCED
|
432
|
+
p.relationship_status_humanize # uses the provided string
|
433
|
+
#=> 'He's divorced'
|
434
|
+
```
|
435
|
+
|
436
|
+
You can also translate specific values:
|
437
|
+
|
438
|
+
``` ruby
|
439
|
+
RelationshipStatus.t(1)
|
440
|
+
#=> 'Casado'
|
441
|
+
```
|
442
|
+
|
443
|
+
## Installation
|
444
|
+
|
445
|
+
``` bash
|
446
|
+
gem install enumerate_it
|
447
|
+
```
|
448
|
+
|
449
|
+
## Using with Rails
|
450
|
+
|
451
|
+
* Add the gem to your Gemfile:
|
452
|
+
|
453
|
+
``` ruby
|
454
|
+
gem "enumerate_it"
|
455
|
+
```
|
456
|
+
|
457
|
+
* Run the install generator:
|
458
|
+
|
459
|
+
``` bash
|
460
|
+
rails generate enumerate_it:install
|
461
|
+
```
|
462
|
+
|
463
|
+
|
464
|
+
An interesting approach to use it in Rails apps is to create an
|
465
|
+
app/enumerations folder and add it to your autoload path in
|
466
|
+
config/application.rb:
|
467
|
+
|
468
|
+
``` ruby
|
469
|
+
module YourApp
|
470
|
+
class Application < Rails::Application
|
471
|
+
config.autoload_paths << "#{Rails.root}/app/enumerations"
|
472
|
+
end
|
473
|
+
end
|
474
|
+
```
|
475
|
+
|
476
|
+
There is also a Rails Generator that you can use to generate enumerations and
|
477
|
+
their locale files. Take a look at how to use it running
|
478
|
+
|
479
|
+
``` bash
|
480
|
+
rails generate enumerate_it:enum --help
|
481
|
+
```
|
482
|
+
|
483
|
+
## Why did you reinvent the wheel?
|
484
|
+
|
485
|
+
There are other similar solutions to the problem out there, but I could not
|
486
|
+
find one that worked both with strings and integers as the enumerations'
|
487
|
+
codes. I had both situations in my legacy database.
|
488
|
+
|
489
|
+
## Why defining enumerations outside the class that use it?
|
490
|
+
|
491
|
+
* I think it's cleaner.
|
492
|
+
* You can add behaviour to the enumeration class.
|
493
|
+
* You can reuse the enumeration inside other classes.
|
494
|
+
|
495
|
+
## Note on Patches/Pull Requests
|
496
|
+
|
497
|
+
* Fork the project.
|
498
|
+
* Make your feature addition or bug fix.
|
499
|
+
* Add tests for it. This is important so I don't break it in a future
|
500
|
+
version unintentionally.
|
501
|
+
* Commit, do not mess with rakefile, version, or history. (if you want to
|
502
|
+
have your own version, that is fine but bump version in a commit by itself
|
503
|
+
I can ignore when I pull)
|
504
|
+
* Send me a pull request. Bonus points for topic branches.
|
505
|
+
|
506
|
+
## Copyright
|
507
|
+
|
508
|
+
Copyright (c) 2010 Cássio Marques. See LICENSE for details.
|
data/lib/enumerate_it/version.rb
CHANGED
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: enumerate_it
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
5
|
-
prerelease:
|
4
|
+
version: 1.2.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Cássio Marques
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-03-07 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: activesupport
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ! '>='
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ! '>='
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,7 +27,6 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: rake
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ! '>='
|
36
32
|
- !ruby/object:Gem::Version
|
@@ -38,7 +34,6 @@ dependencies:
|
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ! '>='
|
44
39
|
- !ruby/object:Gem::Version
|
@@ -46,7 +41,6 @@ dependencies:
|
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: rspec
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
45
|
- - ! '>='
|
52
46
|
- !ruby/object:Gem::Version
|
@@ -54,7 +48,6 @@ dependencies:
|
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
52
|
- - ! '>='
|
60
53
|
- !ruby/object:Gem::Version
|
@@ -62,7 +55,6 @@ dependencies:
|
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: activerecord
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
59
|
- - ! '>='
|
68
60
|
- !ruby/object:Gem::Version
|
@@ -70,7 +62,6 @@ dependencies:
|
|
70
62
|
type: :development
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
66
|
- - ! '>='
|
76
67
|
- !ruby/object:Gem::Version
|
@@ -78,7 +69,6 @@ dependencies:
|
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: pry
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
73
|
- - ! '>='
|
84
74
|
- !ruby/object:Gem::Version
|
@@ -86,7 +76,6 @@ dependencies:
|
|
86
76
|
type: :development
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
80
|
- - ! '>='
|
92
81
|
- !ruby/object:Gem::Version
|
@@ -94,7 +83,6 @@ dependencies:
|
|
94
83
|
- !ruby/object:Gem::Dependency
|
95
84
|
name: pry-nav
|
96
85
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
86
|
requirements:
|
99
87
|
- - ! '>='
|
100
88
|
- !ruby/object:Gem::Version
|
@@ -102,15 +90,11 @@ dependencies:
|
|
102
90
|
type: :development
|
103
91
|
prerelease: false
|
104
92
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
93
|
requirements:
|
107
94
|
- - ! '>='
|
108
95
|
- !ruby/object:Gem::Version
|
109
96
|
version: '0'
|
110
|
-
description:
|
111
|
-
those stupid '4 rows/2 columns' tables with foreign keys and stop doing joins just
|
112
|
-
to fetch a simple description? Or maybe use some integers instead of strings as
|
113
|
-
the code for each value of your enumerations? Here's EnumerateIt.
|
97
|
+
description: Enumerations for Ruby with some magic powers!
|
114
98
|
email:
|
115
99
|
- cassiommc@gmail.com
|
116
100
|
executables: []
|
@@ -123,7 +107,7 @@ files:
|
|
123
107
|
- Gemfile
|
124
108
|
- Gemfile.lock
|
125
109
|
- LICENSE
|
126
|
-
- README.
|
110
|
+
- README.markdown
|
127
111
|
- Rakefile
|
128
112
|
- enumerate_it.gemspec
|
129
113
|
- lib/enumerate_it.rb
|
@@ -146,33 +130,26 @@ files:
|
|
146
130
|
- spec/support/test_classes.rb
|
147
131
|
homepage: http://github.com/cassiomarques/enumerate_it
|
148
132
|
licenses: []
|
133
|
+
metadata: {}
|
149
134
|
post_install_message:
|
150
135
|
rdoc_options: []
|
151
136
|
require_paths:
|
152
137
|
- lib
|
153
138
|
required_ruby_version: !ruby/object:Gem::Requirement
|
154
|
-
none: false
|
155
139
|
requirements:
|
156
140
|
- - ! '>='
|
157
141
|
- !ruby/object:Gem::Version
|
158
142
|
version: '0'
|
159
|
-
segments:
|
160
|
-
- 0
|
161
|
-
hash: 1153526174871300187
|
162
143
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
163
|
-
none: false
|
164
144
|
requirements:
|
165
145
|
- - ! '>='
|
166
146
|
- !ruby/object:Gem::Version
|
167
147
|
version: '0'
|
168
|
-
segments:
|
169
|
-
- 0
|
170
|
-
hash: 1153526174871300187
|
171
148
|
requirements: []
|
172
149
|
rubyforge_project:
|
173
|
-
rubygems_version: 1.
|
150
|
+
rubygems_version: 2.1.4
|
174
151
|
signing_key:
|
175
|
-
specification_version:
|
152
|
+
specification_version: 4
|
176
153
|
summary: Ruby Enumerations
|
177
154
|
test_files:
|
178
155
|
- spec/enumerate_it/base_spec.rb
|
data/README.rdoc
DELETED
@@ -1,366 +0,0 @@
|
|
1
|
-
= EnumerateIt - Ruby Enumerations
|
2
|
-
|
3
|
-
{<img src="https://secure.travis-ci.org/cassiomarques/enumerate_it.png?branch=master" alt="Build Status" />}[http://travis-ci.org/cassiomarques/enumerate_it]
|
4
|
-
|
5
|
-
Author: Cássio Marques - cassiommc at gmail
|
6
|
-
|
7
|
-
== Description
|
8
|
-
|
9
|
-
Ok, I know there are a lot of different solutions to this problem. But none of them solved my problem,
|
10
|
-
so here's EnumerateIt. I needed to build a Rails application around a legacy database and this database was
|
11
|
-
filled with those small, unchangeable tables used to create foreign key constraints everywhere.
|
12
|
-
|
13
|
-
=== For example:
|
14
|
-
|
15
|
-
Table "public.relationshipstatus"
|
16
|
-
Column | Type | Modifiers
|
17
|
-
-------------+---------------+-----------
|
18
|
-
code | character(1) | not null
|
19
|
-
description | character(11) |
|
20
|
-
Indexes:
|
21
|
-
"relationshipstatus_pkey" PRIMARY KEY, btree (code)
|
22
|
-
|
23
|
-
select * from relationshipstatus;
|
24
|
-
code | description
|
25
|
-
-------+--------------
|
26
|
-
1 | Single
|
27
|
-
2 | Married
|
28
|
-
3 | Widow
|
29
|
-
4 | Divorced
|
30
|
-
|
31
|
-
|
32
|
-
And then I had things like a people table with a 'relationship_status' column with a foreign key
|
33
|
-
pointing to the relationshipstatus table.
|
34
|
-
|
35
|
-
While this is a good thing from the database normalization perspective, managing this values in
|
36
|
-
my tests was very hard. Doing database joins just to get the description of some value was absurd.
|
37
|
-
And, more than this, referencing them in my code using magic numbers was terrible and meaningless:
|
38
|
-
What does it mean when we say that someone or something is '2'?
|
39
|
-
|
40
|
-
Enter EnumerateIt.
|
41
|
-
|
42
|
-
== About versions compatibility
|
43
|
-
|
44
|
-
Versions 1.x.x are NOT backwards compatible with 0.x.x versions. The biggest difference is that on 1.0.0 you need to `extend` the EnumerateIt
|
45
|
-
module inside classes that are going to have enumerated attributes, while in past versions you would use `include`.
|
46
|
-
|
47
|
-
== Creating enumerations
|
48
|
-
|
49
|
-
Enumerations are created as models, but you can put then anywhere in your application. In Rails
|
50
|
-
applications, you can put them inside models/.
|
51
|
-
|
52
|
-
class RelationshipStatus < EnumerateIt::Base
|
53
|
-
associate_values(
|
54
|
-
:single => [1, 'Single'],
|
55
|
-
:married => [2, 'Married'],
|
56
|
-
:widow => [3, 'Widow'],
|
57
|
-
:divorced => [4, 'Divorced']
|
58
|
-
)
|
59
|
-
end
|
60
|
-
|
61
|
-
This will create some nice stuff:
|
62
|
-
|
63
|
-
* Each enumeration's value will turn into a constant:
|
64
|
-
|
65
|
-
RelationshipStatus::SINGLE # returns 1
|
66
|
-
RelationshipStatus::MARRIED # returns 2 and so on...
|
67
|
-
|
68
|
-
* You can retrieve a list with all the enumeration codes:
|
69
|
-
|
70
|
-
RelationshipStatus.list # [1,2,3,4]
|
71
|
-
|
72
|
-
* You can get an array of options, ready to use with the 'select', 'select_tag', etc family of Rails helpers.
|
73
|
-
|
74
|
-
RelationshipStatus.to_a # [["Divorced", 4],["Married", 2],["Single", 1],["Widow", 3]]
|
75
|
-
|
76
|
-
* You can retrieve a list with values for a group of enumeration constants.
|
77
|
-
|
78
|
-
RelationshipStatus.values_for %w(MARRIED SINGLE) # [2, 1]
|
79
|
-
|
80
|
-
* You can retrieve the value for a specific enumeration constant:
|
81
|
-
|
82
|
-
RelationshipStatus.value_for("MARRIED") # 2
|
83
|
-
|
84
|
-
* You can retrieve the symbol used to declare a specific enumeration value:
|
85
|
-
|
86
|
-
RelationshipStatus.key_for(RelationshipStatus::MARRIED) # :married
|
87
|
-
|
88
|
-
* You can iterate over the list of the enumeration's values:
|
89
|
-
|
90
|
-
RelationshipStatus.each_value { |value| # ... }
|
91
|
-
|
92
|
-
* You can iterate over the list of the enumeration's translations:
|
93
|
-
|
94
|
-
RelationshipStatus.each_translation { |translation| # ... }
|
95
|
-
|
96
|
-
* You can ask for the enumeration's length:
|
97
|
-
|
98
|
-
RelationshipStatus.length # 4
|
99
|
-
|
100
|
-
* You can manipulate the hash used to create the enumeration:
|
101
|
-
|
102
|
-
RelationshipStatus.enumeration # returns the exact hash used to define the enumeration
|
103
|
-
|
104
|
-
You can also create enumerations in the following ways:
|
105
|
-
|
106
|
-
* Passing an array of symbols, so that the respective value for each symbol will be the stringified version of the symbol itself:
|
107
|
-
|
108
|
-
class RelationshipStatus < EnumerateIt::Base
|
109
|
-
associate_values :married, :single
|
110
|
-
end
|
111
|
-
|
112
|
-
RelationshipStatus::MARRIED # returns "married" and so on
|
113
|
-
|
114
|
-
* Passing hashes where the value for each key/pair does not include a translation. In this case, the I18n feature will be used (more on this below):
|
115
|
-
|
116
|
-
class RelationshipStatus < EnumerateIt::Base
|
117
|
-
associate_values :married => 1, :single => 2
|
118
|
-
end
|
119
|
-
|
120
|
-
=== Defining a default sort mode
|
121
|
-
|
122
|
-
When calling methods like `to_a` and `to_json`, the returned values will be sorted using the translation for each one of the enumeration values. If you want
|
123
|
-
to overwrite the default sort mode, you can use the `sort_mode` class method.
|
124
|
-
|
125
|
-
class RelationshipStatus < EnumerateIt::Base
|
126
|
-
associate_values :married => 1, :single => 2
|
127
|
-
|
128
|
-
sort_by :value
|
129
|
-
end
|
130
|
-
|
131
|
-
The `sort_by` methods accept one of the following values:
|
132
|
-
|
133
|
-
* `:translation`: The default behavior, will sort the returned values based on translations.
|
134
|
-
* `:value`: Will sort the returned values based on values.
|
135
|
-
* `:name`: Will sort the returned values based on the name of each enumeration option.
|
136
|
-
* `:none`: Will return values in order that was passed to associate_values call.
|
137
|
-
|
138
|
-
== Using enumerations
|
139
|
-
|
140
|
-
The cool part is that you can use these enumerations with any class, be it an ActiveRecord instance
|
141
|
-
or not.
|
142
|
-
|
143
|
-
class Person
|
144
|
-
extend EnumerateIt
|
145
|
-
attr_accessor :relationship_status
|
146
|
-
|
147
|
-
has_enumeration_for :relationship_status, :with => RelationshipStatus
|
148
|
-
end
|
149
|
-
|
150
|
-
The :with option is not required. If you ommit it, EnumerateIt will try to load an enumeration class based on the camelized attribute name.
|
151
|
-
|
152
|
-
This will create:
|
153
|
-
|
154
|
-
* A humanized description for the values of the enumerated attribute:
|
155
|
-
|
156
|
-
p = Person.new
|
157
|
-
p.relationship_status = RelationshipStatus::DIVORCED
|
158
|
-
p.relationship_status_humanize # => 'Divorced'
|
159
|
-
|
160
|
-
* If you don't supply a humanized string to represent an option, EnumerateIt will use a 'humanized' version of the hash's key to humanize the attribute's value:
|
161
|
-
|
162
|
-
class RelationshipStatus < EnumerateIt::Base
|
163
|
-
associate_values(
|
164
|
-
:married => 1,
|
165
|
-
:single => 2
|
166
|
-
)
|
167
|
-
end
|
168
|
-
|
169
|
-
p = Person.new
|
170
|
-
p.relationship_status = RelationshipStatus::MARRIED
|
171
|
-
p.relationship_status_humanize # => 'Married'
|
172
|
-
|
173
|
-
* The associated enumerations can be retrieved with the 'enumerations' class method.
|
174
|
-
|
175
|
-
Person.enumerations[:relationship_status] # => RelationshipStatus
|
176
|
-
|
177
|
-
* If you pass the :create_helpers option as 'true', it will create a helper method for each enumeration option (this option defaults to false):
|
178
|
-
|
179
|
-
class Person < ActiveRecord::Base
|
180
|
-
has_enumeration_for :relationship_status, :with => RelationshipStatus, :create_helpers => true
|
181
|
-
end
|
182
|
-
|
183
|
-
p = Person.new
|
184
|
-
p.relationship_status = RelationshipStatus::MARRIED
|
185
|
-
p.married? #=> true
|
186
|
-
p.divorced? #=> false
|
187
|
-
|
188
|
-
* It's also possible to "namespace" the created helper methods, passing a hash to the :create_helpers option.
|
189
|
-
This can be useful when two or more of the enumerations used share the same constants.
|
190
|
-
|
191
|
-
class Person < ActiveRecord::Base
|
192
|
-
has_enumeration_for :relationship_status, :with => RelationshipStatus, :create_helpers => { :prefix => true }
|
193
|
-
end
|
194
|
-
|
195
|
-
p = Person.new
|
196
|
-
p.relationship_status = RelationshipStatus::MARRIED
|
197
|
-
p.relationship_status_married? #=> true
|
198
|
-
p.relationship_status_divoced? #=> false
|
199
|
-
|
200
|
-
* You can define polymorphic behavior for the enum values, so you can define a class for each of
|
201
|
-
them:
|
202
|
-
|
203
|
-
class RelationshipStatus < EnumerateIt::Base
|
204
|
-
associate_values :married, :single
|
205
|
-
|
206
|
-
class Married
|
207
|
-
def saturday_night
|
208
|
-
"At home with the kids"
|
209
|
-
end
|
210
|
-
end
|
211
|
-
|
212
|
-
class Single
|
213
|
-
def saturday_night
|
214
|
-
"Party Hard!"
|
215
|
-
end
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
class Person < ActiveRecord::Base
|
220
|
-
has_enumeration_for :relationship_status, :with => RelationshipStatus, :create_helpers => { :polymorphic => true }
|
221
|
-
end
|
222
|
-
|
223
|
-
p = Person.new
|
224
|
-
p.relationship_status = RelationshipStatus::MARRIED
|
225
|
-
p.relationship_status_object.saturday_night # => "At home with the kids"
|
226
|
-
|
227
|
-
p.relationship_status = RelationshipStatus::SINGLE
|
228
|
-
p.relationship_status_object.saturday_night # => "Party Hard!"
|
229
|
-
|
230
|
-
You can also change the suffix '_object', using the :suffix option:
|
231
|
-
|
232
|
-
class Person < ActiveRecord::Base
|
233
|
-
has_enumeration_for :relationship_status, :with => RelationshipStatus, :create_helpers => { :polymorphic => { :suffix => "_mode" } }
|
234
|
-
end
|
235
|
-
|
236
|
-
p.relationship_status_mode.saturday_night
|
237
|
-
|
238
|
-
* The :create_helpers also creates some mutator helper methods, that can be used to change the attribute's value.
|
239
|
-
|
240
|
-
class Person < ActiveRecord::Base
|
241
|
-
has_enumeration_for :relationship_status, :with => RelationshipStatus, :create_helpers => true
|
242
|
-
end
|
243
|
-
|
244
|
-
p = Person.new
|
245
|
-
p.married!
|
246
|
-
p.married? #=> true
|
247
|
-
p.divorced? #=> false
|
248
|
-
|
249
|
-
* If you pass the :create_scopes option as 'true', it will create a scope method for each enumeration option (this option defaults to false):
|
250
|
-
|
251
|
-
class Person < ActiveRecord::Base
|
252
|
-
has_enumeration_for :relationship_status, :with => RelationshipStatus, :create_scopes => true
|
253
|
-
end
|
254
|
-
|
255
|
-
Person.married.to_sql # => SELECT "people".* FROM "people" WHERE "people"."relationship_status" = 1
|
256
|
-
|
257
|
-
NOTE: The :create_scopes option can only be used for Rails.version >= 3.0.0.
|
258
|
-
|
259
|
-
* If your class can manage validations and responds to :validates_inclusion_of, it will create this validation:
|
260
|
-
|
261
|
-
class Person < ActiveRecord::Base
|
262
|
-
has_enumeration_for :relationship_status, :with => RelationshipStatus
|
263
|
-
end
|
264
|
-
|
265
|
-
p = Person.new :relationship_status => 6 # => there is no '6' value in the enumeration
|
266
|
-
p.valid? # => false
|
267
|
-
p.errors[:relationship_status] # => "is not included in the list"
|
268
|
-
|
269
|
-
* If your class can manage validations and responds to :validates_presence_of, you can pass the :required options as true and this validation will be created for you (this option defaults to false):
|
270
|
-
|
271
|
-
class Person < ActiveRecord::Base
|
272
|
-
has_enumeration_for :relationship_status, :required => true
|
273
|
-
end
|
274
|
-
|
275
|
-
p = Person.new :relationship_status => nil
|
276
|
-
p.valid? # => false
|
277
|
-
p.errors[:relationship_status] # => "can't be blank"
|
278
|
-
|
279
|
-
|
280
|
-
Remember that in Rails 3 you can add validations to any kind of class and not only to those derived from
|
281
|
-
ActiveRecord::Base.
|
282
|
-
|
283
|
-
== I18n
|
284
|
-
|
285
|
-
I18n lookup is provided on both '_humanized' and 'Enumeration#to_a' methods, given the hash key is a Symbol. The I18n strings are
|
286
|
-
located on enumerations.'enumeration_name'.'key' :
|
287
|
-
|
288
|
-
class RelationshipStatus < EnumerateIt::Base
|
289
|
-
associate_values(
|
290
|
-
:married => 1,
|
291
|
-
:single => 2,
|
292
|
-
:divorced => [3, 'He's divorced']
|
293
|
-
)
|
294
|
-
end
|
295
|
-
|
296
|
-
# your locale file
|
297
|
-
pt:
|
298
|
-
enumerations:
|
299
|
-
relationship_status:
|
300
|
-
married: Casado
|
301
|
-
|
302
|
-
p = Person.new
|
303
|
-
p.relationship_status = RelationshipStatus::MARRIED
|
304
|
-
p.relationship_status_humanize # => 'Casado'
|
305
|
-
|
306
|
-
p.relationship_status = RelationshipStatus::SINGLE
|
307
|
-
p.relationship_status_humanize # => 'Single' => nonexistent key
|
308
|
-
|
309
|
-
p.relationship_status = RelationshipStatus::DIVORCED
|
310
|
-
p.relationship_status_humanize # => 'He's divorced' => uses the provided string
|
311
|
-
|
312
|
-
You can also translate specific values:
|
313
|
-
|
314
|
-
RelationshipStatus.t(1) # => 'Casado'
|
315
|
-
|
316
|
-
== Installation
|
317
|
-
|
318
|
-
gem install enumerate_it
|
319
|
-
|
320
|
-
== Using with Rails
|
321
|
-
|
322
|
-
* Add the gem to your Gemfile:
|
323
|
-
|
324
|
-
gem "enumerate_it"
|
325
|
-
|
326
|
-
* Run the install generator:
|
327
|
-
|
328
|
-
rails g enumerate_it:install
|
329
|
-
|
330
|
-
An interesting approach to use it in Rails apps is to create an app/enumerations folder and add it to your autoload path in config/application.rb:
|
331
|
-
|
332
|
-
module YourApp
|
333
|
-
class Application < Rails::Application
|
334
|
-
config.autoload_paths << "#{Rails.root}/app/enumerations"
|
335
|
-
end
|
336
|
-
end
|
337
|
-
|
338
|
-
There is also a Rails Generator that you can use to generate enumerations and their locale files. Take a look at how to use it running
|
339
|
-
|
340
|
-
rails generate enumerate_it:enum --help
|
341
|
-
|
342
|
-
== Why did you reinvent the wheel?
|
343
|
-
|
344
|
-
There are other similar solutions to the problem out there, but I could not find one that
|
345
|
-
worked both with strings and integers as the enumerations' codes. I had both situations in
|
346
|
-
my legacy database.
|
347
|
-
|
348
|
-
== Why defining enumerations outside the class that use it?
|
349
|
-
|
350
|
-
* I think it's cleaner.
|
351
|
-
* You can add behaviour to the enumeration class.
|
352
|
-
* You can reuse the enumeration inside other classes.
|
353
|
-
|
354
|
-
== Note on Patches/Pull Requests
|
355
|
-
|
356
|
-
* Fork the project.
|
357
|
-
* Make your feature addition or bug fix.
|
358
|
-
* Add tests for it. This is important so I don't break it in a
|
359
|
-
future version unintentionally.
|
360
|
-
* Commit, do not mess with rakefile, version, or history.
|
361
|
-
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
362
|
-
* Send me a pull request. Bonus points for topic branches.
|
363
|
-
|
364
|
-
== Copyright
|
365
|
-
|
366
|
-
Copyright (c) 2010 Cássio Marques. See LICENSE for details.
|