class Torque::PostgreSQL::Attributes::EnumSet

Public Class Methods

[](value, *)
Alias for: fetch
enum_source() click to toggle source

The original Enum implementation, for individual values

# File lib/torque/postgresql/attributes/enum_set.rb, line 40
def enum_source
  const_get('EnumSource')
end
fetch(value, *) click to toggle source

Fetch a value from the list see github.com/rails/rails/blob/v5.0.0/activerecord/lib/active_record/fixtures.rb#L656 see github.com/rails/rails/blob/v5.0.0/activerecord/lib/active_record/validations/uniqueness.rb#L101

# File lib/torque/postgresql/attributes/enum_set.rb, line 63
def fetch(value, *)
  new(value.to_s) if values.include?(value)
end
Also aliased as: []
include_on(klass, method_name = nil) click to toggle source

Provide a method on the given class to setup which enum sets will be manually initialized

# File lib/torque/postgresql/attributes/enum_set.rb, line 32
def include_on(klass, method_name = nil)
  method_name ||= Torque::PostgreSQL.config.enum.set_method
  Builder.include_on(klass, method_name, Builder::Enum, set_features: true) do |builder|
    defined_enums[builder.attribute.to_s] = builder.subtype
  end
end
lookup(name, enum_klass) click to toggle source

Find or create the class that will handle the value

# File lib/torque/postgresql/attributes/enum_set.rb, line 19
def lookup(name, enum_klass)
  const     = name.to_s.camelize + 'Set'
  namespace = Torque::PostgreSQL.config.enum.namespace

  return namespace.const_get(const) if namespace.const_defined?(const)

  klass = Class.new(EnumSet)
  klass.const_set('EnumSource', enum_klass)
  namespace.const_set(const, klass)
end
new(*values) click to toggle source

Overpass new so blank values return only nil

Calls superclass method
# File lib/torque/postgresql/attributes/enum_set.rb, line 50
def new(*values)
  return Lazy.new(self, []) if values.compact.blank?
  super
end
new(*values) click to toggle source

Override string initializer to check for a valid value

# File lib/torque/postgresql/attributes/enum_set.rb, line 99
def initialize(*values)
  items =
    if values.size === 1 && values.first.is_a?(Numeric)
      transform_power(values.first)
    else
      transform_values(values)
    end

  @hash = items.zip(Array.new(items.size, true)).to_h
end
power(*values) click to toggle source

Get the power, 2 ** index, of each element

# File lib/torque/postgresql/attributes/enum_set.rb, line 69
def power(*values)
  values.flatten.map do |item|
    item = item.to_i if item.is_a?(Enum)
    item = values.index(item) unless item.is_a?(Numeric)

    next 0 if item.nil? || item >= size
    2 ** item
  end.reduce(:+)
end
sample() click to toggle source

Use the power to get a sample of the value

# File lib/torque/postgresql/attributes/enum_set.rb, line 45
def sample
  new(rand(0..((2 ** size) - 1)))
end
scope(attribute, value) click to toggle source

Build an active record scope for a given atribute agains a value

# File lib/torque/postgresql/attributes/enum_set.rb, line 80
def scope(attribute, value)
  attribute.contains(::Arel.array(value, cast: enum_source.type_name))
end
type_name() click to toggle source

Get the type name from its class name

# File lib/torque/postgresql/attributes/enum_set.rb, line 56
def type_name
  @type_name ||= enum_source.type_name + '[]'
end

Private Class Methods

method_missing(method_name, *arguments) click to toggle source

Allow fast creation of values

Calls superclass method
# File lib/torque/postgresql/attributes/enum_set.rb, line 92
def method_missing(method_name, *arguments)
  return super if self == Enum
  valid?(method_name) ? new(method_name.to_s) : super
end
respond_to_missing?(method_name, include_private = false) click to toggle source

Allows checking value existance

Calls superclass method
# File lib/torque/postgresql/attributes/enum_set.rb, line 87
def respond_to_missing?(method_name, include_private = false)
  valid?(method_name) || super
end

Public Instance Methods

&(other) click to toggle source

Override bitwise & operator to ensure formatted values

# File lib/torque/postgresql/attributes/enum_set.rb, line 163
def &(other)
  other = other.entries.map(&method(:instantiate))
  values = @hash.keys.select { |k| other.include?(k) }
  self.class.new(values)
end
<=>(other) click to toggle source

Allow comparison between values of the same enum

