class BinData::Choice

selection changes. Default is false.
selection to the current selection whenever the
:copy_on_change
If set to true, copy the value of the previous
specifies the currently active choice.
:selection
An index/key into the :choices array/hash which
:selection does not exist in the :choices hash.
of :default. :default is to be used when then
not contain symbols as keys, with the exception
implementation constraint is that the hash may
be provided as [type_symbol, hash_params]. An
is to have params passed to it, then it should
representing the data object type. If a choice
array/hash.values is a list of symbols
data objects. The format of the
:choices

Either an array or a hash specifying the possible
an object. These params are:
Parameters may be provided at initialisation to control the behaviour of
== Parameters
a.to_binary_s #=> “000001”
mychoice.choice = ‘little’
a.to_binary_s #=> “001000”
a.assign(256)
:selection => lambda { mychoice.choice })
a = BinData::Choice.new(:choices => choices, :copy_on_change => true,
choices = {‘big’ => :uint16be, ‘little’ => :uint16le}
mychoice.choice = ‘big’
mychoice = Chooser.new
Chooser = Struct.new(:choice)
a # => “Type1”
a = BinData::Choice.new(:choices => choices, :selection => 3)
choices = [ nil, nil, nil, type1, nil, type2 ]
a # => “Type2”
a = BinData::Choice.new(:choices => choices, :selection => 1)
choices = [ type1, type2 ]
a # => “Type1”
a = BinData::Choice.new(:choices => choices, :selection => 5)
choices = {5 => type1, 17 => type2}
type2 = [:string, {:value => “Type2”}]
type1 = [:string, {:value => “Type1”}]
require ‘bindata’
choice.
at any particular time. Method calls will be delegated to the active
A Choice is a collection of data objects of which only one is active

def assign(val)

def assign(val)
  current_choice.assign(val)
end

def choices_as_hash(choices)

def choices_as_hash(choices)
  if choices.respond_to?(:to_ary)
    key_array_by_index(choices.to_ary)
  else
    choices
  end
end

def clear #:nodoc:

:nodoc:
def clear #:nodoc:
  current_choice.clear
end

def clear? #:nodoc:

:nodoc:
def clear? #:nodoc:
  current_choice.clear?
end

def copy_previous_value(selection, obj)

def copy_previous_value(selection, obj)
  prev = get_previous_choice(selection)
  obj.assign(prev) unless prev.nil?
  remember_current_selection(selection)
end

def current_choice

def current_choice
  selection = eval_parameter(:selection)
  if selection.nil?
    raise IndexError, ":selection returned nil for #{debug_name}"
  end
  obj = get_or_instantiate_choice(selection)
  hook_after_current_choice(selection, obj)
  obj
end

def do_num_bytes #:nodoc:

:nodoc:
def do_num_bytes #:nodoc:
  current_choice.do_num_bytes
end

def do_read(io) #:nodoc:

:nodoc:
def do_read(io) #:nodoc:
  hook_before_do_read
  current_choice.do_read(io)
end

def do_write(io) #:nodoc:

:nodoc:
def do_write(io) #:nodoc:
  current_choice.do_write(io)
end

def ensure_valid_keys(choices)

def ensure_valid_keys(choices)
  if choices.has_key?(nil)
    raise ArgumentError, ":choices hash may not have nil key"
  end
  if choices.keys.detect { |key| key.is_a?(Symbol) and key != :default }
    raise ArgumentError, ":choices hash may not have symbols for keys"
  end
end

def get_or_instantiate_choice(selection)

def get_or_instantiate_choice(selection)
  @choices[selection] ||= instantiate_choice(selection)
end

def get_previous_choice(selection)

def get_previous_choice(selection)
  if selection != @last_selection and @last_selection != nil
    @choices[@last_selection]
  else
    nil
  end
end

def hook_after_current_choice(*args); end

def hook_after_current_choice(*args); end

def hook_before_do_read; end

def hook_before_do_read; end

def initialize_instance

def initialize_instance
  @choices = {}
  @last_selection = nil
end

def initialize_shared_instance

def initialize_shared_instance
  if eval_parameter(:copy_on_change) == true
    class << self
      alias_method :hook_after_current_choice, :copy_previous_value
    end
  end
end

def instantiate_choice(selection)

def instantiate_choice(selection)
  prototype = get_parameter(:choices)[selection]
  if prototype.nil?
    raise IndexError, "selection '#{selection}' does not exist in :choices for #{debug_name}"
  end
  prototype.instantiate(nil, self)
end

def key_array_by_index(array)

def key_array_by_index(array)
  result = {}
  array.each_with_index do |el, i|
    result[i] = el unless el.nil?
  end
  result
end

def method_missing(symbol, *args, &block) #:nodoc:

:nodoc:
def method_missing(symbol, *args, &block) #:nodoc:
  current_choice.__send__(symbol, *args, &block)
end

def null_method; end

def null_method; end

def remember_current_selection(selection)

def remember_current_selection(selection)
  @last_selection = selection
end

def respond_to?(symbol, include_private = false) #:nodoc:

:nodoc:
def respond_to?(symbol, include_private = false) #:nodoc:
  current_choice.respond_to?(symbol, include_private) || super
end

def safe_respond_to?(symbol, include_private = false) #:nodoc:

:nodoc:
def safe_respond_to?(symbol, include_private = false) #:nodoc:
  orig_respond_to?(symbol, include_private)
end

def sanitize_parameters!(params) #:nodoc:

:nodoc:
def sanitize_parameters!(params) #:nodoc:
  params.merge!(dsl_params)
  if params.needs_sanitizing?(:choices)
    choices = choices_as_hash(params[:choices])
    ensure_valid_keys(choices)
    params[:choices] = params.create_sanitized_choices(choices)
  end
end

def selection

A convenience method that returns the current selection.
def selection
  eval_parameter(:selection)
end

def snapshot

def snapshot
  current_choice.snapshot
end

def trace_selection

def trace_selection
  BinData::trace_message do |tracer|
    selection_string = eval_parameter(:selection).inspect
    tracer.trace_obj("#{debug_name}-selection-", selection_string)
  end
end

def turn_off_tracing

def turn_off_tracing
  alias_method :hook_before_do_read, :null_method
end

def turn_on_tracing

def turn_on_tracing
  alias_method :hook_before_do_read, :trace_selection
end