class Torque::PostgreSQL::Attributes::Builder::Enum

Constants

VALID_TYPES

Attributes

attribute[RW]
instance_module[RW]
klass[RW]
klass_module[RW]
options[RW]
subtype[RW]
values[RW]

Public Class Methods

new(klass, attribute, options) click to toggle source

Start a new builder of methods for enum values on ActiveRecord::Base

# File lib/torque/postgresql/attributes/builder/enum.rb, line 14
def initialize(klass, attribute, options)
  @klass     = klass
  @attribute = attribute.to_s
  @subtype   = klass.attribute_types[@attribute]
  @options   = options

  raise Interrupt unless subtype.respond_to?(:klass)
  @values    = subtype.klass.values

  if @options[:only]
    @values &= Array(@options[:only]).map(&:to_s)
  end

  if @options[:except]
    @values -= Array(@options[:except]).map(&:to_s)
  end
end

Public Instance Methods

build() click to toggle source

Create all methods needed

# File lib/torque/postgresql/attributes/builder/enum.rb, line 91
def build
  @klass_module = Module.new
  @instance_module = Module.new

  plural
  stringify
  all_values
  set_scopes if set_features?

  klass.extend klass_module
  klass.include instance_module
end
conflicting?() click to toggle source

Check if any of the methods that will be created get in conflict with the base class methods

# File lib/torque/postgresql/attributes/builder/enum.rb, line 62
          def conflicting?
            return if options[:force] == true
            attributes = attribute.pluralize

            dangerous?(attributes, true)
            dangerous?("#{attributes}_keys", true)
            dangerous?("#{attributes}_texts", true)
            dangerous?("#{attributes}_options", true)
            dangerous?("#{attribute}_text")

            if set_features?
              dangerous?("has_#{attributes}", true)
              dangerous?("has_any_#{attributes}", true)
            end

            values_methods.each do |attr, (scope, ask, bang, *)|
              dangerous?(scope, true)
              dangerous?(bang)
              dangerous?(ask)
            end
          rescue Interrupt => err
            raise ArgumentError, <<-MSG.squish
              Enum #{subtype.name} was not able to generate requested
              methods because the method #{err} already exists in
              #{klass.name}.
            MSG
          end
set_features?() click to toggle source

Check if it's building the methods for sets

# File lib/torque/postgresql/attributes/builder/enum.rb, line 56
def set_features?
  options[:set_features].present?
end
values_methods() click to toggle source

Get the list of methods based on enum values

# File lib/torque/postgresql/attributes/builder/enum.rb, line 33
def values_methods
  return @values_methods if defined?(@values_methods)

  prefix = options.fetch(:prefix, nil)
  suffix = options.fetch(:suffix, nil)

  prefix = attribute if prefix == true
  suffix = attribute if suffix == true

  base   = [prefix, '%s', suffix].compact.join('_')

  @values_methods = begin
    values.map do |val|
      key   = val.downcase.tr('- ', '__')
      scope = base % key
      ask   = scope + '?'
      bang  = scope + '!'
      [key, [scope, ask, bang, val]]
    end.to_h
  end
end

Private Instance Methods

all_values() click to toggle source

Create all the methods that represent actions related to the attribute value

# File lib/torque/postgresql/attributes/builder/enum.rb, line 181
            def all_values
              klass_content = ''
              instance_content = ''
              enum_klass = subtype.klass.name

              values_methods.each do |key, (scope, ask, bang, val)|
                klass_content += <<-RUBY
                  def #{scope}                                    # def admin
                    attr = arel_table['#{attribute}']             #   attr = arel_table['role']
                    where(::#{enum_klass}.scope(attr, '#{val}'))  #   where(Enum::Roles.scope(attr, 'admin'))
                  end                                             # end
                RUBY

                instance_content += <<-RUBY
                  def #{ask}                                      # def admin?
                    #{attribute}.#{key}?                          #   role.admin?
                  end                                             # end

                  def #{bang}                                     # admin!
                    self.#{attribute} = '#{val}'                  #   self.role = 'admin'
                    return unless #{attribute}_changed?           #   return unless role_changed?
                    return save! if Torque::PostgreSQL.config.enum.save_on_bang
                    true                                          #   true
                  end                                             # end
                RUBY
              end

              klass_module.module_eval(klass_content)
              instance_module.module_eval(instance_content)
            end
dangerous?(method_name, class_method = false) click to toggle source

Check if the method already exists in the reference class

# File lib/torque/postgresql/attributes/builder/enum.rb, line 107
            def dangerous?(method_name, class_method = false)
              if class_method
                if klass.dangerous_class_method?(method_name)
                  raise Interrupt, method_name.to_s
                end
              else
                if klass.dangerous_attribute_method?(method_name)
                  raise Interrupt, method_name.to_s
                end
              end
            rescue Interrupt => e
              raise e if Torque::PostgreSQL.config.enum.raise_conflicting
              type = class_method ? 'class method' : 'instance method'
              indicator = class_method ? '.' : '#'

              Torque::PostgreSQL.logger.info(<<~MSG.squish)
                Creating #{class_method} :#{method_name} for enum.
                Overwriting existing method #{klass.name}#{indicator}#{method_name}.
              MSG
            end
plural() click to toggle source

Create the method that allow access to the list of values

# File lib/torque/postgresql/attributes/builder/enum.rb, line 129
            def plural
              enum_klass = subtype.klass.name
              klass_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
                def #{attribute.pluralize}                                  # def roles
                  ::#{enum_klass}.values                                    #   Enum::Roles.values
                end                                                         # end

                def #{attribute.pluralize}_keys                             # def roles_keys
                  ::#{enum_klass}.keys                                      #   Enum::Roles.keys
                end                                                         # end

                def #{attribute.pluralize}_texts                            # def roles_texts
                  ::#{enum_klass}.members.map do |member|                   #   Enum::Roles.members do |member|
                    member.text('#{attribute}', self)                       #     member.text('role', self)
                  end                                                       #   end
                end                                                         # end

                def #{attribute.pluralize}_options                          # def roles_options
                  #{attribute.pluralize}_texts.zip(::#{enum_klass}.values)  #   roles_texts.zip(Enum::Roles.values)
                end                                                         # end
              RUBY
            end
set_scopes() click to toggle source

Create additional methods when the enum is a set, which needs better ways to check if values are present or not

# File lib/torque/postgresql/attributes/builder/enum.rb, line 154
            def set_scopes
              cast_type = subtype.name.chomp('[]')
              klass_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
                def has_#{attribute.pluralize}(*values)                             # def has_roles(*values)
                  attr = arel_table['#{attribute}']                                 #   attr = arel_table['role']
                  where(attr.contains(::Arel.array(values, cast: '#{cast_type}')))  #   where(attr.contains(::Arel.array(values, cast: 'roles')))
                end                                                                 # end

                def has_any_#{attribute.pluralize}(*values)                         # def has_roles(*values)
                  attr = arel_table['#{attribute}']                                 #   attr = arel_table['role']
                  where(attr.overlaps(::Arel.array(values, cast: '#{cast_type}')))  #   where(attr.overlaps(::Arel.array(values, cast: 'roles')))
                end                                                                 # end
              RUBY
            end
stringify() click to toggle source

Create the method that turn the attribute value into text using the model scope

# File lib/torque/postgresql/attributes/builder/enum.rb, line 171
            def stringify
              instance_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
                def #{attribute}_text                      # def role_text
                  #{attribute}.text('#{attribute}', self)  #   role.text('role', self)
                end                                        # end
              RUBY
            end