power_enum 0.8.6 → 0.9.1
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 → README.markdown} +315 -157
- data/lib/active_record/virtual_enumerations.rb +132 -48
- data/lib/power_enum/enumerated.rb +405 -0
- data/lib/power_enum/has_enumerated.rb +234 -0
- data/lib/power_enum.rb +18 -2
- metadata +7 -8
- data/examples/virtual_enumerations_sample.rb +0 -76
- data/lib/active_record/acts/enumerated.rb +0 -395
- data/lib/active_record/aggregations/has_enumerated.rb +0 -238
@@ -1,68 +1,152 @@
|
|
1
1
|
# Copyright (c) 2005 Trevor Squires
|
2
|
+
# Copyright (c) 2012 Arthur Shagall
|
2
3
|
# Released under the MIT License. See the LICENSE file for more details.
|
3
4
|
|
4
|
-
module ActiveRecord
|
5
|
+
module ActiveRecord # :nodoc:
|
6
|
+
|
7
|
+
# Implements a mechanism to synthesize enum classes for simple enums. This is for situations where you wish to avoid
|
8
|
+
# cluttering the models directory with your enums.
|
9
|
+
#
|
10
|
+
# Create a custom Rails initializer: Rails.root/config/initializers/virtual_enumerations.rb
|
11
|
+
#
|
12
|
+
# ActiveRecord::VirtualEnumerations.define do |config|
|
13
|
+
# config.define 'ClassName',
|
14
|
+
# :table_name => 'table',
|
15
|
+
# :extends => 'SuperclassName',
|
16
|
+
# :conditions => ['something = ?', "value"],
|
17
|
+
# :order => 'column ASC',
|
18
|
+
# :on_lookup_failure => :enforce_strict,
|
19
|
+
# :name_column => 'name_column',
|
20
|
+
# :alias_name => false {
|
21
|
+
# # class_evaled_functions
|
22
|
+
# }
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# Only the 'ClassName' argument is required. :table_name is used to define a custom table name while the :extends
|
26
|
+
# option is used to set a custom superclass. Class names can be either camel-cased like ClassName or with
|
27
|
+
# underscores, like class_name. Strings and symbols are both fine.
|
28
|
+
#
|
29
|
+
# If you need to fine-tune the definition of the enum class, you can optionally pass in a block, which will be
|
30
|
+
# evaluated in the context of the enum class.
|
31
|
+
#
|
32
|
+
# Example:
|
33
|
+
#
|
34
|
+
# config.define :color, :on_lookup_failure => :enforce_strict, do
|
35
|
+
# def to_argb(alpha)
|
36
|
+
# case self.to_sym
|
37
|
+
# when :white
|
38
|
+
# [alpha, 255, 255, 255]
|
39
|
+
# when :red
|
40
|
+
# [alpha, 255, 0, 0]
|
41
|
+
# when :blue
|
42
|
+
# [alpha, 0, 0, 255]
|
43
|
+
# when :yellow
|
44
|
+
# [alpha, 255, 255, 0]
|
45
|
+
# when :black
|
46
|
+
# [alpha, 0, 0, 0]
|
47
|
+
# end
|
48
|
+
# end
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# As a convenience, if multiple enums share the same configuration, you can pass all of them to config.define.
|
52
|
+
#
|
53
|
+
# Example:
|
54
|
+
#
|
55
|
+
# config.define :booking_status, :connector_type, :color, :order => :name
|
56
|
+
#
|
57
|
+
# STI is also supported:
|
58
|
+
#
|
59
|
+
# Example:
|
60
|
+
#
|
61
|
+
# config.define :base_enum, :name_column => ;foo
|
62
|
+
# config.define :booking_status, :connector_type, :color, :extends => :base_enum
|
5
63
|
module VirtualEnumerations # :nodoc:
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
64
|
+
|
65
|
+
# Defines enumeration classes. Passes a config object to the given block
|
66
|
+
# which is used to define the virtual enumerations. Call config.define for
|
67
|
+
# each enum or enums with a given set of options.
|
68
|
+
def self.define
|
69
|
+
raise ArgumentError, "#{self.name}: must pass a block to define()" unless block_given?
|
70
|
+
config = ActiveRecord::VirtualEnumerations::Config.new
|
71
|
+
yield config
|
72
|
+
@config = config # we only overwrite config if no exceptions were thrown
|
73
|
+
end
|
74
|
+
|
75
|
+
# Creates a constant for a virtual enum if a config is defined for it.
|
76
|
+
def self.synthesize_if_defined(const)
|
77
|
+
if @config && options = @config[const]
|
78
|
+
class_declaration = "class #{const} < #{options[:extends]}; end"
|
79
|
+
|
80
|
+
eval( class_declaration, TOPLEVEL_BINDING, __FILE__, __LINE__ )
|
81
|
+
|
82
|
+
virtual_enum_class = const_get( const )
|
83
|
+
|
84
|
+
inject_class_options( virtual_enum_class, options )
|
85
|
+
|
86
|
+
virtual_enum_class
|
87
|
+
else
|
88
|
+
nil
|
12
89
|
end
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.inject_class_options( virtual_enum_class, options ) # :nodoc:
|
93
|
+
# Declare it acts_as_enumerated
|
94
|
+
virtual_enum_class.class_eval do
|
95
|
+
acts_as_enumerated :conditions => options[:conditions],
|
96
|
+
:order => options[:order],
|
97
|
+
:on_lookup_failure => options[:on_lookup_failure],
|
98
|
+
:name_column => options[:name_column],
|
99
|
+
:alias_name => options[:table_name]
|
100
|
+
end
|
101
|
+
|
102
|
+
# If necessary, set the table name
|
103
|
+
unless (table_name = options[:table_name]).blank?
|
104
|
+
virtual_enum_class.class_eval do
|
105
|
+
self.table_name = table_name
|
29
106
|
end
|
30
|
-
|
31
|
-
|
107
|
+
end
|
108
|
+
|
109
|
+
if block = options[:customizations_block]
|
110
|
+
virtual_enum_class.class_eval(&block)
|
111
|
+
end
|
32
112
|
end
|
33
|
-
|
113
|
+
private_class_method :inject_class_options
|
114
|
+
|
115
|
+
# Config class for VirtualEnumerations
|
34
116
|
class Config
|
35
|
-
def initialize
|
117
|
+
def initialize # :nodoc:
|
36
118
|
@enumeration_defs = {}
|
37
119
|
end
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
120
|
+
|
121
|
+
# Creates definition(s) for one or more enums.
|
122
|
+
def define(*args, &block)
|
123
|
+
options = args.extract_options!
|
124
|
+
args.compact!
|
125
|
+
args.flatten!
|
126
|
+
args.each do |class_name|
|
127
|
+
camel_name = class_name.to_s.camelize
|
128
|
+
if camel_name.blank?
|
129
|
+
raise ArgumentError, "ActiveRecord::VirtualEnumerations.define - invalid class_name argument (#{class_name.inspect})"
|
130
|
+
end
|
131
|
+
if @enumeration_defs[camel_name.to_sym]
|
132
|
+
raise ArgumentError, "ActiveRecord::VirtualEnumerations.define - class_name already defined (#{camel_name})"
|
133
|
+
end
|
134
|
+
options.assert_valid_keys(:table_name, :extends, :conditions, :order, :on_lookup_failure, :name_column, :alias_name)
|
45
135
|
enum_def = options.clone
|
46
|
-
enum_def[:extends]
|
47
|
-
|
136
|
+
enum_def[:extends] = if superclass = enum_def[:extends]
|
137
|
+
superclass.to_s.camelize
|
138
|
+
else
|
139
|
+
"ActiveRecord::Base"
|
140
|
+
end
|
141
|
+
enum_def[:customizations_block] = block
|
48
142
|
@enumeration_defs[camel_name.to_sym] = enum_def
|
49
143
|
end
|
50
144
|
end
|
51
|
-
|
145
|
+
|
146
|
+
# Proxies lookups to @enumeration_defs
|
52
147
|
def [](arg)
|
53
148
|
@enumeration_defs[arg]
|
54
149
|
end
|
55
150
|
end #class Config
|
56
151
|
end #module VirtualEnumerations
|
57
152
|
end #module ActiveRecord
|
58
|
-
|
59
|
-
class Module # :nodoc:
|
60
|
-
alias_method :enumerations_original_const_missing, :const_missing
|
61
|
-
def const_missing(const_id)
|
62
|
-
# let rails have a go at loading it
|
63
|
-
enumerations_original_const_missing(const_id)
|
64
|
-
rescue NameError
|
65
|
-
# now it's our turn
|
66
|
-
ActiveRecord::VirtualEnumerations.synthesize_if_defined(const_id) or raise
|
67
|
-
end
|
68
|
-
end
|
@@ -0,0 +1,405 @@
|
|
1
|
+
# Copyright (c) 2005 Trevor Squires
|
2
|
+
# Copyright (c) 2012 Arthur Shagall
|
3
|
+
# Released under the MIT License. See the LICENSE file for more details.
|
4
|
+
|
5
|
+
module PowerEnum::Enumerated
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
|
10
|
+
# Returns false for ActiveRecord models that do not act as enumerated.
|
11
|
+
def acts_as_enumerated?
|
12
|
+
false
|
13
|
+
end
|
14
|
+
|
15
|
+
# Declares the model as enumerated. See the README for detailed usage instructions.
|
16
|
+
#
|
17
|
+
# === Supported options
|
18
|
+
# [:conditions]
|
19
|
+
# SQL search conditions
|
20
|
+
# [:order]
|
21
|
+
# SQL load order clause
|
22
|
+
# [:on_lookup_failure]
|
23
|
+
# Specifies the name of a class method to invoke when the +[]+ method is unable to locate a BookingStatus
|
24
|
+
# record for arg. The default is the built-in :enforce_none which returns nil. There are also built-ins for
|
25
|
+
# :enforce_strict (raise and exception regardless of the type for arg), :enforce_strict_literals (raises an
|
26
|
+
# exception if the arg is a Fixnum or Symbol), :enforce_strict_ids (raises and exception if the arg is a
|
27
|
+
# Fixnum) and :enforce_strict_symbols (raises an exception if the arg is a Symbol). The purpose of the
|
28
|
+
# :on_lookup_failure option is that a) under some circumstances a lookup failure is a Bad Thing and action
|
29
|
+
# should be taken, therefore b) a fallback action should be easily configurable. You can also give it a
|
30
|
+
# lambda that takes in a single argument (The arg that was passed to +[]+).
|
31
|
+
# [:name_column]
|
32
|
+
# Override for the 'name' column. By default, assumed to be 'name'.
|
33
|
+
# [:alias_name]
|
34
|
+
# By default, if a name column is not 'name', will create an alias of 'name' to the name_column attribute. Set
|
35
|
+
# this to +false+ if you don't want this behavior.
|
36
|
+
#
|
37
|
+
# === Examples
|
38
|
+
#
|
39
|
+
# ====Example 1
|
40
|
+
# class BookingStatus < ActiveRecord::Base
|
41
|
+
# acts_as_enumerated
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# ====Example 2
|
45
|
+
# class BookingStatus < ActiveRecord::Base
|
46
|
+
# acts_as_enumerated :on_lookup_failure => :enforce_strict
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# ====Example 3
|
50
|
+
# class BookingStatus < ActiveRecord::Base
|
51
|
+
# acts_as_enumerated :conditions => [:exclude => false],
|
52
|
+
# :order => 'created_at DESC',
|
53
|
+
# :on_lookup_failure => :lookup_failed,
|
54
|
+
# :name_column => :status_code
|
55
|
+
#
|
56
|
+
# def self.lookup_failed(arg)
|
57
|
+
# logger.error("Invalid status code lookup #{arg.inspect}")
|
58
|
+
# nil
|
59
|
+
# end
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# ====Example 4
|
63
|
+
# class BookingStatus < ActiveRecord::Base
|
64
|
+
# acts_as_enumerated :conditions => [:exclude => false],
|
65
|
+
# :order => 'created_at DESC',
|
66
|
+
# :on_lookup_failure => lambda { |arg| raise CustomError, "BookingStatus lookup failed; #{arg}" },
|
67
|
+
# :name_column => :status_code
|
68
|
+
# end
|
69
|
+
def acts_as_enumerated(options = {})
|
70
|
+
valid_keys = [:conditions, :order, :on_lookup_failure, :name_column, :alias_name]
|
71
|
+
options.assert_valid_keys(*valid_keys)
|
72
|
+
|
73
|
+
valid_keys.each do |key|
|
74
|
+
class_attribute "acts_enumerated_#{key.to_s}"
|
75
|
+
if options.has_key?( key )
|
76
|
+
self.send "acts_enumerated_#{key.to_s}=", options[key]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
name_column = if options.has_key?(:name_column) && !options[:name_column].blank? then
|
81
|
+
options[:name_column].to_s.to_sym
|
82
|
+
else
|
83
|
+
:name
|
84
|
+
end
|
85
|
+
|
86
|
+
alias_name = if options.has_key?(:alias_name) then
|
87
|
+
options[:alias_name]
|
88
|
+
else
|
89
|
+
true
|
90
|
+
end
|
91
|
+
|
92
|
+
class_attribute :acts_enumerated_name_column
|
93
|
+
self.acts_enumerated_name_column = name_column
|
94
|
+
|
95
|
+
unless self.is_a? PowerEnum::Enumerated::EnumClassMethods
|
96
|
+
extend PowerEnum::Enumerated::EnumClassMethods
|
97
|
+
|
98
|
+
class_eval do
|
99
|
+
include PowerEnum::Enumerated::EnumInstanceMethods
|
100
|
+
|
101
|
+
before_save :enumeration_model_update
|
102
|
+
before_destroy :enumeration_model_update
|
103
|
+
validates name_column, :presence => true, :uniqueness => true
|
104
|
+
|
105
|
+
define_method :__enum_name__ do
|
106
|
+
read_attribute( name_column ).to_s
|
107
|
+
end
|
108
|
+
|
109
|
+
if alias_name && name_column != :name
|
110
|
+
alias_method :name, :__enum_name__
|
111
|
+
end
|
112
|
+
end # class_eval
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
module EnumClassMethods
|
118
|
+
attr_accessor :enumeration_model_updates_permitted
|
119
|
+
|
120
|
+
# Returns true for ActiveRecord models that act as enumerated.
|
121
|
+
def acts_as_enumerated?
|
122
|
+
true
|
123
|
+
end
|
124
|
+
|
125
|
+
# Returns all the enum values. Caches results after the first time this method is run.
|
126
|
+
def all
|
127
|
+
return @all if @all
|
128
|
+
conditions = self.acts_enumerated_conditions
|
129
|
+
order = self.acts_enumerated_order
|
130
|
+
@all = where(conditions).order(order).collect{|val| val.freeze}.freeze
|
131
|
+
end
|
132
|
+
|
133
|
+
# Returns all the active enum values. See the 'active?' instance method.
|
134
|
+
def active
|
135
|
+
return @all_active if @all_active
|
136
|
+
@all_active = all.select{ |enum| enum.active? }.freeze
|
137
|
+
end
|
138
|
+
|
139
|
+
# Returns all the inactive enum values. See the 'inactive?' instance method.
|
140
|
+
def inactive
|
141
|
+
return @all_inactive if @all_inactive
|
142
|
+
@all_inactive = all.select{ |enum| !enum.active? }.freeze
|
143
|
+
end
|
144
|
+
|
145
|
+
# Returns the names of all the enum values as an array of symbols.
|
146
|
+
def names
|
147
|
+
all.map { |item| item.name_sym }
|
148
|
+
end
|
149
|
+
|
150
|
+
# Enum lookup by Symbol, String, or id. Returns <tt>arg<tt> if arg is
|
151
|
+
# an enum instance. Passing in a list of arguments returns a list of enums.
|
152
|
+
def [](*args)
|
153
|
+
case args.size
|
154
|
+
when 0
|
155
|
+
nil
|
156
|
+
when 1
|
157
|
+
arg = args.first
|
158
|
+
case arg
|
159
|
+
when Symbol
|
160
|
+
return_val = lookup_name(arg.id2name) and return return_val
|
161
|
+
when String
|
162
|
+
return_val = lookup_name(arg) and return return_val
|
163
|
+
when Fixnum
|
164
|
+
return_val = lookup_id(arg) and return return_val
|
165
|
+
when self
|
166
|
+
return arg
|
167
|
+
when nil
|
168
|
+
nil
|
169
|
+
else
|
170
|
+
raise TypeError, "#{self.name}[]: argument should be a String, Symbol or Fixnum but got a: #{arg.class.name}"
|
171
|
+
end
|
172
|
+
|
173
|
+
handle_lookup_failure(arg)
|
174
|
+
else
|
175
|
+
args.map{ |item| self[item] }.uniq
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# Deals with a lookup failure for the given argument.
|
180
|
+
def handle_lookup_failure(arg)
|
181
|
+
if (lookup_failure_handler = self.acts_enumerated_on_lookup_failure)
|
182
|
+
case lookup_failure_handler
|
183
|
+
when Proc
|
184
|
+
lookup_failure_handler.call(arg)
|
185
|
+
else
|
186
|
+
self.send(lookup_failure_handler, arg)
|
187
|
+
end
|
188
|
+
else
|
189
|
+
self.send(:enforce_none, arg)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
private :handle_lookup_failure
|
193
|
+
|
194
|
+
# Enum lookup by id
|
195
|
+
def lookup_id(arg)
|
196
|
+
all_by_id[arg]
|
197
|
+
end
|
198
|
+
|
199
|
+
# Enum lookup by String
|
200
|
+
def lookup_name(arg)
|
201
|
+
all_by_name[arg]
|
202
|
+
end
|
203
|
+
|
204
|
+
# Returns true if the enum lookup by the given Symbol, String or id would have returned a value, false otherwise.
|
205
|
+
def include?(arg)
|
206
|
+
case arg
|
207
|
+
when Symbol
|
208
|
+
!lookup_name(arg.id2name).nil?
|
209
|
+
when String
|
210
|
+
!lookup_name(arg).nil?
|
211
|
+
when Fixnum
|
212
|
+
!lookup_id(arg).nil?
|
213
|
+
when self
|
214
|
+
possible_match = lookup_id(arg.id)
|
215
|
+
!possible_match.nil? && possible_match == arg
|
216
|
+
else
|
217
|
+
false
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# NOTE: purging the cache is sort of pointless because
|
222
|
+
# of the per-process rails model.
|
223
|
+
# By default this blows up noisily just in case you try to be more
|
224
|
+
# clever than rails allows.
|
225
|
+
# For those times (like in Migrations) when you really do want to
|
226
|
+
# alter the records you can silence the carping by setting
|
227
|
+
# enumeration_model_updates_permitted to true.
|
228
|
+
def purge_enumerations_cache
|
229
|
+
unless self.enumeration_model_updates_permitted
|
230
|
+
raise "#{self.name}: cache purging disabled for your protection"
|
231
|
+
end
|
232
|
+
@all = @all_by_name = @all_by_id = @all_active = nil
|
233
|
+
end
|
234
|
+
|
235
|
+
# The preferred method to update an enumerations model. The same
|
236
|
+
# warnings as 'purge_enumerations_cache' and
|
237
|
+
# 'enumerations_model_update_permitted' apply. Pass a block to this
|
238
|
+
# method (no args) where you perform your updates. Cache will be
|
239
|
+
# flushed automatically.
|
240
|
+
def update_enumerations_model
|
241
|
+
if block_given?
|
242
|
+
begin
|
243
|
+
self.enumeration_model_updates_permitted = true
|
244
|
+
yield
|
245
|
+
ensure
|
246
|
+
purge_enumerations_cache
|
247
|
+
self.enumeration_model_updates_permitted = false
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
# Returns the name of the column this enum uses as the basic underlying value.
|
253
|
+
def name_column
|
254
|
+
@name_column ||= self.acts_enumerated_name_column
|
255
|
+
end
|
256
|
+
|
257
|
+
# ---Private methods---
|
258
|
+
|
259
|
+
# Returns a hash of all enumeration members keyed by their ids.
|
260
|
+
def all_by_id
|
261
|
+
@all_by_id ||= all_by_attribute( :id )
|
262
|
+
end
|
263
|
+
private :all_by_id
|
264
|
+
|
265
|
+
# Returns a hash of all the enumeration members keyed by their names.
|
266
|
+
def all_by_name
|
267
|
+
begin
|
268
|
+
@all_by_name ||= all_by_attribute( :__enum_name__ )
|
269
|
+
rescue NoMethodError => err
|
270
|
+
if err.name == name_column
|
271
|
+
raise TypeError, "#{self.name}: you need to define a '#{name_column}' column in the table '#{table_name}'"
|
272
|
+
end
|
273
|
+
raise
|
274
|
+
end
|
275
|
+
end
|
276
|
+
private :all_by_name
|
277
|
+
|
278
|
+
def all_by_attribute(attr)
|
279
|
+
all.inject({}) { |memo, item|
|
280
|
+
memo[item.send(attr)] = item
|
281
|
+
memo
|
282
|
+
}.freeze
|
283
|
+
end
|
284
|
+
private :all_by_attribute
|
285
|
+
|
286
|
+
def enforce_none(arg)
|
287
|
+
nil
|
288
|
+
end
|
289
|
+
private :enforce_none
|
290
|
+
|
291
|
+
def enforce_strict(arg)
|
292
|
+
raise_record_not_found(arg)
|
293
|
+
end
|
294
|
+
private :enforce_strict
|
295
|
+
|
296
|
+
def enforce_strict_literals(arg)
|
297
|
+
raise_record_not_found(arg) if (Fixnum === arg) || (Symbol === arg)
|
298
|
+
nil
|
299
|
+
end
|
300
|
+
private :enforce_strict_literals
|
301
|
+
|
302
|
+
def enforce_strict_ids(arg)
|
303
|
+
raise_record_not_found(arg) if Fixnum === arg
|
304
|
+
nil
|
305
|
+
end
|
306
|
+
private :enforce_strict_ids
|
307
|
+
|
308
|
+
def enforce_strict_symbols(arg)
|
309
|
+
raise_record_not_found(arg) if Symbol === arg
|
310
|
+
nil
|
311
|
+
end
|
312
|
+
private :enforce_strict_symbols
|
313
|
+
|
314
|
+
def raise_record_not_found(arg)
|
315
|
+
raise ActiveRecord::RecordNotFound, "Couldn't find a #{self.name} identified by (#{arg.inspect})"
|
316
|
+
end
|
317
|
+
private :raise_record_not_found
|
318
|
+
|
319
|
+
end
|
320
|
+
|
321
|
+
module EnumInstanceMethods
|
322
|
+
# Behavior depends on the type of +arg+.
|
323
|
+
#
|
324
|
+
# * If +arg+ is +nil+, returns +false+.
|
325
|
+
# * If +arg+ is an instance of +Symbol+, +Fixnum+ or +String+, returns the result of +BookingStatus[:foo] == BookingStatus[arg]+.
|
326
|
+
# * If +arg+ is an +Array+, returns +true+ if any member of the array returns +true+ for +===(arg)+, +false+ otherwise.
|
327
|
+
# * In all other cases, delegates to +===(arg)+ of the superclass.
|
328
|
+
#
|
329
|
+
# Examples:
|
330
|
+
#
|
331
|
+
# BookingStatus[:foo] === :foo #Returns true
|
332
|
+
# BookingStatus[:foo] === 'foo' #Returns true
|
333
|
+
# BookingStatus[:foo] === :bar #Returns false
|
334
|
+
# BookingStatus[:foo] === [:foo, :bar, :baz] #Returns true
|
335
|
+
# BookingStatus[:foo] === nil #Returns false
|
336
|
+
#
|
337
|
+
# You should note that defining an +:on_lookup_failure+ method that raises an exception will cause +===+ to
|
338
|
+
# also raise an exception for any lookup failure of +BookingStatus[arg]+.
|
339
|
+
def ===(arg)
|
340
|
+
case arg
|
341
|
+
when nil
|
342
|
+
false
|
343
|
+
when Symbol, String, Fixnum
|
344
|
+
return self == self.class[arg]
|
345
|
+
when Array
|
346
|
+
return self.in?(*arg)
|
347
|
+
else
|
348
|
+
super
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
alias_method :like?, :===
|
353
|
+
|
354
|
+
# Returns true if any element in the list returns true for ===(arg), false otherwise.
|
355
|
+
def in?(*list)
|
356
|
+
for item in list
|
357
|
+
self === item and return true
|
358
|
+
end
|
359
|
+
false
|
360
|
+
end
|
361
|
+
|
362
|
+
# Returns the symbol representation of the name of the enum. BookingStatus[:foo].name_sym returns :foo.
|
363
|
+
def name_sym
|
364
|
+
self.__enum_name__.to_sym
|
365
|
+
end
|
366
|
+
|
367
|
+
alias_method :to_sym, :name_sym
|
368
|
+
|
369
|
+
# By default enumeration #to_s should return stringified name of the enum. BookingStatus[:foo].to_s returns "foo"
|
370
|
+
def to_s
|
371
|
+
self.__enum_name__
|
372
|
+
end
|
373
|
+
|
374
|
+
# Returns true if the instance is active, false otherwise. If it has an attribute 'active',
|
375
|
+
# returns the attribute cast to a boolean, otherwise returns true. This method is used by the 'active'
|
376
|
+
# class method to select active enums.
|
377
|
+
def active?
|
378
|
+
@_active_status ||= ( attributes.include?('active') ? !!self.active : true )
|
379
|
+
end
|
380
|
+
|
381
|
+
# Returns true if the instance is inactive, false otherwise. Default implementations returns !active?
|
382
|
+
# This method is used by the 'inactive' class method to select inactive enums.
|
383
|
+
def inactive?
|
384
|
+
!active?
|
385
|
+
end
|
386
|
+
|
387
|
+
# NOTE: updating the models that back an acts_as_enumerated is
|
388
|
+
# rather dangerous because of rails' per-process model.
|
389
|
+
# The cached values could get out of synch between processes
|
390
|
+
# and rather than completely disallow changes I make you jump
|
391
|
+
# through an extra hoop just in case you're defining your enumeration
|
392
|
+
# values in Migrations. I.e. set enumeration_model_updates_permitted = true
|
393
|
+
def enumeration_model_update
|
394
|
+
if self.class.enumeration_model_updates_permitted
|
395
|
+
self.class.purge_enumerations_cache
|
396
|
+
true
|
397
|
+
else
|
398
|
+
# Ugh. This just seems hack-ish. I wonder if there's a better way.
|
399
|
+
self.errors.add(self.class.name_column, "changes to acts_as_enumeration model instances are not permitted")
|
400
|
+
false
|
401
|
+
end
|
402
|
+
end
|
403
|
+
private :enumeration_model_update
|
404
|
+
end # module EnumInstanceMethods
|
405
|
+
end # module PowerEnum::Enumerated
|