power_enum 3.5.0 → 3.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,137 +2,141 @@
2
2
  # Copyright (c) 2012 Arthur Shagall
3
3
  # Released under the MIT License. See the LICENSE file for more details.
4
4
 
5
- # Implementation of has_enumerated
6
- module PowerEnum::HasEnumerated
7
-
8
- extend ActiveSupport::Concern
9
-
10
- # Class-level behavior injected into ActiveRecord to support has_enumerated
11
- module ClassMethods
12
-
13
- # Returns a list of all the attributes on the ActiveRecord model which are enumerated.
14
- def enumerated_attributes
15
- @enumerated_attributes ||= []
16
- end
17
-
18
- # Returns +true+ if +attribute+ is an enumerated attribute, +false+ otherwise.
19
- def has_enumerated?(attribute)
20
- return false if attribute.nil?
21
- enumerated_attributes.include? attribute.to_s
22
- end
23
-
24
- # Defines an enumerated attribute with the given attribute_name on the model. Also accepts a hash of options as an
25
- # optional second argument.
26
- #
27
- # === Supported options
28
- # [:class_name]
29
- # Name of the enum class. By default it is the camelized version of the has_enumerated attribute.
30
- # [:foreign_key]
31
- # Explicitly set the foreign key column. By default it's assumed to be your_enumerated_attribute_name_id.
32
- # [:on_lookup_failure]
33
- # The :on_lookup_failure option in has_enumerated is there because you may want to create an error handler for
34
- # situations where the argument passed to status=(arg) is invalid. By default, an invalid value will cause an
35
- # ArgumentError to be raised. Since this may not be optimal in your situation, you can do one of three
36
- # things:
37
- #
38
- # 1) You can set it to 'validation_error'. In this case, the invalid value will be cached and returned on
39
- # subsequent lookups, but the model will fail validation.
40
- # 2) You can specify an instance method to be called in the case of a lookup failure. The method signature is
41
- # as follows:
42
- # <tt>your_lookup_handler(operation, attribute_name, name_foreign_key, acts_enumerated_class_name, lookup_value)</tt>
43
- # The 'operation' arg will be either :read or :write. In the case of :read you are expected to return
44
- # something or raise an exception, while in the case of a :write you don't have to return anything. Note that
45
- # there's enough information in the method signature that you can specify one method to handle all lookup
46
- # failures for all has_enumerated fields if you happen to have more than one defined in your model.
47
- # 'NOTE': A nil is always considered to be a valid value for status=(arg) since it's assumed you're trying to
48
- # null out the foreign key. The :on_lookup_failure method will be bypassed.
49
- # 3) You can give it a lambda function. In that case, the lambda needs to accept the ActiveRecord model as
50
- # its first argument, with the rest of the arguments being identical to the signature of the lookup handler
51
- # instance method.
52
- # [:permit_empty_name]
53
- # Setting this to 'true' disables automatic conversion of empty strings to nil. Default is 'false'.
54
- # [:default]
55
- # Setting this option will generate an after_initialize callback to set a default value on the attribute
56
- # unless a non-nil one already exists.
57
- # [:create_scope]
58
- # Setting this option to 'false' will disable automatically creating 'with_enum_attribute' and
59
- # 'exclude_enum_attribute' scope.
60
- #
61
- # === Example
62
- # class Booking < ActiveRecord::Base
63
- # has_enumerated :status,
64
- # :class_name => 'BookingStatus',
65
- # :foreign_key => 'status_id',
66
- # :on_lookup_failure => :optional_instance_method,
67
- # :permit_empty_name => true,
68
- # :default => :unconfirmed,
69
- # :create_cope => false
70
- # end
71
- #
72
- # === Example 2
73
- #
74
- # class Booking < ActiveRecord::Base
75
- # has_enumerated :booking_status,
76
- # :class_name => 'BookingStatus',
77
- # :foreign_key => 'status_id',
78
- # :on_lookup_failure => lambda{ |record, op, attr, fk, cl_name, value|
79
- # # handle lookup failure
80
- # }
81
- # end
82
- def has_enumerated(part_id, options = {})
83
- options.assert_valid_keys( :class_name,
84
- :foreign_key,
85
- :on_lookup_failure,
86
- :permit_empty_name,
87
- :default,
88
- :create_scope )
89
-
90
- # Add a reflection for the enumerated attribute.
91
- reflection = create_ar_reflection(part_id, options)
92
-
93
- attribute_name = part_id.to_s
94
- class_name = reflection.class_name
95
- foreign_key = reflection.foreign_key
96
- failure_opt = options[:on_lookup_failure]
97
- allow_empty_name = options[:permit_empty_name]
98
- create_scope = options[:create_scope]
99
-
100
- failure_handler = get_lookup_failure_handler(failure_opt)
101
-
102
- class_attribute "has_enumerated_#{attribute_name}_error_handler"
103
- self.send( "has_enumerated_#{attribute_name}_error_handler=", failure_handler )
104
-
105
- define_enum_accessor attribute_name, class_name, foreign_key, failure_handler
106
- define_enum_writer attribute_name, class_name, foreign_key, failure_handler, allow_empty_name
107
-
108
- if failure_opt.to_s == 'validation_error'
109
- define_validation_error( attribute_name )
110
- end
5
+ module PowerEnum
6
+
7
+ # Implementation of has_enumerated
8
+ module HasEnumerated
9
+
10
+ extend ActiveSupport::Concern
111
11
 
