power_enum 0.2.5 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +92 -14
- data/lib/active_record/acts/enumerated.rb +28 -3
- data/lib/power_enum/migration/command_recorder.rb +18 -0
- data/lib/power_enum/schema/schema_statements.rb +84 -0
- data/lib/power_enum.rb +11 -0
- metadata +24 -12
data/README.md
CHANGED
@@ -4,17 +4,19 @@ Enumerations for Rails 3.X Done Right.
|
|
4
4
|
|
5
5
|
## What is this?:
|
6
6
|
|
7
|
-
Power Enum allows you to treat instances of your
|
8
|
-
|
7
|
+
Power Enum allows you to treat instances of your ActiveRecord models as though they were an enumeration of values.
|
8
|
+
It allows you to cleanly solve many of the problems that the traditional Rails alternatives handler poorly if at all.
|
9
|
+
It is particularly suitable for scenarios where your Rails application is not the only user of the database, such as
|
10
|
+
when it's used for analytics or reporting.
|
9
11
|
|
10
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
|
11
|
-
to the original plugin by Trevor Squires located at https://github.com/protocool/enumerations_mixin. While
|
13
|
+
to the original plugin by Trevor Squires located at https://github.com/protocool/enumerations_mixin. While many of the core ideas remain,
|
12
14
|
it has been reworked and a full test suite written to facilitate further development.
|
13
15
|
|
14
16
|
At it's most basic level, it allows you to say things along the lines of:
|
15
17
|
|
16
18
|
booking = Booking.new(:status => BookingStatus[:provisional])
|
17
|
-
booking.
|
19
|
+
booking.status = :confirmed
|
18
20
|
|
19
21
|
Booking.find :first,
|
20
22
|
:conditions => ['status_id = ?', BookingStatus[:provisional].id]
|
@@ -25,19 +27,29 @@ See "How to use it" below for more information.
|
|
25
27
|
|
26
28
|
## Installation
|
27
29
|
|
28
|
-
|
30
|
+
Add the gem to your Gemfile
|
29
31
|
|
30
32
|
gem 'power_enum'
|
31
33
|
|
34
|
+
then run
|
35
|
+
|
36
|
+
bundle install
|
37
|
+
|
32
38
|
## Gem Contents
|
33
39
|
|
34
|
-
This package adds two mixins and a helper to Rails' ActiveRecord
|
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.
|
35
41
|
|
36
|
-
<code>acts_as_enumerated</code> provides capabilities to treat your model and its records as an enumeration.
|
42
|
+
<code>acts_as_enumerated</code> 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 'name' column.
|
44
|
+
It is strongly recommended that there be a NOT NULL constraint on the 'name' column.
|
45
|
+
All instances for the acts_as_enumerated model are cached in memory. If the table has an 'active' column, the
|
46
|
+
value of that attribute will be used to determine which enum instances are active. Otherwise, all values are considered
|
47
|
+
active.
|
37
48
|
|
38
49
|
<code>has_enumerated</code> adds methods to your ActiveRecord model for setting and retrieving enumerated values using an associated acts_as_enumerated model.
|
39
50
|
|
40
|
-
There is also an <code>ActiveRecord::VirtualEnumerations</code> helper module to create 'virtual' acts_as_enumerated models which helps to avoid
|
51
|
+
There is also an <code>ActiveRecord::VirtualEnumerations</code> helper module to create 'virtual' acts_as_enumerated models which helps to avoid
|
52
|
+
cluttering up your models directory with acts_as_enumerated classes.
|
41
53
|
|
42
54
|
## How to use it
|
43
55
|
|
@@ -45,11 +57,13 @@ In the following example, we'll look at a Booking that can have several types of
|
|
45
57
|
|
46
58
|
### migration
|
47
59
|
|
48
|
-
|
49
|
-
|
60
|
+
create_enum :booking_status, :name_limit => 50
|
61
|
+
# The above is equivalent to saying
|
62
|
+
# create_table :booking_statuses do |t|
|
63
|
+
# t.string :name, :limit => 50, :null => false
|
50
64
|
|
51
|
-
|
52
|
-
end
|
65
|
+
# t.timestamps
|
66
|
+
# end
|
53
67
|
|
54
68
|
create_table :bookings do |t|
|
55
69
|
t.integer :status_id
|
@@ -59,6 +73,47 @@ In the following example, we'll look at a Booking that can have several types of
|
|
59
73
|
|
60
74
|
# Ideally, you would use a gem of some sort to handle foreign keys.
|
61
75
|
execute "ALTER TABLE bookings ADD 'bookings_bookings_status_id_fk' FOREIGN KEY (status_id) REFERENCES booking_statuses (id);"
|
76
|
+
|
77
|
+
There are two methods added to Rails migrations:
|
78
|
+
|
79
|
+
##### create_enum(enum_name, options = {})
|
80
|
+
|
81
|
+
Creates a new enum table. <code>enum_name</code> will be automatically pluralized. The following options are supported:
|
82
|
+
|
83
|
+
- [: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 <code>true</code> to have a 'description' column generated.
|
85
|
+
- [:name_limit] Set this define the limit of the name column.
|
86
|
+
- [:desc_limit] Set this to define the limit of the description column
|
87
|
+
- [:active] Set this to <code>true</code> to have a boolean 'active' column generated. The 'active' column will have the options of NOT NULL and DEFAULT TRUE.
|
88
|
+
|
89
|
+
Example:
|
90
|
+
|
91
|
+
create_enum :booking_status, :name_column => :booking_name,
|
92
|
+
:name_limit => 50,
|
93
|
+
:description => true,
|
94
|
+
:desc_limit => 100,
|
95
|
+
:active => true
|
96
|
+
|
97
|
+
is the equivalent of
|
98
|
+
|
99
|
+
create_table :booking_statuses do |t|
|
100
|
+
t.string :booking_name, :limit => 50, :null => false
|
101
|
+
t.string :description, :limit => 100
|
102
|
+
t.boolean :active, :null => false, :default => true
|
103
|
+
t.timestamps
|
104
|
+
end
|
105
|
+
|
106
|
+
##### remove_enum(enum_name)
|
107
|
+
|
108
|
+
Drops the enum table. <code>enum_name</code> will be automatically pluralized.
|
109
|
+
|
110
|
+
Example:
|
111
|
+
|
112
|
+
remove_enum :booking_status
|
113
|
+
|
114
|
+
is the equivalent of
|
115
|
+
|
116
|
+
drop_table :booking_statuses
|
62
117
|
|
63
118
|
### acts_as_enumerated
|
64
119
|
|
@@ -73,7 +128,7 @@ With that, your BookingStatus class will have the following methods defined:
|
|
73
128
|
|
74
129
|
#### Class Methods
|
75
130
|
|
76
|
-
##### []
|
131
|
+
##### [](arg)
|
77
132
|
|
78
133
|
<code>BookingStatus[arg]</code> performs a lookup the BookingStatus instance for arg. The arg value can be a 'string' or a :symbol, in which case the lookup will be against the BookingStatus.name field. Alternatively arg can be a Fixnum, in which case the lookup will be against the BookingStatus.id field.
|
79
134
|
|
@@ -85,6 +140,14 @@ The purpose of the :on_lookup_failure option is that a) under some circumstances
|
|
85
140
|
|
86
141
|
<code>BookingStatus.all</code> returns an array of all BookingStatus records that match the :conditions specified in acts_as_enumerated, in the order specified by :order.
|
87
142
|
|
143
|
+
##### active
|
144
|
+
|
145
|
+
<code>BookingStatus.active</code> returns an array of all BookingStatus records that are marked active. See the <code>active?</code> instance method.
|
146
|
+
|
147
|
+
##### inactive
|
148
|
+
|
149
|
+
<code>BookingStatus.inactive</code> returns an array of all BookingStatus records that are inactive. See the <code>inactive?</code> instance method.
|
150
|
+
|
88
151
|
#### Instance Methods
|
89
152
|
|
90
153
|
Each enumeration model gets the following instance methods.
|
@@ -109,6 +172,17 @@ Returns the 'name' of the enum, i.e. the value in the <code>:name_column</code>
|
|
109
172
|
|
110
173
|
Returns the symbol representation of the name of the enum. <code>BookingStatus[:foo].name_sym</code> returns :foo.
|
111
174
|
|
175
|
+
##### active?
|
176
|
+
|
177
|
+
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 'active'
|
179
|
+
class method to select active enums.
|
180
|
+
|
181
|
+
##### inactive?
|
182
|
+
|
183
|
+
Returns true if the instance is inactive, false otherwise. Default implementations returns !active?
|
184
|
+
This method is used by the 'inactive' class method to select inactive enums.
|
185
|
+
|
112
186
|
#### Notes
|
113
187
|
|
114
188
|
acts_as_enumerated records are considered immutable. By default you cannot create/alter/destroy instances because they are cached in memory. 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.
|
@@ -142,13 +216,17 @@ With that, your Booking class will have the following methods defined:
|
|
142
216
|
|
143
217
|
Returns the BookingStatus with an id that matches the value in the Booking.status_id.
|
144
218
|
|
145
|
-
#### status=
|
219
|
+
#### status=(arg)
|
146
220
|
|
147
221
|
Sets the value for Booking.status_id using the id of the BookingStatus instance passed as an argument. As a 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.
|
148
222
|
|
149
223
|
example:
|
150
224
|
|
151
225
|
mybooking.status = :confirmed
|
226
|
+
|
227
|
+
this also works:
|
228
|
+
|
229
|
+
mybooking.status = 'confirmed'
|
152
230
|
|
153
231
|
The <code>:on_lookup_failure</code> option in has_enumerated is there because you may want to create an error handler for situations where the argument passed to status= is invalid. By default, an invalid value will cause an ArgumentError to be raised.
|
154
232
|
|
@@ -45,7 +45,8 @@ module ActiveRecord
|
|
45
45
|
|
46
46
|
module ClassMethods
|
47
47
|
attr_accessor :enumeration_model_updates_permitted
|
48
|
-
|
48
|
+
|
49
|
+
# Returns all the enum values. Caches results after the first time this method is run.
|
49
50
|
def all
|
50
51
|
return @all if @all
|
51
52
|
@all = find(:all,
|
@@ -54,6 +55,18 @@ module ActiveRecord
|
|
54
55
|
).collect{|val| val.freeze}.freeze
|
55
56
|
end
|
56
57
|
|
58
|
+
# Returns all the active enum values. See the 'active?' instance method.
|
59
|
+
def active
|
60
|
+
return @all_active if @all_active
|
61
|
+
@all_active = all.select{ |enum| enum.active? }.freeze
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns all the inactive enum values. See the 'inactive?' instance method.
|
65
|
+
def inactive
|
66
|
+
return @all_inactive if @all_inactive
|
67
|
+
@all_inactive = all.select{ |enum| !enum.active? }.freeze
|
68
|
+
end
|
69
|
+
|
57
70
|
# Enum lookup by Symbol, String, or id.
|
58
71
|
def [](arg)
|
59
72
|
case arg
|
@@ -109,7 +122,7 @@ module ActiveRecord
|
|
109
122
|
unless self.enumeration_model_updates_permitted
|
110
123
|
raise "#{self.name}: cache purging disabled for your protection"
|
111
124
|
end
|
112
|
-
@all = @all_by_name = @all_by_id = nil
|
125
|
+
@all = @all_by_name = @all_by_id = @all_active = nil
|
113
126
|
end
|
114
127
|
|
115
128
|
# Returns the name of the column this enum uses as the basic underlying value.
|
@@ -194,7 +207,18 @@ module ActiveRecord
|
|
194
207
|
self.name.to_sym
|
195
208
|
end
|
196
209
|
|
197
|
-
|
210
|
+
# Returns true if the instance is active, false otherwise. If it has an attribute 'active',
|
211
|
+
# returns the attribute cast to a boolean, otherwise returns true. This method is used by the 'active'
|
212
|
+
# class method to select active enums.
|
213
|
+
def active?
|
214
|
+
@_active_status ||= ( attributes.include?('active') ? !!self.active : true )
|
215
|
+
end
|
216
|
+
|
217
|
+
# Returns true if the instance is inactive, false otherwise. Default implementations returns !active?
|
218
|
+
# This method is used by the 'inactive' class method to select inactive enums.
|
219
|
+
def inactive?
|
220
|
+
!active?
|
221
|
+
end
|
198
222
|
|
199
223
|
# NOTE: updating the models that back an acts_as_enumerated is
|
200
224
|
# rather dangerous because of rails' per-process model.
|
@@ -212,6 +236,7 @@ module ActiveRecord
|
|
212
236
|
false
|
213
237
|
end
|
214
238
|
end
|
239
|
+
private :enumeration_model_update
|
215
240
|
end
|
216
241
|
end
|
217
242
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module PowerEnum::Migration
|
2
|
+
|
3
|
+
module CommandRecorder
|
4
|
+
def create_enum(*args)
|
5
|
+
record(:create_enum, args)
|
6
|
+
end
|
7
|
+
|
8
|
+
def remove_enum(*args)
|
9
|
+
record(:remove_enum, args)
|
10
|
+
end
|
11
|
+
|
12
|
+
def invert_create_enum(args)
|
13
|
+
enum_name = args[0]
|
14
|
+
[:remove_enum, [enum_name]]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module PowerEnum::Schema
|
2
|
+
module SchemaStatements
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base::AbstractAdapter.class_eval do
|
6
|
+
include PowerEnum::Schema::AbstractAdapter
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
module AbstractAdapter
|
13
|
+
|
14
|
+
# Creates a new enum table. +enum_name+ will be automatically pluralized.
|
15
|
+
#
|
16
|
+
# === Supported options
|
17
|
+
# [:name_column]
|
18
|
+
# Specify the column name for name of the enum. By default it's :name.
|
19
|
+
# This can be a String or a Symbol
|
20
|
+
# [:description]
|
21
|
+
# Set this to <tt>true</tt> to have a 'description' column generated.
|
22
|
+
# [:name_limit]
|
23
|
+
# Set this define the limit of the name column.
|
24
|
+
# [:desc_limit]
|
25
|
+
# Set this to define the limit of the description column.
|
26
|
+
# [:active]
|
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
|
+
#
|
29
|
+
# ===== Examples
|
30
|
+
# ====== Basic Enum
|
31
|
+
# create_enum :connector_type
|
32
|
+
# is the equivalent of
|
33
|
+
# create_table :connector_types do |t|
|
34
|
+
# t.string :name, :null => false
|
35
|
+
# t.timestamps
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# ====== Advanced Enum
|
39
|
+
# create_enum :connector_type, :name_column => :connector, :name_limit => 50, :description => true, :desc_limit => 100, :active => true
|
40
|
+
# is the equivalent of
|
41
|
+
# create_table :connector_types do |t|
|
42
|
+
# t.string :connector, :limit => 50, :null => false
|
43
|
+
# t.string :description, :limit => 100
|
44
|
+
# t.boolean :active, :null => false, :default => true
|
45
|
+
# t.timestamps
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
def create_enum(enum_name, options = {})
|
49
|
+
enum_table_name = enum_name.pluralize
|
50
|
+
name_column = options[:name_column] || :name
|
51
|
+
generate_description = !!options[:description]
|
52
|
+
generate_active = !!options[:active]
|
53
|
+
name_limit = options[:name_limit]
|
54
|
+
desc_limit = options[:desc_limit]
|
55
|
+
|
56
|
+
create_table enum_table_name do |t|
|
57
|
+
t.string name_column, :limit => name_limit, :null => false
|
58
|
+
if generate_description
|
59
|
+
t.string :description, :limit => desc_limit
|
60
|
+
end
|
61
|
+
if generate_active
|
62
|
+
t.boolean :active, :null => false, :default => true
|
63
|
+
end
|
64
|
+
|
65
|
+
t.timestamps
|
66
|
+
end
|
67
|
+
|
68
|
+
add_index enum_table_name, [name_column], :unique => true
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
# Drops the enum table. +enum_name+ will be automatically pluralized.
|
73
|
+
#
|
74
|
+
# ===== Example
|
75
|
+
# remove_enum :connector_type
|
76
|
+
# is the equivalent of
|
77
|
+
# drop_table :connector_types
|
78
|
+
def remove_enum(enum_name)
|
79
|
+
drop_table enum_name.pluralize
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
data/lib/power_enum.rb
CHANGED
@@ -7,6 +7,17 @@ class PowerEnum < Rails::Engine
|
|
7
7
|
ActiveSupport.on_load(:active_record) do
|
8
8
|
include ActiveRecord::Acts::Enumerated
|
9
9
|
include ActiveRecord::Aggregations::HasEnumerated
|
10
|
+
|
11
|
+
ActiveRecord::ConnectionAdapters.module_eval do
|
12
|
+
include PowerEnum::Schema::SchemaStatements
|
13
|
+
end
|
14
|
+
|
15
|
+
if defined?(ActiveRecord::Migration::CommandRecorder)
|
16
|
+
ActiveRecord::Migration::CommandRecorder.class_eval do
|
17
|
+
include PowerEnum::Migration::CommandRecorder
|
18
|
+
end
|
19
|
+
end
|
10
20
|
end
|
21
|
+
|
11
22
|
end
|
12
23
|
end
|
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.
|
4
|
+
version: 0.3.0
|
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-23 00:00:00.000000000Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: rails
|
19
|
-
requirement: &
|
19
|
+
requirement: &18214180 !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: *18214180
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: jeweler
|
30
|
-
requirement: &
|
30
|
+
requirement: &18213580 !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: *18213580
|
39
39
|
- !ruby/object:Gem::Dependency
|
40
40
|
name: rspec
|
41
|
-
requirement: &
|
41
|
+
requirement: &18189680 !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: *18189680
|
50
50
|
- !ruby/object:Gem::Dependency
|
51
51
|
name: sqlite3
|
52
|
-
requirement: &
|
52
|
+
requirement: &18188860 !ruby/object:Gem::Requirement
|
53
53
|
none: false
|
54
54
|
requirements:
|
55
55
|
- - ! '>='
|
@@ -57,9 +57,19 @@ dependencies:
|
|
57
57
|
version: '0'
|
58
58
|
type: :development
|
59
59
|
prerelease: false
|
60
|
-
version_requirements: *
|
61
|
-
description:
|
62
|
-
were an enumeration of values
|
60
|
+
version_requirements: *18188860
|
61
|
+
description: ! 'Power Enum allows you to treat instances of your ActiveRecord models
|
62
|
+
as though they were an enumeration of values.
|
63
|
+
|
64
|
+
It allows you to cleanly solve many of the problems that the traditional Rails alternatives
|
65
|
+
handler poorly if at all.
|
66
|
+
|
67
|
+
It is particularly suitable for scenarios where your Rails application is not the
|
68
|
+
only user of the database, such as
|
69
|
+
|
70
|
+
when it''s used for analytics or reporting.
|
71
|
+
|
72
|
+
'
|
63
73
|
email: arthur.shagall@gmail.com
|
64
74
|
executables: []
|
65
75
|
extensions: []
|
@@ -72,6 +82,8 @@ files:
|
|
72
82
|
- lib/active_record/aggregations/has_enumerated.rb
|
73
83
|
- lib/active_record/virtual_enumerations.rb
|
74
84
|
- lib/power_enum.rb
|
85
|
+
- lib/power_enum/migration/command_recorder.rb
|
86
|
+
- lib/power_enum/schema/schema_statements.rb
|
75
87
|
- LICENSE
|
76
88
|
- README.md
|
77
89
|
homepage: http://github.com/albertosaurus/enumerations_mixin
|