enumerate_it 1.2.0 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://travis-ci.org/cassiomarques/enumerate_it.png?branch=master)](https://travis-ci.org/cassiomarques/enumerate_it)
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/enumerate_it.png)](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.
|