112
- enumerated_attributes << attribute_name
12
+ # Class-level behavior injected into ActiveRecord to support has_enumerated
13
+ module ClassMethods
14
+
15
+ # Returns a list of all the attributes on the ActiveRecord model which are enumerated.
16
+ def enumerated_attributes
17
+ @enumerated_attributes ||= []
18
+ end
113
19
 
114
- if options.has_key?(:default)
115
- define_default_enum_value( attribute_name, options[:default] )
20
+ # Returns +true+ if +attribute+ is an enumerated attribute, +false+ otherwise.
21
+ def has_enumerated?(attribute)
22
+ return false if attribute.nil?
23
+ enumerated_attributes.include? attribute.to_s
116
24
  end
117
25
 
118
- unless create_scope == false
119
- define_enum_scope( attribute_name, class_name, foreign_key )
26
+ # Defines an enumerated attribute with the given attribute_name on the model. Also accepts a hash of options as an
27
+ # optional second argument.
28
+ #
29
+ # === Supported options
30
+ # [:class_name]
31
+ # Name of the enum class. By default it is the camelized version of the has_enumerated attribute.
32
+ # [:foreign_key]
33
+ # Explicitly set the foreign key column. By default it's assumed to be your_enumerated_attribute_name_id.
34
+ # [:on_lookup_failure]
35
+ # The :on_lookup_failure option in has_enumerated is there because you may want to create an error handler for
36
+ # situations where the argument passed to status=(arg) is invalid. By default, an invalid value will cause an
37
+ # ArgumentError to be raised. Since this may not be optimal in your situation, you can do one of three
38
+ # things:
39
+ #
40
+ # 1) You can set it to 'validation_error'. In this case, the invalid value will be cached and returned on
41
+ # subsequent lookups, but the model will fail validation.
42
+ # 2) You can specify an instance method to be called in the case of a lookup failure. The method signature is
43
+ # as follows:
44
+ # <tt>your_lookup_handler(operation, attribute_name, name_foreign_key, acts_enumerated_class_name, lookup_value)</tt>
45
+ # The 'operation' arg will be either :read or :write. In the case of :read you are expected to return
46
+ # something or raise an exception, while in the case of a :write you don't have to return anything. Note that
47
+ # there's enough information in the method signature that you can specify one method to handle all lookup
48
+ # failures for all has_enumerated fields if you happen to have more than one defined in your model.
49
+ # 'NOTE': A nil is always considered to be a valid value for status=(arg) since it's assumed you're trying to
50
+ # null out the foreign key. The :on_lookup_failure method will be bypassed.
51
+ # 3) You can give it a lambda function. In that case, the lambda needs to accept the ActiveRecord model as
52
+ # its first argument, with the rest of the arguments being identical to the signature of the lookup handler
53
+ # instance method.
54
+ # [:permit_empty_name]
55
+ # Setting this to 'true' disables automatic conversion of empty strings to nil. Default is 'false'.
56
+ # [:default]
57
+ # Setting this option will generate an after_initialize callback to set a default value on the attribute
58
+ # unless a non-nil one already exists.
59
+ # [:create_scope]
60
+ # Setting this option to 'false' will disable automatically creating 'with_enum_attribute' and
61
+ # 'exclude_enum_attribute' scope.
62
+ #
63
+ # === Example
64
+ # class Booking < ActiveRecord::Base
65
+ # has_enumerated :status,
66
+ # :class_name => 'BookingStatus',
67
+ # :foreign_key => 'status_id',
68
+ # :on_lookup_failure => :optional_instance_method,
69
+ # :permit_empty_name => true,
70
+ # :default => :unconfirmed,
71
+ # :create_cope => false
72
+ # end
73
+ #
74
+ # === Example 2
75
+ #
76
+ # class Booking < ActiveRecord::Base
77
+ # has_enumerated :booking_status,
78
+ # :class_name => 'BookingStatus',
79
+ # :foreign_key => 'status_id',
80
+ # :on_lookup_failure => lambda{ |record, op, attr, fk, cl_name, value|
81
+ # # handle lookup failure
82
+ # }
83
+ # end
84
+ def has_enumerated(part_id, options = {})
85
+ options.assert_valid_keys(:class_name,
86
+ :foreign_key,
87
+ :on_lookup_failure,
88
+ :permit_empty_name,
89
+ :default,
90
+ :create_scope)
91
+
92
+ # Add a reflection for the enumerated attribute.
93
+ reflection = create_ar_reflection(part_id, options)
94
+
95
+ attribute_name = part_id.to_s
96
+ class_name = reflection.class_name
97
+ foreign_key = reflection.foreign_key
98
+ failure_opt = options[:on_lookup_failure]
99
+ allow_empty_name = options[:permit_empty_name]
100
+ create_scope = options[:create_scope]
101
+
102
+ failure_handler = get_lookup_failure_handler(failure_opt)
103
+
104
+ class_attribute "has_enumerated_#{attribute_name}_error_handler"
105
+ self.send("has_enumerated_#{attribute_name}_error_handler=", failure_handler)
106
+
107
+ define_enum_accessor attribute_name, class_name, foreign_key, failure_handler
108
+ define_enum_writer attribute_name, class_name, foreign_key, failure_handler, allow_empty_name
109
+
110
+ if failure_opt.to_s == 'validation_error'
111
+ define_validation_error(attribute_name)
112
+ end
113
+
114
+ enumerated_attributes << attribute_name
115
+
116
+ if options.has_key?(:default)
117
+ define_default_enum_value(attribute_name, options[:default])
118
+ end
119
+
120
+ unless create_scope == false
121
+ define_enum_scope(attribute_name, class_name, foreign_key)
122
+ end
123
+
120
124
  end
