Methods
C
G
I
N
O
V
Attributes
[R] attribute
[R] extension
[R] values
Class Public methods
new(attribute, values=[], &extension)
# File lib/bitmask_attributes/definition.rb, line 5
def initialize(attribute, values=[], &extension)
  @attribute = attribute
  @values = values
  @extension = extension
end
Instance Public methods
install_on(model)
# File lib/bitmask_attributes/definition.rb, line 11
def install_on(model)
  validate_for model
  generate_bitmasks_on model
  override model
  create_convenience_class_method_on model
  create_convenience_instance_methods_on model
  create_scopes_on model
  create_attribute_methods_on model
end
Instance Private methods
create_attribute_methods_on(model)

Returns the defined values as an Array.

# File lib/bitmask_attributes/definition.rb, line 65
def create_attribute_methods_on(model)
  model.class_eval %Q(
    def self.values_for_#{attribute}      # def self.values_for_numbers
      #{values}                           #   [:one, :two, :three]
    end                                   # end
  )
end
create_convenience_class_method_on(model)
# File lib/bitmask_attributes/definition.rb, line 73
def create_convenience_class_method_on(model)
  model.class_eval %Q(
    def self.bitmask_for_#{attribute}(*values)
      values.inject(0) do |bitmask, value|
        unless (bit = bitmasks[:#{attribute}][value])
          raise ArgumentError, "Unsupported value for #{attribute}: \#{value.inspect}"
        end
        bitmask | bit
      end
    end
  )
end
create_convenience_instance_methods_on(model)
# File lib/bitmask_attributes/definition.rb, line 86
def create_convenience_instance_methods_on(model)
  values.each do |value|
    model.class_eval %Q(
      def #{attribute}_for_#{value}?                  
        self.#{attribute}?(:#{value})
      end
    )
  end
  model.class_eval %Q(
    def #{attribute}?(*values)
      if !values.blank?
        values.all? do |value|
          self.#{attribute}.include?(value)
        end
      else
        self.#{attribute}.present?
      end
    end
  )
end
create_scopes_on(model)
# File lib/bitmask_attributes/definition.rb, line 107
def create_scopes_on(model)
  model.class_eval %Q(
    scope :with_#{attribute},
      proc { |*values|
        if values.blank?
          where('#{attribute} > 0 OR #{attribute} IS NOT NULL')
        else
          sets = values.map do |value|
            mask = #{model}.bitmask_for_#{attribute}(value)
            "#{attribute} & \#{mask} <> 0"
          end
          where(sets.join(' AND '))
        end
      }
    scope :without_#{attribute}, 
      proc { |value| 
        if value
          mask = #{model}.bitmask_for_#{attribute}(value)
          where("#{attribute} IS NULL OR #{attribute} & ? = 0", mask)
        else
          where("#{attribute} IS NULL OR #{attribute} = 0")
        end              
        }                    
    
    scope :no_#{attribute}, where("#{attribute} = 0 OR #{attribute} IS NULL")
    
    scope :with_any_#{attribute},
      proc { |*values|
        if values.blank?
          where('#{attribute} > 0 OR #{attribute} IS NOT NULL')
        else
          sets = values.map do |value|
            mask = #{model}.bitmask_for_#{attribute}(value)
            "#{attribute} & \#{mask} <> 0"
          end
          where(sets.join(' OR '))
        end
      }
  )
  values.each do |value|
    model.class_eval %Q(
      scope :#{attribute}_for_#{value},
            where('#{attribute} & ? <> 0', #{model}.bitmask_for_#{attribute}(:#{value}))
    )
  end      
end
generate_bitmasks_on(model)
# File lib/bitmask_attributes/definition.rb, line 34
def generate_bitmasks_on(model)
  model.bitmasks[attribute] = HashWithIndifferentAccess.new.tap do |mapping|
    values.each_with_index do |value, index|
      mapping[value] = 0b1 << index
    end
  end
end
override(model)
# File lib/bitmask_attributes/definition.rb, line 42
def override(model)
  override_getter_on(model)
  override_setter_on(model)
end
override_getter_on(model)
# File lib/bitmask_attributes/definition.rb, line 47
def override_getter_on(model)
  model.class_eval %Q(
    def #{attribute}
      @#{attribute} ||= BitmaskAttributes::ValueProxy.new(self, :#{attribute}, &self.class.bitmask_definitions[:#{attribute}].extension)
    end
  )
end
override_setter_on(model)
# File lib/bitmask_attributes/definition.rb, line 55
def override_setter_on(model)
  model.class_eval %Q(
    def #{attribute}=(raw_value)
      values = raw_value.kind_of?(Array) ? raw_value : [raw_value]
      self.#{attribute}.replace(values.reject(&:blank?))
    end
  )
end
validate_for(model)
# File lib/bitmask_attributes/definition.rb, line 23
def validate_for(model)
  # The model cannot be validated if it is preloaded and the attribute/column is not in the
  # database (the migration has not been run) or table doesn't exist. This usually
  # occurs in the 'test' and 'production' environment or during migration.
  return if defined?(Rails) && Rails.configuration.cache_classes || !model.table_exists?
 
  unless model.columns.detect { |col| col.name == attribute.to_s }
    raise ArgumentError, "`#{attribute}' is not an attribute of `#{model}'"
  end
end