power_enum 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +4 -1
- data/README.md +103 -72
- data/lib/power_enum/schema/schema_statements.rb +12 -4
- metadata +10 -10
data/LICENSE
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
Copyright (c) 2005 Trevor Squires
|
1
|
+
Initial Version Copyright (c) 2005 Trevor Squires
|
2
|
+
Rails 3 Updates Copyright (c) 2010 Pivotal Labs
|
3
|
+
Initial Test Suite Copyright (c) 2011 Sergey Potapov
|
4
|
+
Subsequent Updates Copyright (c) 2011 Arthur Shagall
|
2
5
|
|
3
6
|
Permission is hereby granted, free of charge, to any person obtaining
|
4
7
|
a copy of this software and associated documentation files (the
|
data/README.md
CHANGED
@@ -9,8 +9,8 @@ It allows you to cleanly solve many of the problems that the traditional Rails a
|
|
9
9
|
It is particularly suitable for scenarios where your Rails application is not the only user of the database, such as
|
10
10
|
when it's used for analytics or reporting.
|
11
11
|
|
12
|
-
Power Enum is built on top of the Rails 3 modernization made by the fine folks at Protocool https://github.com/protocool/
|
13
|
-
to the original plugin by Trevor Squires located at https://github.com/protocool/
|
12
|
+
Power Enum is built on top of the Rails 3 modernization made by the fine folks at Protocool https://github.com/protocool/enumerations\_mixin
|
13
|
+
to the original plugin by Trevor Squires located at https://github.com/protocool/enumerations\_mixin. While many of the core ideas remain,
|
14
14
|
it has been reworked and a full test suite written to facilitate further development.
|
15
15
|
|
16
16
|
At it's most basic level, it allows you to say things along the lines of:
|
@@ -39,17 +39,18 @@ then run
|
|
39
39
|
|
40
40
|
This package adds two mixins and a helper to Rails' ActiveRecord, as well as methods to migrations to simplify the creation of backing tables.
|
41
41
|
|
42
|
-
|
43
|
-
At a minimum, the database table for
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
active.
|
42
|
+
`acts_as_enumerated` provides capabilities to treat your model and its records as an enumeration.
|
43
|
+
At a minimum, the database table for an acts\_as\_enumerated must contain an 'id' column and a column
|
44
|
+
to hold the value of the enum ('name' by default). It is strongly recommended that there be
|
45
|
+
a NOT NULL constraint on the 'name' column. All instances for the `acts_as_enumerated` model
|
46
|
+
are cached in memory. If the table has an 'active' column, the value of that attribute
|
47
|
+
will be used to determine which enum instances are active.
|
48
|
+
Otherwise, all values are considered active.
|
48
49
|
|
49
|
-
|
50
|
+
`has_enumerated` adds methods to your ActiveRecord model for setting and retrieving enumerated values using an associated acts\_as\_enumerated model.
|
50
51
|
|
51
|
-
There is also an
|
52
|
-
cluttering up your models directory with
|
52
|
+
There is also an `ActiveRecord::VirtualEnumerations` helper module to create 'virtual' acts\_as\_enumerated models which helps to avoid
|
53
|
+
cluttering up your models directory with acts\_as\_enumerated classes.
|
53
54
|
|
54
55
|
## How to use it
|
55
56
|
|
@@ -61,8 +62,6 @@ In the following example, we'll look at a Booking that can have several types of
|
|
61
62
|
# The above is equivalent to saying
|
62
63
|
# create_table :booking_statuses do |t|
|
63
64
|
# t.string :name, :limit => 50, :null => false
|
64
|
-
|
65
|
-
# t.timestamps
|
66
65
|
# end
|
67
66
|
|
68
67
|
create_table :bookings do |t|
|
@@ -76,23 +75,35 @@ In the following example, we'll look at a Booking that can have several types of
|
|
76
75
|
|
77
76
|
There are two methods added to Rails migrations:
|
78
77
|
|
79
|
-
##### create_enum(enum_name, options = {})
|
78
|
+
##### `create_enum(enum_name, options = {})`
|
80
79
|
|
81
|
-
Creates a new enum table.
|
80
|
+
Creates a new enum table. `enum_name` will be automatically pluralized. The following options are supported:
|
82
81
|
|
83
82
|
- [:name_column] Specify the column name for name of the enum. By default it's :name. This can be a String or a Symbol
|
84
|
-
- [:description] Set this to
|
83
|
+
- [:description] Set this to `true` to have a 'description' column generated.
|
85
84
|
- [:name_limit] Set this define the limit of the name column.
|
86
85
|
- [:desc_limit] Set this to define the limit of the description column
|
87
|
-
- [:active] Set this to
|
86
|
+
- [:active] Set this to `true` to have a boolean 'active' column generated. The 'active' column will have the options of NOT NULL and DEFAULT TRUE.
|
87
|
+
- [:timestamps] Set this to `true` to have the timestamp columns (created\_at and updated\_at) generated
|
88
88
|
|
89
89
|
Example:
|
90
90
|
|
91
|
+
create_enum :booking_status
|
92
|
+
|
93
|
+
is the equivalent of
|
94
|
+
|
95
|
+
create_table :booking_statuses do |t|
|
96
|
+
t.string :name, :null => false
|
97
|
+
end
|
98
|
+
|
99
|
+
In a more complex case:
|
100
|
+
|
91
101
|
create_enum :booking_status, :name_column => :booking_name,
|
92
102
|
:name_limit => 50,
|
93
103
|
:description => true,
|
94
104
|
:desc_limit => 100,
|
95
|
-
:active => true
|
105
|
+
:active => true,
|
106
|
+
:timestamps => true
|
96
107
|
|
97
108
|
is the equivalent of
|
98
109
|
|
@@ -103,9 +114,9 @@ is the equivalent of
|
|
103
114
|
t.timestamps
|
104
115
|
end
|
105
116
|
|
106
|
-
##### remove_enum(enum_name)
|
117
|
+
##### `remove_enum(enum_name)`
|
107
118
|
|
108
|
-
Drops the enum table.
|
119
|
+
Drops the enum table. `enum_name` will be automatically pluralized.
|
109
120
|
|
110
121
|
Example:
|
111
122
|
|
@@ -115,77 +126,85 @@ is the equivalent of
|
|
115
126
|
|
116
127
|
drop_table :booking_statuses
|
117
128
|
|
118
|
-
###
|
129
|
+
### acts\_as\_enumerated
|
119
130
|
|
120
131
|
class BookingStatus < ActiveRecord::Base
|
121
|
-
acts_as_enumerated :conditions
|
122
|
-
|
123
|
-
|
124
|
-
|
132
|
+
acts_as_enumerated :conditions => 'optional_sql_conditions',
|
133
|
+
:order => 'optional_sql_orderby',
|
134
|
+
:on_lookup_failure => :optional_class_method,
|
135
|
+
:name_column => 'optional_name_column' #If required, may override the default name column
|
125
136
|
end
|
126
137
|
|
127
138
|
With that, your BookingStatus class will have the following methods defined:
|
128
139
|
|
129
140
|
#### Class Methods
|
130
141
|
|
131
|
-
##### [](arg)
|
142
|
+
##### `[](arg)`
|
132
143
|
|
133
|
-
|
144
|
+
`BookingStatus[arg]` performs a lookup for the BookingStatus instance for the given arg. The arg value can be a 'string' or a :symbol,
|
145
|
+
in which case the lookup will be against the BookingStatus.name field. Alternatively arg can be a Fixnum,
|
146
|
+
in which case the lookup will be against the BookingStatus.id field.
|
134
147
|
|
135
|
-
The
|
148
|
+
The `:on_lookup_failure` option specifies the name of a *class* method to invoke when the `[]` method is unable to locate a BookingStatus record for arg.
|
149
|
+
The default is the built-in `:enforce_none` which returns nil. There are also built-ins for `:enforce_strict` (raise and exception regardless of the type for arg),
|
150
|
+
`:enforce_strict_literals` (raises an exception if the arg is a Fixnum or Symbol), `:enforce_strict_ids` (raises and exception if the arg is a Fixnum)
|
151
|
+
and `:enforce_strict_symbols` (raises an exception if the arg is a Symbol).
|
136
152
|
|
137
|
-
The purpose of the
|
153
|
+
The purpose of the `:on_lookup_failure` option is that a) under some circumstances a lookup failure is a Bad Thing and action should be taken,
|
154
|
+
therefore b) a fallback action should be easily configurable.
|
138
155
|
|
139
|
-
##### all
|
156
|
+
##### `all`
|
140
157
|
|
141
|
-
|
158
|
+
`BookingStatus.all` returns an array of all BookingStatus records that match the `:conditions` specified in `acts_as_enumerated`, in the order specified by `:order`.
|
142
159
|
|
143
|
-
##### active
|
160
|
+
##### `active`
|
144
161
|
|
145
|
-
|
162
|
+
`BookingStatus.active` returns an array of all BookingStatus records that are marked active. See the `active?` instance method.
|
146
163
|
|
147
|
-
##### inactive
|
164
|
+
##### `inactive`
|
148
165
|
|
149
|
-
|
166
|
+
`BookingStatus.inactive` returns an array of all BookingStatus records that are inactive. See the `inactive?` instance method.
|
150
167
|
|
151
168
|
#### Instance Methods
|
152
169
|
|
153
170
|
Each enumeration model gets the following instance methods.
|
154
171
|
|
155
|
-
#####
|
172
|
+
##### `===(arg)`
|
156
173
|
|
157
|
-
|
174
|
+
`BookingStatus[:foo] === arg` returns true if `BookingStatus[:foo] === BookingStatus[arg]` returns true if arg is Fixnum, String,
|
175
|
+
or Symbol. If arg is an Array, will compare every element of the array and return true if any element return true for `===`.
|
158
176
|
|
159
|
-
You should note that defining an
|
177
|
+
You should note that defining an `:on_lookup_failure` method that raises an exception will cause `===` to also raise an exception for any lookup failure of `BookingStatus[arg]`.
|
160
178
|
|
161
|
-
|
179
|
+
`like?` is aliased to `===`
|
162
180
|
|
163
|
-
##### in?(*list)
|
181
|
+
##### `in?(*list)`
|
164
182
|
|
165
|
-
Returns true if any element in the list returns true for
|
183
|
+
Returns true if any element in the list returns true for `===(arg)`, false otherwise.
|
166
184
|
|
167
|
-
##### name
|
185
|
+
##### `name`
|
168
186
|
|
169
|
-
Returns the 'name' of the enum, i.e. the value in the
|
187
|
+
Returns the 'name' of the enum, i.e. the value in the `:name_column` attribute of the enumeration model.
|
170
188
|
|
171
|
-
##### name_sym
|
189
|
+
##### `name_sym`
|
172
190
|
|
173
|
-
Returns the symbol representation of the name of the enum.
|
191
|
+
Returns the symbol representation of the name of the enum. `BookingStatus[:foo].name_sym` returns :foo.
|
174
192
|
|
175
|
-
##### active
|
193
|
+
##### `active?`
|
176
194
|
|
177
195
|
Returns true if the instance is active, false otherwise. If it has an attribute 'active',
|
178
|
-
returns the attribute cast to a boolean, otherwise returns true. This method is used by the
|
196
|
+
returns the attribute cast to a boolean, otherwise returns true. This method is used by the `active`
|
179
197
|
class method to select active enums.
|
180
198
|
|
181
|
-
##### inactive
|
199
|
+
##### `inactive?`
|
182
200
|
|
183
|
-
Returns true if the instance is inactive, false otherwise. Default implementations returns
|
184
|
-
This method is used by the
|
201
|
+
Returns true if the instance is inactive, false otherwise. Default implementations returns `!active?`
|
202
|
+
This method is used by the `inactive` class method to select inactive enums.
|
185
203
|
|
186
204
|
#### Notes
|
187
205
|
|
188
|
-
acts_as_enumerated records are considered immutable. By default you cannot create/alter/destroy instances because they are cached in memory.
|
206
|
+
`acts_as_enumerated` records are considered immutable. By default you cannot create/alter/destroy instances because they are cached in memory.
|
207
|
+
Because of Rails' process-based model it is not safe to allow updating acts\_as\_enumerated records as the caches will get out of sync.
|
189
208
|
|
190
209
|
However, one instance where updating the models *should* be allowed is if you are using seeds.rb to seed initial values into the database.
|
191
210
|
|
@@ -196,64 +215,76 @@ Using the above example you would do the following:
|
|
196
215
|
BookingStatus.create( :name => status_name )
|
197
216
|
end
|
198
217
|
|
199
|
-
|
218
|
+
Note that a `:presence` and `:uniqueness` validation is automatically defined on each model for the name column.
|
200
219
|
|
201
|
-
###
|
220
|
+
### has\_enumerated
|
202
221
|
|
203
|
-
First of all, note that you *could* specify the relationship to an acts_as_enumerated class using the belongs_to association.
|
222
|
+
First of all, note that you *could* specify the relationship to an `acts_as_enumerated` class using the belongs_to association.
|
223
|
+
However, `has_enumerated` is preferable because you aren't really associated to the enumerated value, you are *aggregating* it. As such,
|
224
|
+
the `has_enumerated` macro behaves more like an aggregation than an association.
|
204
225
|
|
205
226
|
class Booking < ActiveRecord::Base
|
206
|
-
has_enumerated :status, :class_name
|
207
|
-
|
208
|
-
|
227
|
+
has_enumerated :status, :class_name => 'BookingStatus',
|
228
|
+
:foreign_key => 'status_id',
|
229
|
+
:on_lookup_failure => :optional_instance_method
|
209
230
|
end
|
210
231
|
|
211
|
-
By default, the foreign key is interpreted to be the name of your
|
232
|
+
By default, the foreign key is interpreted to be the name of your has\_enumerated field (in this case 'status') plus '\_id'. Additionally,
|
233
|
+
the default value for `:class_name` is the camel-ized version of the name for your has\_enumerated field. `:on_lookup_failure` is explained below.
|
212
234
|
|
213
235
|
With that, your Booking class will have the following methods defined:
|
214
236
|
|
215
|
-
#### status
|
237
|
+
#### `status`
|
216
238
|
|
217
239
|
Returns the BookingStatus with an id that matches the value in the Booking.status_id.
|
218
240
|
|
219
|
-
#### status=(arg)
|
241
|
+
#### `status=(arg)`
|
220
242
|
|
221
|
-
Sets the value for Booking.status_id using the id of the BookingStatus instance passed as an argument. As a
|
243
|
+
Sets the value for Booking.status_id using the id of the BookingStatus instance passed as an argument. As a
|
244
|
+
short-hand, you can also pass it the 'name' of a BookingStatus instance, either as a 'string' or :symbol, or pass in the id directly.
|
222
245
|
|
223
246
|
example:
|
224
247
|
|
225
248
|
mybooking.status = :confirmed
|
226
249
|
|
227
|
-
this
|
250
|
+
this is equivalent to:
|
228
251
|
|
229
252
|
mybooking.status = 'confirmed'
|
230
253
|
|
231
|
-
|
254
|
+
or:
|
255
|
+
|
256
|
+
mybooking.status = BookingStatus[:confirmed]
|
257
|
+
|
258
|
+
The `:on_lookup_failure` option in has_enumerated is there because you may want to create an error handler for situations
|
259
|
+
where the argument passed to `status=(arg)` is invalid. By default, an invalid value will cause an ArgumentError to be raised.
|
232
260
|
|
233
261
|
Of course, this may not be optimal in your situation. In this case you can specify an *instance* method to be called in the case of a lookup failure. The method signature is as follows:
|
234
262
|
|
235
263
|
your_lookup_handler(operation, name, name_foreign_key, acts_enumerated_class_name, lookup_value)
|
236
264
|
|
237
|
-
The 'operation' arg will be either
|
265
|
+
The 'operation' arg will be either `:read` or `:write`. In the case of `:read` you are expected to return something or raise an exception,
|
266
|
+
while in the case of a `:write` you don't have to return anything.
|
238
267
|
|
239
|
-
Note that there's enough information in the method signature that you can specify one method to handle all lookup failures
|
268
|
+
Note that there's enough information in the method signature that you can specify one method to handle all lookup failures
|
269
|
+
for all has\_enumerated fields if you happen to have more than one defined in your model.
|
240
270
|
|
241
|
-
NOTE: A nil is always considered to be a valid value for status= since it's assumed you're trying to null out the foreign key
|
271
|
+
NOTE: A `nil` is always considered to be a valid value for `status=(arg)` since it's assumed you're trying to null out the foreign key.
|
272
|
+
The `:on_lookup_failure` will be bypassed.
|
242
273
|
|
243
274
|
### ActiveRecord::VirtualEnumerations
|
244
275
|
|
245
|
-
|
276
|
+
In many instances, your `acts_as_enumerated` classes will do nothing more than just act as enumerated.
|
246
277
|
|
247
278
|
In that case there isn't much point cluttering up your models directory with those class files. You can use ActiveRecord::VirtualEnumerations to reduce that clutter.
|
248
279
|
|
249
|
-
Copy
|
280
|
+
Copy virtual\_enumerations\_sample.rb to Rails.root/config/initializers/virtual\_enumerations.rb and configure it accordingly.
|
250
281
|
|
251
|
-
See
|
282
|
+
See virtual\_enumerations\_sample.rb in the examples directory of this gem for a full description.
|
252
283
|
|
253
284
|
|
254
285
|
## How to run tests
|
255
286
|
|
256
|
-
Go to dummy project:
|
287
|
+
Go to the 'dummy' project:
|
257
288
|
|
258
289
|
cd ./spec/dummy
|
259
290
|
|
@@ -277,7 +308,7 @@ And finally run tests:
|
|
277
308
|
|
278
309
|
* Initial Version Copyright (c) 2005 Trevor Squires
|
279
310
|
* Rails 3 Updates Copyright (c) 2010 Pivotal Labs
|
280
|
-
* Initial
|
281
|
-
*
|
311
|
+
* Initial Test Suite Copyright (c) 2011 Sergey Potapov
|
312
|
+
* Subsequent Updates Copyright (c) 2011 Arthur Shagall
|
282
313
|
|
283
314
|
Released under the MIT License. See the LICENSE file for more details.
|
@@ -25,6 +25,8 @@ module PowerEnum::Schema
|
|
25
25
|
# Set this to define the limit of the description column.
|
26
26
|
# [:active]
|
27
27
|
# Set this to <tt>true</tt> to have a boolean 'active' column generated. The 'active' column will have the options of NOT NULL and DEFAULT TRUE.
|
28
|
+
# [:timestamps]
|
29
|
+
# Set this to <tt>true</tt> to have timestamp columns (created_at and updated_at) generated.
|
28
30
|
#
|
29
31
|
# ===== Examples
|
30
32
|
# ====== Basic Enum
|
@@ -32,11 +34,15 @@ module PowerEnum::Schema
|
|
32
34
|
# is the equivalent of
|
33
35
|
# create_table :connector_types do |t|
|
34
36
|
# t.string :name, :null => false
|
35
|
-
# t.timestamps
|
36
37
|
# end
|
37
38
|
#
|
38
39
|
# ====== Advanced Enum
|
39
|
-
# create_enum :connector_type, :name_column => :connector,
|
40
|
+
# create_enum :connector_type, :name_column => :connector,
|
41
|
+
# :name_limit => 50,
|
42
|
+
# :description => true,
|
43
|
+
# :desc_limit => 100,
|
44
|
+
# :active => true,
|
45
|
+
# :timestamps => true
|
40
46
|
# is the equivalent of
|
41
47
|
# create_table :connector_types do |t|
|
42
48
|
# t.string :connector, :limit => 50, :null => false
|
@@ -50,6 +56,7 @@ module PowerEnum::Schema
|
|
50
56
|
name_column = options[:name_column] || :name
|
51
57
|
generate_description = !!options[:description]
|
52
58
|
generate_active = !!options[:active]
|
59
|
+
generate_timestamps = !!options[:timestamps]
|
53
60
|
name_limit = options[:name_limit]
|
54
61
|
desc_limit = options[:desc_limit]
|
55
62
|
|
@@ -61,8 +68,9 @@ module PowerEnum::Schema
|
|
61
68
|
if generate_active
|
62
69
|
t.boolean :active, :null => false, :default => true
|
63
70
|
end
|
64
|
-
|
65
|
-
|
71
|
+
if generate_timestamps
|
72
|
+
t.timestamps
|
73
|
+
end
|
66
74
|
end
|
67
75
|
|
68
76
|
add_index enum_table_name, [name_column], :unique => true
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: power_enum
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -12,11 +12,11 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2011-09-
|
15
|
+
date: 2011-09-25 00:00:00.000000000Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: rails
|
19
|
-
requirement: &
|
19
|
+
requirement: &28153380 !ruby/object:Gem::Requirement
|
20
20
|
none: false
|
21
21
|
requirements:
|
22
22
|
- - ! '>='
|
@@ -24,10 +24,10 @@ dependencies:
|
|
24
24
|
version: 3.0.0
|
25
25
|
type: :runtime
|
26
26
|
prerelease: false
|
27
|
-
version_requirements: *
|
27
|
+
version_requirements: *28153380
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: jeweler
|
30
|
-
requirement: &
|
30
|
+
requirement: &28152380 !ruby/object:Gem::Requirement
|
31
31
|
none: false
|
32
32
|
requirements:
|
33
33
|
- - ! '>='
|
@@ -35,10 +35,10 @@ dependencies:
|
|
35
35
|
version: '0'
|
36
36
|
type: :development
|
37
37
|
prerelease: false
|
38
|
-
version_requirements: *
|
38
|
+
version_requirements: *28152380
|
39
39
|
- !ruby/object:Gem::Dependency
|
40
40
|
name: rspec
|
41
|
-
requirement: &
|
41
|
+
requirement: &28151860 !ruby/object:Gem::Requirement
|
42
42
|
none: false
|
43
43
|
requirements:
|
44
44
|
- - ! '>='
|
@@ -46,10 +46,10 @@ dependencies:
|
|
46
46
|
version: '0'
|
47
47
|
type: :development
|
48
48
|
prerelease: false
|
49
|
-
version_requirements: *
|
49
|
+
version_requirements: *28151860
|
50
50
|
- !ruby/object:Gem::Dependency
|
51
51
|
name: sqlite3
|
52
|
-
requirement: &
|
52
|
+
requirement: &28151280 !ruby/object:Gem::Requirement
|
53
53
|
none: false
|
54
54
|
requirements:
|
55
55
|
- - ! '>='
|
@@ -57,7 +57,7 @@ dependencies:
|
|
57
57
|
version: '0'
|
58
58
|
type: :development
|
59
59
|
prerelease: false
|
60
|
-
version_requirements: *
|
60
|
+
version_requirements: *28151280
|
61
61
|
description: ! 'Power Enum allows you to treat instances of your ActiveRecord models
|
62
62
|
as though they were an enumeration of values.
|
63
63
|
|