module CompactFlags::HasFlags::ClassMethods

Public Instance Methods

compact_flags(*args) click to toggle source
# File lib/compact_flags.rb, line 13
def compact_flags(*args)
  mapping = args.first
  store_column = mapping.keys.first
  flags = mapping[store_column]

  raise "No flags defined" if flags.blank?
  raise "Too many flags, maximum flags count (#{MAX_FLAGS_COUNT})" if flags.size > MAX_FLAGS_COUNT

  @@flags ||={}
  @@store_columns ||={}
  i=0

  flags.each do |flag|
    @@flags[flag] = 1 << i
    @@store_columns[flag] = store_column
    i += 1

    # Define instance getter
    define_method "#{flag}" do
      return (@@flags[flag] & self.send(store_column)) > 0
    end

    alias_method "#{flag}?", "#{flag}"

    # Define instance setter
    define_method "#{flag}=" do |val|
      self.send("#{store_column}=", (val ?
          self.send(store_column) | @@flags[flag] :
          self.send(store_column) & (MAX_FLAGS_MAPPING ^ @@flags[flag]) ))
    end

    define_method "#{store_column}_values" do
      vals = []
      flags.each do |flag|
        vals << flag.to_s.titleize if self.send(flag)
      end
      return vals
    end

    # named scopes to be used in conditions
    scope "#{flag}".pluralize.to_sym, -> {where("(#{@@store_columns[flag]} & #{@@flags[flag]}) > 0")}
    scope "not_#{flag}".pluralize.to_sym, -> {where("(#{@@store_columns[flag]} & #{@@flags[flag]}) = 0")}
  end

  class << self
    @@store_columns.values.uniq.each do |store_column|
      define_method "#{store_column}_or" do |flags, column_name=store_column|
        raise "Expected array of flags" unless flags.is_a? Array
        raise "Expected array of flags, Minimum 2 flags" if flags.count < 2
        where_query = []
        flags.each do |flag|
          where_query << self.send("where_#{flag}")
        end
        return self.where(where_query.join(' or '))
      end
    end

    @@flags.each do |key, value|
      define_method "#{key}_value" do
        return value
      end

      define_method "where_#{key}" do
        return "((#{@@store_columns[key]} & #{@@flags[key]}) > 0)"
      end

      define_method "where_not_#{key}" do
        return "((#{@@store_columns[key]} & #{@@flags[key]}) = 0)"
      end
    end
  end
end