power_enum 0.2.5 → 0.3.0
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.
- 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
|