lib/enum_for.rb
require 'enum_for/version'
require 'active_support/hash_with_indifferent_access'
require 'active_support/core_ext/string'
require 'active_support/core_ext/hash'
require 'active_support/inflector/inflections'
# Public: Module that extends class in order to define enum methods using
# `enum_for` class method.
module EnumFor
class Error < StandardError; end
# Public: Defines few methods useful for handling integer attributes which
# have to be used by enums. There is ActiveRecord enum type, but it shouldn't
# be exposed in API as it doesn't handle validations well (it raises exception
# when wrong enum is sent, while we would like to validate enum)
#
# This method doesn't prevent enum names to be reserved ruby words so please
# use with caution.
#
# Methods generated by `enum_for` defined as:
#
# enum_for color: { red: 0, green: 1 }
#
# When enum is set to 1:
#
# object.color
# => 'green'
#
# object.red?
# => false
#
# object.green?
# => true
#
# object.class.colors
# => { red: 0, green: 1 }
#
# object.color_to_enum
# => 1
#
# It also adds validation:
#
# validates :color, presence: true, inclusion: colors.keys
#
# @return [NilClass]
def enum_for(hash)
enum_name = hash.keys.first.to_s
mapping = hash.values.first.with_indifferent_access
define_singleton_method(enum_name.pluralize) do
mapping
end
define_method(enum_name) do
return nil if self[enum_name].blank?
mapping.key(self[enum_name]).to_s
end
define_method("#{enum_name}=") do |value|
begin
self[enum_name] = Integer(value)
rescue ArgumentError, TypeError
self[enum_name] = mapping[value.to_s.downcase]
end
end
mapping.each do |name, _|
define_method "#{name}?" do
public_send(enum_name).to_s == name
end
end
mapping.each do |name, value|
define_method "#{name}!" do
public_send("#{enum_name}=", value)
save!
end
end
define_method("#{enum_name}_to_enum") do
self[enum_name]
end
nil
end
end