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 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