lib/power_enum/enumerated.rb in power_enum-3.5.0 vs lib/power_enum/enumerated.rb in power_enum-3.6.0

- old
+ new

@@ -1,519 +1,524 @@ # Copyright (c) 2005 Trevor Squires # Copyright (c) 2012 Arthur Shagall # Released under the MIT License. See the LICENSE file for more details. -# Implementation of acts_as_enumerated -module PowerEnum::Enumerated - extend ActiveSupport::Concern +module PowerEnum - # Class level methods injected into ActiveRecord. - module ClassMethods + # Implementation of acts_as_enumerated + module Enumerated + extend ActiveSupport::Concern - # Returns false for ActiveRecord models that do not act as enumerated. - def acts_as_enumerated? - false - end + # Class level methods injected into ActiveRecord. + module ClassMethods - # Declares the model as enumerated. See the README for detailed usage instructions. - # - # === Supported options - # [:conditions] - # SQL search conditions - # [:order] - # SQL load order clause - # [:on_lookup_failure] - # Specifies the name of a class method to invoke when the +[]+ method is unable to locate a BookingStatus - # record for arg. The default is the built-in :enforce_none which returns nil. There are also built-ins for - # :enforce_strict (raise and exception regardless of the type for arg), :enforce_strict_literals (raises an - # exception if the arg is a Integer or Symbol), :enforce_strict_ids (raises and exception if the arg is a - # Integer) and :enforce_strict_symbols (raises an exception if the arg is a Symbol). The purpose of the - # :on_lookup_failure option is that a) under some circumstances a lookup failure is a Bad Thing and action - # should be taken, therefore b) a fallback action should be easily configurable. You can also give it a - # lambda that takes in a single argument (The arg that was passed to +[]+). - # [:name_column] - # Override for the 'name' column. By default, assumed to be 'name'. - # [:alias_name] - # By default, if a name column is not 'name', will create an alias of 'name' to the name_column attribute. Set - # this to +false+ if you don't want this behavior. - # [:freeze_members] - # Specifies whether individual enum instances should be frozen on database load. By default, true in production. - # Can be either a lambda or a boolean. - # - # === Examples - # - # ====Example 1 - # class BookingStatus < ActiveRecord::Base - # acts_as_enumerated - # end - # - # ====Example 2 - # class BookingStatus < ActiveRecord::Base - # acts_as_enumerated :on_lookup_failure => :enforce_strict - # end - # - # ====Example 3 - # class BookingStatus < ActiveRecord::Base - # acts_as_enumerated :conditions => [:exclude => false], - # :order => 'created_at DESC', - # :on_lookup_failure => :lookup_failed, - # :name_column => :status_code - # - # def self.lookup_failed(arg) - # logger.error("Invalid status code lookup #{arg.inspect}") - # nil - # end - # end - # - # ====Example 4 - # class BookingStatus < ActiveRecord::Base - # acts_as_enumerated :conditions => [:exclude => false], - # :order => 'created_at DESC', - # :on_lookup_failure => lambda { |arg| raise CustomError, "BookingStatus lookup failed; #{arg}" }, - # :name_column => :status_code, - # :freeze_members => true - # end - def acts_as_enumerated(options = {}) - valid_keys = [:conditions, :order, :on_lookup_failure, :name_column, :alias_name, :freeze_members] - options.assert_valid_keys(*valid_keys) + # Returns false for ActiveRecord models that do not act as enumerated. + def acts_as_enumerated? + false + end - valid_keys.each do |key| - class_attribute "acts_enumerated_#{key.to_s}" - if options.has_key?( key ) - self.send "acts_enumerated_#{key.to_s}=", options[key] + # Declares the model as enumerated. See the README for detailed usage instructions. + # + # === Supported options + # [:conditions] + # SQL search conditions + # [:order] + # SQL load order clause + # [:on_lookup_failure] + # Specifies the name of a class method to invoke when the +[]+ method is unable to locate a BookingStatus + # record for arg. The default is the built-in :enforce_none which returns nil. There are also built-ins for + # :enforce_strict (raise and exception regardless of the type for arg), :enforce_strict_literals (raises an + # exception if the arg is a Integer or Symbol), :enforce_strict_ids (raises and exception if the arg is a + # Integer) and :enforce_strict_symbols (raises an exception if the arg is a Symbol). The purpose of the + # :on_lookup_failure option is that a) under some circumstances a lookup failure is a Bad Thing and action + # should be taken, therefore b) a fallback action should be easily configurable. You can also give it a + # lambda that takes in a single argument (The arg that was passed to +[]+). + # [:name_column] + # Override for the 'name' column. By default, assumed to be 'name'. + # [:alias_name] + # By default, if a name column is not 'name', will create an alias of 'name' to the name_column attribute. Set + # this to +false+ if you don't want this behavior. + # [:freeze_members] + # Specifies whether individual enum instances should be frozen on database load. By default, true in production. + # Can be either a lambda or a boolean. + # + # === Examples + # + # ====Example 1 + # class BookingStatus < ActiveRecord::Base + # acts_as_enumerated + # end + # + # ====Example 2 + # class BookingStatus < ActiveRecord::Base + # acts_as_enumerated :on_lookup_failure => :enforce_strict + # end + # + # ====Example 3 + # class BookingStatus < ActiveRecord::Base + # acts_as_enumerated :conditions => [:exclude => false], + # :order => 'created_at DESC', + # :on_lookup_failure => :lookup_failed, + # :name_column => :status_code + # + # def self.lookup_failed(arg) + # logger.error("Invalid status code lookup #{arg.inspect}") + # nil + # end + # end + # + # ====Example 4 + # class BookingStatus < ActiveRecord::Base + # acts_as_enumerated :conditions => [:exclude => false], + # :order => 'created_at DESC', + # :on_lookup_failure => lambda { |arg| raise CustomError, "BookingStatus lookup failed; #{arg}" }, + # :name_column => :status_code, + # :freeze_members => true + # end + def acts_as_enumerated(options = {}) + valid_keys = [:conditions, :order, :on_lookup_failure, :name_column, :alias_name, :freeze_members] + options.assert_valid_keys(*valid_keys) + + valid_keys.each do |key| + class_attribute "acts_enumerated_#{key.to_s}" + if options.has_key?( key ) + self.send "acts_enumerated_#{key.to_s}=", options[key] + end end - end - self.acts_enumerated_name_column = get_name_column(options) + self.acts_enumerated_name_column = get_name_column(options) - unless self.is_a? PowerEnum::Enumerated::EnumClassMethods - preserve_query_aliases - extend_enum_class_methods( options ) + unless self.is_a? PowerEnum::Enumerated::EnumClassMethods + preserve_query_aliases + extend_enum_class_methods( options ) + end end - end - # Rails 4 delegates all the finder methods to 'all'. PowerEnum overrides 'all'. Hence, - # the need to re-alias the query methods. - def preserve_query_aliases - class << self - # I have to do the interesting hack below instead of using alias_method - # because there's some sort of weirdness going on with how __all binds - # to all in Ruby 2.0. - __all = self.instance_method(:all) + # Rails 4 delegates all the finder methods to 'all'. PowerEnum overrides 'all'. Hence, + # the need to re-alias the query methods. + def preserve_query_aliases + class << self + # I have to do the interesting hack below instead of using alias_method + # because there's some sort of weirdness going on with how __all binds + # to all in Ruby 2.0. + __all = self.instance_method(:all) - define_method(:__all) do - __all.bind(self).call - end + define_method(:__all) do + __all.bind(self).call + end - # From ActiveRecord::Querying - delegate :find, :take, :take!, :first, :first!, :last, :last!, :exists?, :any?, :many?, :to => :__all - delegate :first_or_create, :first_or_create!, :first_or_initialize, :to => :__all - delegate :find_or_create_by, :find_or_create_by!, :find_or_initialize_by, :to => :__all - delegate :find_by, :find_by!, :to => :__all - delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, :to => :__all - delegate :find_each, :find_in_batches, :to => :__all - delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, - :where, :preload, :eager_load, :includes, :from, :lock, :readonly, - :having, :create_with, :uniq, :distinct, :references, :none, :unscope, :to => :__all - delegate :count, :average, :minimum, :maximum, :sum, :calculate, :pluck, :ids, :to => :__all + # From ActiveRecord::Querying + delegate :find, :take, :take!, :first, :first!, :last, :last!, :exists?, :any?, :many?, :to => :__all + delegate :first_or_create, :first_or_create!, :first_or_initialize, :to => :__all + delegate :find_or_create_by, :find_or_create_by!, :find_or_initialize_by, :to => :__all + delegate :find_by, :find_by!, :to => :__all + delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, :to => :__all + delegate :find_each, :find_in_batches, :to => :__all + delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, + :where, :preload, :eager_load, :includes, :from, :lock, :readonly, + :having, :create_with, :uniq, :distinct, :references, :none, :unscope, :to => :__all + delegate :count, :average, :minimum, :maximum, :sum, :calculate, :pluck, :ids, :to => :__all + end end - end - # Injects the class methods into model - def extend_enum_class_methods(options) #:nodoc: + # Injects the class methods into model + def extend_enum_class_methods(options) #:nodoc: - extend PowerEnum::Enumerated::EnumClassMethods + extend PowerEnum::Enumerated::EnumClassMethods - class_eval do - include PowerEnum::Enumerated::EnumInstanceMethods + class_eval do + include PowerEnum::Enumerated::EnumInstanceMethods - before_save :enumeration_model_update - before_destroy :enumeration_model_update - validates acts_enumerated_name_column, :presence => true, :uniqueness => true - validate :validate_enumeration_model_updates_permitted + before_save :enumeration_model_update + before_destroy :enumeration_model_update + validates acts_enumerated_name_column, :presence => true, :uniqueness => true + validate :validate_enumeration_model_updates_permitted - define_method :__enum_name__ do - read_attribute(acts_enumerated_name_column).to_s - end + define_method :__enum_name__ do + read_attribute(acts_enumerated_name_column).to_s + end - if should_alias_name?(options) && acts_enumerated_name_column != :name - alias_method :name, :__enum_name__ - end - end # class_eval + if should_alias_name?(options) && acts_enumerated_name_column != :name + alias_method :name, :__enum_name__ + end + end # class_eval - end + end - # Determines if the name column should be explicitly aliased - def should_alias_name?(options) #:nodoc: - if options.has_key?(:alias_name) then - options[:alias_name] - else - true + # Determines if the name column should be explicitly aliased + def should_alias_name?(options) #:nodoc: + if options.has_key?(:alias_name) then + options[:alias_name] + else + true + end end - end - # Extracts the name column from options or gives the default - def get_name_column(options) #:nodoc: - if options.has_key?(:name_column) && !options[:name_column].blank? then - options[:name_column].to_s.to_sym - else - :name + # Extracts the name column from options or gives the default + def get_name_column(options) #:nodoc: + if options.has_key?(:name_column) && !options[:name_column].blank? then + options[:name_column].to_s.to_sym + else + :name + end end end - end - # These are class level methods which are patched into classes that act as - # enumerated - module EnumClassMethods - attr_accessor :enumeration_model_updates_permitted + # These are class level methods which are patched into classes that act as + # enumerated + module EnumClassMethods + attr_accessor :enumeration_model_updates_permitted - # Returns true for ActiveRecord models that act as enumerated. - def acts_as_enumerated? - true - end + # Returns true for ActiveRecord models that act as enumerated. + def acts_as_enumerated? + true + end - # Returns all the enum values. Caches results after the first time this method is run. - def all - return @all if @all + # Returns all the enum values. Caches results after the first time this method is run. + def all + return @all if @all - freeze_handler = if (handler = self.acts_enumerated_freeze_members).nil? - -> { Rails.env.production? } - else - case handler - when Proc - handler + freeze_handler = if (handler = self.acts_enumerated_freeze_members).nil? + -> { Rails.env.production? } else - -> { handler } + case handler + when Proc + handler + else + -> { handler } + end end - end - @all = load_all.collect{ |val| !!freeze_handler.call ? val.freeze : val }.freeze - end + @all = load_all.collect{ |val| !!freeze_handler.call ? val.freeze : val }.freeze + end - # Returns all the active enum values. See the 'active?' instance method. - def active - return @all_active if @all_active - @all_active = all.find_all{ |enum| enum.active? }.freeze - end + # Returns all the active enum values. See the 'active?' instance method. + def active + return @all_active if @all_active + @all_active = all.find_all{ |enum| enum.active? }.freeze + end - # Returns all the inactive enum values. See the 'inactive?' instance method. - def inactive - return @all_inactive if @all_inactive - @all_inactive = all.find_all{ |enum| !enum.active? }.freeze - end + # Returns all the inactive enum values. See the 'inactive?' instance method. + def inactive + return @all_inactive if @all_inactive + @all_inactive = all.find_all{ |enum| !enum.active? }.freeze + end - # Returns the names of all the enum values as an array of symbols. - def names - all.map { |item| item.name_sym } - end + # Returns the names of all the enum values as an array of symbols. + def names + all.map { |item| item.name_sym } + end - # Returns all except for the given list - def all_except(*excluded) - all.find_all { |item| !(item === excluded) } - end + # Returns all except for the given list + def all_except(*excluded) + all.find_all { |item| !(item === excluded) } + end - # Enum lookup by Symbol, String, or id. Returns <tt>arg<tt> if arg is - # an enum instance. Passing in a list of arguments returns a list of - # enums. When called with no arguments, returns nil. - def [](*args) - case args.size - when 0 - nil - when 1 - arg = args.first - lookup_enum_by_type(arg) || handle_lookup_failure(arg) - else - args.map{ |item| self[item] }.uniq + # Enum lookup by Symbol, String, or id. Returns <tt>arg<tt> if arg is + # an enum instance. Passing in a list of arguments returns a list of + # enums. When called with no arguments, returns nil. + def [](*args) + case args.size + when 0 + nil + when 1 + arg = args.first + lookup_enum_by_type(arg) || handle_lookup_failure(arg) + else + args.map{ |item| self[item] }.uniq + end end - end - # Returns <tt>true</tt> if the given Symbol, String or id has a member - # instance in the enumeration, <tt>false</tt> otherwise. Returns <tt>true</tt> - # if the argument is an enum instance, returns <tt>false</tt> if the argument - # is nil or any other value. - def contains?(arg) - case arg - when Symbol - !!lookup_name(arg.id2name) - when String - !!lookup_name(arg) - when Integer - !!lookup_id(arg) - when self - true - else - false + # Returns <tt>true</tt> if the given Symbol, String or id has a member + # instance in the enumeration, <tt>false</tt> otherwise. Returns <tt>true</tt> + # if the argument is an enum instance, returns <tt>false</tt> if the argument + # is nil or any other value. + def contains?(arg) + case arg + when Symbol + !!lookup_name(arg.id2name) + when String + !!lookup_name(arg) + when Integer + !!lookup_id(arg) + when self + true + else + false + end end - end - # Enum lookup by id - def lookup_id(arg) - all_by_id[arg] - end + # Enum lookup by id + def lookup_id(arg) + all_by_id[arg] + end - # Enum lookup by String - def lookup_name(arg) - all_by_name[arg] - end + # Enum lookup by String + def lookup_name(arg) + all_by_name[arg] + end - # Returns true if the enum lookup by the given Symbol, String or id would have returned a value, false otherwise. - def include?(arg) - case arg - when Symbol - !lookup_name(arg.id2name).nil? - when String - !lookup_name(arg).nil? - when Integer - !lookup_id(arg).nil? - when self - possible_match = lookup_id(arg.id) - !possible_match.nil? && possible_match == arg - else - false + # Returns true if the enum lookup by the given Symbol, String or id would have returned a value, false otherwise. + def include?(arg) + case arg + when Symbol + !lookup_name(arg.id2name).nil? + when String + !lookup_name(arg).nil? + when Integer + !lookup_id(arg).nil? + when self + possible_match = lookup_id(arg.id) + !possible_match.nil? && possible_match == arg + else + false + end end - end - # NOTE: purging the cache is sort of pointless because - # of the per-process rails model. - # By default this blows up noisily just in case you try to be more - # clever than rails allows. - # For those times (like in Migrations) when you really do want to - # alter the records you can silence the carping by setting - # enumeration_model_updates_permitted to true. - def purge_enumerations_cache - unless self.enumeration_model_updates_permitted - raise "#{self.name}: cache purging disabled for your protection" + # NOTE: purging the cache is sort of pointless because + # of the per-process rails model. + # By default this blows up noisily just in case you try to be more + # clever than rails allows. + # For those times (like in Migrations) when you really do want to + # alter the records you can silence the carping by setting + # enumeration_model_updates_permitted to true. + def purge_enumerations_cache + unless self.enumeration_model_updates_permitted + raise "#{self.name}: cache purging disabled for your protection" + end + @all = @all_by_name = @all_by_id = @all_active = nil end - @all = @all_by_name = @all_by_id = @all_active = nil - end - # The preferred method to update an enumerations model. The same - # warnings as 'purge_enumerations_cache' and - # 'enumerations_model_update_permitted' apply. Pass a block to this - # method where you perform your updates. Cache will be - # flushed automatically. If your block takes an argument, will pass in - # the model class. The argument is optional. - def update_enumerations_model(&block) - if block_given? - begin - self.enumeration_model_updates_permitted = true - purge_enumerations_cache - @all = load_all - @enumerations_model_updating = true - case block.arity - when 0 - yield - else - yield self + # The preferred method to update an enumerations model. The same + # warnings as 'purge_enumerations_cache' and + # 'enumerations_model_update_permitted' apply. Pass a block to this + # method where you perform your updates. Cache will be + # flushed automatically. If your block takes an argument, will pass in + # the model class. The argument is optional. + def update_enumerations_model(&block) + if block_given? + begin + self.enumeration_model_updates_permitted = true + purge_enumerations_cache + @all = load_all + @enumerations_model_updating = true + case block.arity + when 0 + yield + else + yield self + end + ensure + purge_enumerations_cache + @enumerations_model_updating = false + self.enumeration_model_updates_permitted = false end - ensure - purge_enumerations_cache - @enumerations_model_updating = false - self.enumeration_model_updates_permitted = false end end - end - # Returns true if the enumerations model is in the middle of an - # update_enumerations_model block, false otherwise. - def enumerations_model_updating? - !!@enumerations_model_updating - end + # Returns true if the enumerations model is in the middle of an + # update_enumerations_model block, false otherwise. + def enumerations_model_updating? + !!@enumerations_model_updating + end - # Returns the name of the column this enum uses as the basic underlying value. - def name_column - @name_column ||= self.acts_enumerated_name_column - end + # Returns the name of the column this enum uses as the basic underlying value. + def name_column + @name_column ||= self.acts_enumerated_name_column + end - # ---Private methods--- + # ---Private methods--- - private def load_all - conditions = self.acts_enumerated_conditions - order = self.acts_enumerated_order - unscoped.where(conditions).order(order) - end + private def load_all + conditions = self.acts_enumerated_conditions + order = self.acts_enumerated_order + unscoped.where(conditions).order(order) + end - # Looks up the enum based on the type of the argument. - private def lookup_enum_by_type(arg) - case arg - when Symbol - lookup_name(arg.id2name) - when String - lookup_name(arg) - when Integer - lookup_id(arg) - when self - arg - when nil - nil - else - raise TypeError, "#{self.name}[]: argument should"\ - " be a String, Symbol or Integer but got a: #{arg.class.name}" + # Looks up the enum based on the type of the argument. + private def lookup_enum_by_type(arg) + case arg + when Symbol + lookup_name(arg.id2name) + when String + lookup_name(arg) + when Integer + lookup_id(arg) + when self + arg + when nil + nil + else + raise TypeError, "#{self.name}[]: argument should"\ + " be a String, Symbol or Integer but got a: #{arg.class.name}" + end end - end - # Deals with a lookup failure for the given argument. - private def handle_lookup_failure(arg) - if (lookup_failure_handler = self.acts_enumerated_on_lookup_failure) - case lookup_failure_handler - when Proc - lookup_failure_handler.call(arg) + # Deals with a lookup failure for the given argument. + private def handle_lookup_failure(arg) + if (lookup_failure_handler = self.acts_enumerated_on_lookup_failure) + case lookup_failure_handler + when Proc + lookup_failure_handler.call(arg) + else + self.send(lookup_failure_handler, arg) + end else - self.send(lookup_failure_handler, arg) + self.send(:enforce_none, arg) end - else - self.send(:enforce_none, arg) end - end - # Returns a hash of all enumeration members keyed by their ids. - private def all_by_id - @all_by_id ||= all_by_attribute( primary_key ) - end + # Returns a hash of all enumeration members keyed by their ids. + private def all_by_id + @all_by_id ||= all_by_attribute( primary_key ) + end - # Returns a hash of all the enumeration members keyed by their names. - private def all_by_name - begin - @all_by_name ||= all_by_attribute( :__enum_name__ ) - rescue NoMethodError => err - if err.name == name_column - raise TypeError, "#{self.name}: you need to define a '#{name_column}' column in the table '#{table_name}'" + # Returns a hash of all the enumeration members keyed by their names. + private def all_by_name + begin + @all_by_name ||= all_by_attribute( :__enum_name__ ) + rescue NoMethodError => err + if err.name == name_column + raise TypeError, "#{self.name}: you need to define a '#{name_column}' column in the table '#{table_name}'" + end + raise end - raise end - end - private def all_by_attribute(attr) # :nodoc: - aba = all.inject({}) { |memo, item| - memo[item.send(attr)] = item - memo - } - aba.freeze unless enumerations_model_updating? - aba - end + private def all_by_attribute(attr) # :nodoc: + aba = all.inject({}) { |memo, item| + memo[item.send(attr)] = item + memo + } + aba.freeze unless enumerations_model_updating? + aba + end - private def enforce_none(arg) # :nodoc: - nil - end + private def enforce_none(arg) # :nodoc: + nil + end - private def enforce_strict(arg) # :nodoc: - raise_record_not_found(arg) - end + private def enforce_strict(arg) # :nodoc: + raise_record_not_found(arg) + end - private def enforce_strict_literals(arg) # :nodoc: - raise_record_not_found(arg) if (Integer === arg) || (Symbol === arg) - nil - end + private def enforce_strict_literals(arg) # :nodoc: + raise_record_not_found(arg) if (Integer === arg) || (Symbol === arg) + nil + end - private def enforce_strict_ids(arg) # :nodoc: - raise_record_not_found(arg) if Integer === arg - nil - end + private def enforce_strict_ids(arg) # :nodoc: + raise_record_not_found(arg) if Integer === arg + nil + end - private def enforce_strict_symbols(arg) # :nodoc: - raise_record_not_found(arg) if Symbol === arg - nil - end + private def enforce_strict_symbols(arg) # :nodoc: + raise_record_not_found(arg) if Symbol === arg + nil + end - # raise the {ActiveRecord::RecordNotFound} error. - # @private - private def raise_record_not_found(arg) - raise ActiveRecord::RecordNotFound, "Couldn't find a #{self.name} identified by (#{arg.inspect})" + # raise the {ActiveRecord::RecordNotFound} error. + # @private + private def raise_record_not_found(arg) + raise ActiveRecord::RecordNotFound, "Couldn't find a #{self.name} identified by (#{arg.inspect})" + end + end - end + # These are instance methods for objects which are enums. + module EnumInstanceMethods + # Behavior depends on the type of +arg+. + # + # * If +arg+ is +nil+, returns +false+. + # * If +arg+ is an instance of +Symbol+, +Integer+ or +String+, returns the result of +BookingStatus[:foo] == BookingStatus[arg]+. + # * If +arg+ is an +Array+, returns +true+ if any member of the array returns +true+ for +===(arg)+, +false+ otherwise. + # * In all other cases, delegates to +===(arg)+ of the superclass. + # + # Examples: + # + # BookingStatus[:foo] === :foo #Returns true + # BookingStatus[:foo] === 'foo' #Returns true + # BookingStatus[:foo] === :bar #Returns false + # BookingStatus[:foo] === [:foo, :bar, :baz] #Returns true + # BookingStatus[:foo] === nil #Returns false + # + # You should note that defining an +:on_lookup_failure+ method that raises an exception will cause +===+ to + # also raise an exception for any lookup failure of +BookingStatus[arg]+. + def ===(arg) + case arg + when nil + false + when Symbol, String, Integer + return self == self.class[arg] + when Array + return self.in?(*arg) + else + super + end + end - # These are instance methods for objects which are enums. - module EnumInstanceMethods - # Behavior depends on the type of +arg+. - # - # * If +arg+ is +nil+, returns +false+. - # * If +arg+ is an instance of +Symbol+, +Integer+ or +String+, returns the result of +BookingStatus[:foo] == BookingStatus[arg]+. - # * If +arg+ is an +Array+, returns +true+ if any member of the array returns +true+ for +===(arg)+, +false+ otherwise. - # * In all other cases, delegates to +===(arg)+ of the superclass. - # - # Examples: - # - # BookingStatus[:foo] === :foo #Returns true - # BookingStatus[:foo] === 'foo' #Returns true - # BookingStatus[:foo] === :bar #Returns false - # BookingStatus[:foo] === [:foo, :bar, :baz] #Returns true - # BookingStatus[:foo] === nil #Returns false - # - # You should note that defining an +:on_lookup_failure+ method that raises an exception will cause +===+ to - # also raise an exception for any lookup failure of +BookingStatus[arg]+. - def ===(arg) - case arg - when nil + alias_method :like?, :=== + + # Returns true if any element in the list returns true for ===(arg), false otherwise. + def in?(*list) + for item in list + self === item and return true + end false - when Symbol, String, Integer - return self == self.class[arg] - when Array - return self.in?(*arg) - else - super end - end - alias_method :like?, :=== - - # Returns true if any element in the list returns true for ===(arg), false otherwise. - def in?(*list) - for item in list - self === item and return true + # Returns the symbol representation of the name of the enum. BookingStatus[:foo].name_sym returns :foo. + def name_sym + self.__enum_name__.to_sym end - false - end - # Returns the symbol representation of the name of the enum. BookingStatus[:foo].name_sym returns :foo. - def name_sym - self.__enum_name__.to_sym - end + alias_method :to_sym, :name_sym - alias_method :to_sym, :name_sym + # By default enumeration #to_s should return stringified name of the enum. BookingStatus[:foo].to_s returns "foo" + def to_s + self.__enum_name__ + end - # By default enumeration #to_s should return stringified name of the enum. BookingStatus[:foo].to_s returns "foo" - def to_s - self.__enum_name__ - end + # Returns true if the instance is active, false otherwise. If it has an attribute 'active', + # returns the attribute cast to a boolean, otherwise returns true. This method is used by the 'active' + # class method to select active enums. + def active? + @_active_status ||= ( attributes.include?('active') ? !!self.active : true ) + end - # Returns true if the instance is active, false otherwise. If it has an attribute 'active', - # returns the attribute cast to a boolean, otherwise returns true. This method is used by the 'active' - # class method to select active enums. - def active? - @_active_status ||= ( attributes.include?('active') ? !!self.active : true ) - end + # Returns true if the instance is inactive, false otherwise. Default implementations returns !active? + # This method is used by the 'inactive' class method to select inactive enums. + def inactive? + !active? + end - # Returns true if the instance is inactive, false otherwise. Default implementations returns !active? - # This method is used by the 'inactive' class method to select inactive enums. - def inactive? - !active? - end - - # NOTE: updating the models that back an acts_as_enumerated is - # rather dangerous because of rails' per-process model. - # The cached values could get out of synch between processes - # and rather than completely disallow changes I make you jump - # through an extra hoop just in case you're defining your enumeration - # values in Migrations. I.e. set enumeration_model_updates_permitted = true - private def enumeration_model_update - if self.class.enumeration_model_updates_permitted - self.class.purge_enumerations_cache - true - else - # Ugh. This just seems hack-ish. I wonder if there's a better way. - if Rails.version =~ /^4\.2\.*/ - false + # NOTE: updating the models that back an acts_as_enumerated is + # rather dangerous because of rails' per-process model. + # The cached values could get out of synch between processes + # and rather than completely disallow changes I make you jump + # through an extra hoop just in case you're defining your enumeration + # values in Migrations. I.e. set enumeration_model_updates_permitted = true + private def enumeration_model_update + if self.class.enumeration_model_updates_permitted + self.class.purge_enumerations_cache + true else - throw(:abort) + # Ugh. This just seems hack-ish. I wonder if there's a better way. + if Rails.version =~ /^4\.2\.*/ + false + else + throw(:abort) + end end end - end - # Validates that model updates are enabled. - private def validate_enumeration_model_updates_permitted - unless self.class.enumeration_model_updates_permitted - self.errors.add(self.class.name_column, "changes to acts_as_enumeration model instances are not permitted") + # Validates that model updates are enabled. + private def validate_enumeration_model_updates_permitted + unless self.class.enumeration_model_updates_permitted + self.errors.add(self.class.name_column, "changes to acts_as_enumeration model instances are not permitted") + end end - end - end # module EnumInstanceMethods -end # module PowerEnum::Enumerated + end # module EnumInstanceMethods + + end # module Enumerated + +end # module PowerEnum