class BitMagic::Adapters::Magician

A container for bit_magic settings and fields Meant to be used internally by the Base adapter (and by extension, all adapters).

@attr_reader [Hash] field_options bit_magic options that define fields @attr_reader [Hash] action_options bit_magic options that define settings @attr_reader [Hash] field_list name => bits key pairs based off field_options @attr_reader [Integer] bits_length total number of bits defined in field_options @attr_reader [Integer] max_bit the largest bit defined in field_options @attr_reader [Symbol] bit_magic_name the name given to bit_magic

Constants

DEFAULT_ACTION_OPTIONS

Attributes

action_options[R]
bit_magic_name[R]
bits_length[R]
field_list[R]
field_options[R]
max_bit[R]

Public Class Methods

field_key_value_check(check) click to toggle source

Checks if the key is a a field key definition (Integer or Range, defining bit or bit ranges in question).

@param [Integer, Range<Integer>] checkValue an integer bit or bit range

to check if it is a valid bit index

@return [Integer, Array<Integer>] will return an integer or an array of

integers if the checkValue is a valid bit index or bit range
# File lib/bit_magic/adapters/magician.rb, line 29
def self.field_key_value_check(check)
  if check.is_a?(Integer)
    check
  elsif check.is_a?(Range)
    list = check.to_a
    valid = list.reduce(true) {|m, i| m && i.is_a?(Integer) }
    list if valid and list.length > 0
  elsif check.is_a?(Array)
    valid = true
    list = check.collect {|i|
      key = self.field_key_value_check(i)
      key.nil? ? (valid = false; break;) : key
    }.flatten
    list if valid and list.length > 0
  end
end
new(name, options = {}) click to toggle source

Initialize a new Magician, a container for bit_magic settings and fields

@param [Symbol] name the name to be used as a namespace @param [Hash] options the options given to bit_magic. Keys that are

Integer, Arrays or Range objects are treated as bit allocations, their
value should be the name of the bit field. Keys that are anything else
(usually Symbol) are treated as action options or settings.

@example Initialize a Magician (usually you would not do this directly)

magician = Magician.new(:example, 0 => :is_odd, [1, 2] => :eyes, 3..6 => :fingers, default: 7)
# here, field names are :is_odd, :eyes, and :fingers
# with bits indices 0, [1, 2], and [3, 4, 5, 6] respectively
# default is an action option, set to 7

@return a Magician

# File lib/bit_magic/adapters/magician.rb, line 98
def initialize(name, options = {})
  @bit_magic_name = name
  @field_options, @action_options = self.class.options_splitter(options)
  validate_field_options!
end
options_splitter(options = {}) click to toggle source

Separate field and action options from the options passed to bit_magic

Valid keys for field options are:

Integer - for a specific bit position
Range - for a range of bits
Array<Integer> - an array of bit positions

The value of the key-pair should be a Symbol.

Action options are everything else that's not a field option

@param [Hash] options the options passed to bit_magic

@return [Hash, Hash] returns an array of two options [field, actions]

field options and action options, in that order respectively
# File lib/bit_magic/adapters/magician.rb, line 60
def self.options_splitter(options = {})
  field_opts = {}
  action_opts = DEFAULT_ACTION_OPTIONS.dup
  
  options.each_pair do |check_key, value|
    if key = self.field_key_value_check(check_key)
      field_opts[key] = value
    else
      if (!options[:allow_failed_fields]) and (check_key.is_a?(Integer) or check_key.is_a?(Range) or check_key.is_a?(Array))
        raise BitMagic::FieldError.new("key-pair expected to be a valid field option, but it is not: #{check_key.inspect} => #{value.inspect}. If this is an action option, you can disable this error by passing ':allow_failed_fields => true' as an option")
      end
      action_opts[check_key] = value
    end
  end
  
  [field_opts.freeze, action_opts.freeze]
end

Public Instance Methods

bits() click to toggle source

List of bits defined in @field_options

@return [Array<Integer>] an array of bits defined in @field_options

# File lib/bit_magic/adapters/magician.rb, line 175
def bits
  @field_list.values.flatten
end
bits_generator() click to toggle source

Used by adapters to generate value lists for particular bit operations

@return [BitsGenerator] a BitsGenerator object with this magician's field

list
# File lib/bit_magic/adapters/magician.rb, line 190
def bits_generator
  @bits_generator ||= (self.action_options[:bits_generator] || BitsGenerator).new self
end
bits_wrapper() click to toggle source

Used by the Base#bit_magic to create a Bits wrapper around instances

@return [Class] a Bits class

# File lib/bit_magic/adapters/magician.rb, line 182
def bits_wrapper
  self.action_options[:bits_wrapper] || Bits
end
define_bit_magic_methods(klass) click to toggle source

Define helper methods on the instance, namespaced to the name given in the bit_magic invocation.

This is an internal method, only meant to be used by the Base adapter to during its setup phase. Should not be used directly.

Methods that are defined is namespaced to the name during initialization. Referred to here as NAMESPACE. These methods are available on instances.

NAMESPACE - defined by Base adapter, returns a Bits wrapper
NAMESPACE_enabled?(*field_names) - checks if all the given field names
  or bit indices are enabled (value > 0)
NAMESPACE_disabled?(*field_names) - checks if all the given field names
  or bit indices are disabled (value == 0)

The following are helpers, defined based on field names during initialization Refered to here as 'name'.

name - returns the value of the field
name=(new_value) - sets the value of the field to the new value
name? - available only if the field is a single bit, returns true if 
  the value of the bit is 1, or false if 0

@param [Class] klass the class to inject methods into.

@return nothing useful.

# File lib/bit_magic/adapters/magician.rb, line 131
def define_bit_magic_methods(klass)
  names = @field_list
  bit_magic_name = @bit_magic_name
  
  klass.instance_eval do
  
    define_method(:"#{bit_magic_name}_enabled?") do |*fields|
      self.send(bit_magic_name).enabled?(*fields)
    end
  
    define_method(:"#{bit_magic_name}_disabled?") do |*fields|
      self.send(bit_magic_name).disabled?(*fields)
    end
  end
  
  if @action_options[:helpers]
  
    klass.instance_eval do
      names.each_pair do |name, bits|
        
        define_method(:"#{name}") do
          self.send(bit_magic_name)[name]
        end
        
        define_method(:"#{name}=") do |val|
          self.send(bit_magic_name)[name] = val
        end
        
        if bits.is_a?(Integer) or bits.length == 1
          define_method(:"#{name}?") do
            self.send(bit_magic_name)[name] == 1
          end
        end
        
      end
    end
  
  end
  
end
inspect() click to toggle source

Inspect this object. This is customized just to shorten the output to actually be readable.

# File lib/bit_magic/adapters/magician.rb, line 196
def inspect
  "#<#{self.class.to_s} name=#{@bit_magic_name} field_list=#{@field_list.inspect}>"
end

Protected Instance Methods

validate_field_options!() click to toggle source

Internal use only. Sets @field_list @bits_length and @max_bit from @field_options

# File lib/bit_magic/adapters/magician.rb, line 202
def validate_field_options!
  @field_list = {}
  
  @field_options.each_pair do |bits, name|
    name = name.to_sym if name.is_a?(String)
    
    if name.is_a?(Symbol)
      raise FieldError.new("'#{name}' defined more than once") if @field_list.has_key?(name)
      @field_list[name] = bits
    else
      raise FieldError.new("field name must be a symbol or string, #{name.inspect} is not")
    end
    
  end
  
  bits = self.bits
  @bits_length = bits.uniq.length
  @max_bit = bits.max
  @field_list.freeze
end