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 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
- ActiveRecord models as though they were an enumeration of values.
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 mot the core ideas remain,
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.update_attribute(:status, BookingStatus[:confirmed])
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
- To use this version, add the gem to your Gemfile
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. At a minimum, the database table for an acts_as_enumerated must contain an 'id' column and a 'name' column. All instances for the acts_as_enumerated model are cached in memory.
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 cluttering up your models directory with acts_as_enumerated classes.
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
- create_table :booking_statuses do |t|
49
- t.string :name
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
- t.timestamps
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
- private
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.2.5
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-18 00:00:00.000000000Z
15
+ date: 2011-09-23 00:00:00.000000000Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: rails
19
- requirement: &15753300 !ruby/object:Gem::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: *15753300
27
+ version_requirements: *18214180
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: jeweler
30
- requirement: &15752440 !ruby/object:Gem::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: *15752440
38
+ version_requirements: *18213580
39
39
  - !ruby/object:Gem::Dependency
40
40
  name: rspec
41
- requirement: &15751840 !ruby/object:Gem::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: *15751840
49
+ version_requirements: *18189680
50
50
  - !ruby/object:Gem::Dependency
51
51
  name: sqlite3
52
- requirement: &15751240 !ruby/object:Gem::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: *15751240
61
- description: Allows you to treat instances of your ActiveRecord models as though they
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