121
125
 
122
- end # has_enumerated
126
+ # has_enumerated
123
127
 
124
- # Creates the ActiveRecord reflection
125
- def create_ar_reflection(part_id, options)
126
- reflection = PowerEnum::Reflection::EnumerationReflection.new(part_id, options, self)
128
+ # Creates the ActiveRecord reflection
129
+ private def create_ar_reflection(part_id, options)
130
+ reflection = PowerEnum::Reflection::EnumerationReflection.new(part_id, options, self)
127
131
 
128
- self._reflections = self._reflections.merge(part_id.to_s => reflection)
129
- reflection
130
- end
131
- private :create_ar_reflection
132
+ self._reflections = self._reflections.merge(part_id.to_s => reflection)
133
+ reflection
134
+ end
132
135
 
133
- # Defines the accessor method
134
- def define_enum_accessor(attribute_name, class_name, foreign_key, failure_handler) #:nodoc:
135
- module_eval( <<-end_eval, __FILE__, __LINE__ )
136
+ # Defines the accessor method
137
+ private def define_enum_accessor(attribute_name, class_name, foreign_key, failure_handler)
138
+ #:nodoc:
139
+ module_eval(<<-end_eval, __FILE__, __LINE__)
136
140
  def #{attribute_name}
137
141
  if @invalid_enum_values && @invalid_enum_values.has_key?(:#{attribute_name})
138
142
  return @invalid_enum_values[:#{attribute_name}]
@@ -144,13 +148,13 @@ module PowerEnum::HasEnumerated
144
148
  rval
145
149
  end
146
150
  end
147
- end_eval
148
- end
149
- private :define_enum_accessor
151
+ end_eval
152
+ end
150
153
 
151
- # Defines the enum attribute writer method
152
- def define_enum_writer(attribute_name, class_name, foreign_key, failure_handler, allow_empty_name) #:nodoc:
153
- module_eval( <<-end_eval, __FILE__, __LINE__ )
154
+ # Defines the enum attribute writer method
155
+ private def define_enum_writer(attribute_name, class_name, foreign_key, failure_handler, allow_empty_name)
156
+ #:nodoc:
157
+ module_eval(<<-end_eval, __FILE__, __LINE__)
154
158
  def #{attribute_name}=(arg)
155
159
  @invalid_enum_values ||= {}
156
160
 
@@ -186,26 +190,26 @@ module PowerEnum::HasEnumerated
186
190
  end
187
191
 
188
192
  alias_method :'#{attribute_name}_bak=', :'#{attribute_name}='
189
- end_eval
190
- end
191
- private :define_enum_writer
193
+ end_eval
194
+ end
192
195
 
193
- # Defines the default value for the enumerated attribute.
194
- def define_default_enum_value(attribute_name, default) #:nodoc:
195
- set_default_method = "set_default_value_for_#{attribute_name}".to_sym
196
+ # Defines the default value for the enumerated attribute.
197
+ private def define_default_enum_value(attribute_name, default)
198
+ #:nodoc:
199
+ set_default_method = "set_default_value_for_#{attribute_name}".to_sym
196
200
 
197
- after_initialize set_default_method
201
+ after_initialize set_default_method
198
202
 
199
- define_method set_default_method do
200
- self.send("#{attribute_name}=", default) if self.send(attribute_name).nil?
203
+ define_method set_default_method do
204
+ self.send("#{attribute_name}=", default) if self.send(attribute_name).nil?
205
+ end
206
+ private set_default_method
201
207
  end
202
- private set_default_method
203
- end
204
- private :define_default_enum_value
205
208
 
206
- # Defines validation_error handling mechanism
207
- def define_validation_error(attribute_name) #:nodoc:
208
- module_eval(<<-end_eval, __FILE__, __LINE__)
209
+ # Defines validation_error handling mechanism
210
+ private def define_validation_error(attribute_name)
211
+ #:nodoc:
212
+ module_eval(<<-end_eval, __FILE__, __LINE__)
209
213
  validate do
210
214
  if @invalid_enum_values && @invalid_enum_values.has_key?(:#{attribute_name})
211
215
  errors.add(:#{attribute_name}, "is invalid")
@@ -221,13 +225,13 @@ module PowerEnum::HasEnumerated
221
225
  end
222
226
  end
223
227
  private :validation_error
224
- end_eval
225
- end
226
- private :define_validation_error
228
+ end_eval
229
+ end
227
230
 
228
- # Defines the enum scopes on the model
229
- def define_enum_scope(attribute_name, class_name, foreign_key) #:nodoc:
230
- module_eval(<<-end_eval, __FILE__, __LINE__)
231
+ # Defines the enum scopes on the model
232
+ private def define_enum_scope(attribute_name, class_name, foreign_key)
233
+ #:nodoc:
234
+ module_eval(<<-end_eval, __FILE__, __LINE__)
231
235
  scope :with_#{attribute_name}, lambda { |*args|
232
236
  ids = args.map{ |arg|
233
237
  n = #{class_name}[arg]
@@ -240,37 +244,36 @@ module PowerEnum::HasEnumerated
240
244
  }
241
245
  where(:#{foreign_key} => ids)
242
246
  }
243
- end_eval
247
+ end_eval
244
248
 
245
- if (name_p = attribute_name.pluralize) != attribute_name
246
- module_eval(<<-end_eval, __FILE__, __LINE__)
249
+ if (name_p = attribute_name.pluralize) != attribute_name
250
+ module_eval(<<-end_eval, __FILE__, __LINE__)
247
251
  class << self
248
252
  alias_method :with_#{name_p}, :with_#{attribute_name}
249
253
  alias_method :exclude_#{name_p}, :exclude_#{attribute_name}
250
254
  end
251
- end_eval
255
+ end_eval
256
+ end
252
257
  end
253
- end
254
- private :define_enum_scope
255
-
256
- # If the lookup failure handler is a method attribute_name, wraps it in a lambda.
257
- def get_lookup_failure_handler(failure_opt) # :nodoc:
258
- if failure_opt.nil?
259
- nil
260
- else
261
- case failure_opt
262
- when Proc
263
- failure_opt
258
+
259
+ # If the lookup failure handler is a method attribute_name, wraps it in a lambda.
260
+ private def get_lookup_failure_handler(failure_opt)
261
+ # :nodoc:
262
+ if failure_opt.nil?
263
+ nil
264
264
  else
265
- lambda { |record, op, attr, fk, cl_name, value|
266
- record.send(failure_opt.to_s, op, attr, fk, cl_name, value)
267
- }
268
- end
265
+ case failure_opt
266
+ when Proc
267
+ failure_opt
268
+ else
269
+ lambda { |record, op, attr, fk, cl_name, value|
270
+ record.send(failure_opt.to_s, op, attr, fk, cl_name, value)
271
+ }
272
+ end
269
273
 
274
+ end
270
275
  end
271
- end
272
- private :get_lookup_failure_handler
273
-
274
- end #module MacroMethods
275
276
 
277
+ end #module MacroMethods
278
+ end
276
279
  end #module PowerEnum::HasEnumerated
data/lib/power_enum.rb CHANGED
@@ -2,34 +2,44 @@ require 'rails'
2
2
  require 'active_record'
3
3
  require 'testing/rspec'
4
4
 
5
+ require "power_enum/has_enumerated"
6
+ require "power_enum/enumerated"
7
+ require "power_enum/reflection"
8
+
9
+ require "power_enum/schema/schema_statements"
10
+ require "power_enum/migration/command_recorder"
11
+
12
+ require "active_record/virtual_enumerations"
13
+
5
14
  # Power Enum allows you to treat instances of your ActiveRecord models as
6
15
  # though they were an enumeration of values. It allows you to cleanly solve
7
16
  # many of the problems that the traditional Rails alternatives handle poorly
8
17
  # if at all. It is particularly suitable for scenarios where your Rails
9
18
  # application is not the only user of the database, such as when it's used for
10
19
  # analytics or reporting.
11
- class PowerEnum < Rails::Engine
12
- config.autoload_paths << File.expand_path(File.join(__FILE__, "../"))
20
+ module PowerEnum
21
+ class Engine < Rails::Engine
13
22
 
14
- initializer 'power_enum' do
15
- ActiveSupport.on_load(:active_record) do
16
- include PowerEnum::Enumerated
17
- include PowerEnum::HasEnumerated
23
+ initializer 'power_enum' do
24
+ ActiveSupport.on_load(:active_record) do
25
+ include PowerEnum::Enumerated
26
+ include PowerEnum::HasEnumerated
18
27
 
19
- ActiveRecord::Base.module_eval do
20
- class << self
21
- prepend ::PowerEnum::Reflection
28
+ ActiveRecord::Base.module_eval do
29
+ class << self
30
+ prepend ::PowerEnum::Reflection
31
+ end
22
32
  end
23
- end
24
33
 
25
- ActiveRecord::ConnectionAdapters.module_eval do
26
- include PowerEnum::Schema::SchemaStatements
27
- end
34
+ ActiveRecord::ConnectionAdapters.module_eval do
35
+ include PowerEnum::Schema::SchemaStatements
36
+ end
28
37
 
29
- ActiveRecord::Migration::CommandRecorder.class_eval do
30
- include PowerEnum::Migration::CommandRecorder
38
+ ActiveRecord::Migration::CommandRecorder.class_eval do
39
+ include PowerEnum::Migration::CommandRecorder
40
+ end
31
41
  end
32
- end
33
42
 
43
+ end
34
44
  end
35
45
  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: 3.5.0
4
+ version: 3.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Trevor Squires
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2021-01-05 00:00:00.000000000 Z
14
+ date: 2021-12-08 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -126,9 +126,11 @@ extensions: []
126
126
  extra_rdoc_files:
127
127
  - LICENSE
128
128
  - README.markdown
129
+ - VERSION
129
130
  files:
130
131
  - LICENSE
131
132
  - README.markdown
133
+ - VERSION
132
134
  - lib/active_record/virtual_enumerations.rb
133
135
  - lib/generators/enum/USAGE
134
136
  - lib/generators/enum/enum_generator.rb