# File lib/torque/postgresql/attributes/enum_set.rb, line 111
def <=>(other)
  raise_comparison(other) if other.is_a?(EnumSet) && other.class != self.class

  to_i <=>
    case other
    when Numeric, EnumSet then other.to_i
    when String, Symbol   then self.class.power(other.to_s)
    when Array, Set       then self.class.power(*other)
    else raise_comparison(other)
    end
end
==(other) click to toggle source

Only allow value comparison with values of the same class

# File lib/torque/postgresql/attributes/enum_set.rb, line 124
def ==(other)
  (self <=> other) == 0
rescue EnumSetError
  false
end
Also aliased as: eql?
[]=(key, value) click to toggle source

Replace the setter by instantiating the value

Calls superclass method
# File lib/torque/postgresql/attributes/enum_set.rb, line 153
def []=(key, value)
  super(key, instantiate(value))
end
eql?(other)
Alias for: ==
inspect() click to toggle source

Change the inspection to show the enum name

# File lib/torque/postgresql/attributes/enum_set.rb, line 148
def inspect
  "[#{map(&:inspect).join(', ')}]"
end
merge(other) click to toggle source

Override the merge method to ensure formatted values

Calls superclass method
# File lib/torque/postgresql/attributes/enum_set.rb, line 158
def merge(other)
  super other.map(&method(:instantiate))
end
replace(*values) click to toggle source

It only accepts if the other value is valid

Calls superclass method
# File lib/torque/postgresql/attributes/enum_set.rb, line 132
def replace(*values)
  super(transform_values(values))
end
text(attr = nil, model = nil) click to toggle source

Get a translated version of the value

# File lib/torque/postgresql/attributes/enum_set.rb, line 137
def text(attr = nil, model = nil)
  map { |item| item.text(attr, model) }.to_sentence
end
Also aliased as: to_s
to_i() click to toggle source

Get the index of the value

# File lib/torque/postgresql/attributes/enum_set.rb, line 143
def to_i
  self.class.power(@hash.keys)
end
to_s(attr = nil, model = nil)
Alias for: text

Private Instance Methods

instantiate(value) click to toggle source

Create a new enum instance of the value

# File lib/torque/postgresql/attributes/enum_set.rb, line 188
def instantiate(value)
  value.is_a?(self.class.enum_source) ? value : self.class.enum_source.new(value)
end
method_missing(method_name, *arguments) click to toggle source

Allow '_' to be associated to '-'

Calls superclass method
# File lib/torque/postgresql/attributes/enum_set.rb, line 217
def method_missing(method_name, *arguments)
  name = method_name.to_s

  if name.chomp!('?')
    include?(name)
  elsif name.chomp!('!')
    add(name) unless include?(name)
  else
    super
  end
end
raise_comparison(other) click to toggle source

Throw an exception for comparasion between different enums

# File lib/torque/postgresql/attributes/enum_set.rb, line 239
def raise_comparison(other)
  raise EnumSetError, "Comparison of #{self.class.name} with #{self.inspect} failed"
end
raise_invalid(value) click to toggle source

Throw an exception for invalid valus

# File lib/torque/postgresql/attributes/enum_set.rb, line 230
def raise_invalid(value)
  if value.is_a?(Numeric)
    raise EnumSetError, "#{value.inspect} is out of bounds of #{self.class.name}"
  else
    raise EnumSetError, "#{value.inspect} is not valid for #{self.class.name}"
  end
end
respond_to_missing?(method_name, include_private = false) click to toggle source

Check for valid '?' and '!' methods

# File lib/torque/postgresql/attributes/enum_set.rb, line 209
def respond_to_missing?(method_name, include_private = false)
  name = method_name.to_s

  return true if name.chomp!('?')
  name.chomp!('!') && self.class.valid?(name)
end
transform_power(value) click to toggle source

Turn a binary (power) definition into real values

# File lib/torque/postgresql/attributes/enum_set.rb, line 193
def transform_power(value)
  list = value.to_s(2).reverse.chars.map.with_index do |item, idx|
    next idx if item.eql?('1')
  end

  raise raise_invalid(value) if list.size > self.class.size
  self.class.members.values_at(*list.compact)
end
transform_values(values) click to toggle source

Turn all the values into their respective Enum representations

# File lib/torque/postgresql/attributes/enum_set.rb, line 203
def transform_values(values)
  values = values.first if values.size.eql?(1) && values.first.is_a?(::Enumerable)
  values.map(&method(:instantiate)).reject(&:nil?)
end