class BinData::Choice

specifies the currently active choice.
:selection
An index/key into the :choices array/hash which
contain symbols as keys.
An implementation gotcha is that the hash may not
should be provided as [type_symbol, hash_params].
If a choice is to have params passed to it, then it
a list of symbols representing the data object type.
data objects. The format of the array/hash.values is
: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_s #=> “000001”
a.selection #=> ‘little’
mychoice.replace ‘little’
a.to_s #=> “001000”
a.value = 256
:selection => lambda { mychoice })
a = BinData::Choice.new(:choices => choices,
choices = {‘big’ => :uint16be, ‘little’ => :uint16le}
mychoice = ‘big’
a.value # => “Type1”
a = BinData::Choice.new(:choices => choices, :selection => 3)
choices = [ nil, nil, nil, type1, nil, type2 ]
a.value # => “Type2”
a = BinData::Choice.new(:choices => choices, :selection => 1)
choices = [ type1, type2 ]
a.value # => “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 initialize(params = {}, parent = nil)

def initialize(params = {}, parent = nil)
  super(params, parent)
  @choices  = {}
  @last_key = nil
end

def method_missing(symbol, *args, &block)

def method_missing(symbol, *args, &block)
  if the_choice.respond_to?(symbol)
    the_choice.__send__(symbol, *args, &block)
  else
    super
  end
end

def obj

A choice represents a specific object.
def obj
  the_choice
end

def respond_to?(symbol, include_private = false)

Override to include selected data object.
def respond_to?(symbol, include_private = false)
  super || the_choice.respond_to?(symbol, include_private)
end

def sanitize_parameters!(sanitizer, params)

Ensures that +params+ is of the form expected by #initialize.
def sanitize_parameters!(sanitizer, params)
  if params.has_key?(:choices)
    choices = params[:choices]
    # convert array to hash keyed by index
    if ::Array === choices
      tmp = {}
      choices.each_with_index do |el, i|
        tmp[i] = el unless el.nil?
      end
      choices = tmp
    end
    # ensure valid hash keys
    if choices.has_key?(nil)
      raise ArgumentError, ":choices hash may not have nil key"
    end
    if choices.keys.detect { |k| Symbol === k }
      raise ArgumentError, ":choices hash may not have symbols for keys"
    end
    # sanitize each choice
    new_choices = {}
    choices.each_pair do |key, val|
      type, param = val
      klass = sanitizer.lookup_klass(type)
      sanitized_params = sanitizer.sanitize_params(klass, param)
      new_choices[key] = [klass, sanitized_params]
    end
    params[:choices] = new_choices
  end
  super(sanitizer, params)
end

def selection

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

def selection=(v)

pc.data #=> "Type2"
pc.selection = 17

pc.data #=> "Type1"
pc.selection = 5

pc = ProgrammaticChoice.new(:choices => choices)
choices = {5 => type1, 17 => type2}

type2 = [:string, {:value => "Type2"}]
type1 = [:string, {:value => "Type1"}]

end
attrib_accessor :selection
choice :data, :choices => :choices, :selection => :selection
class ProgrammaticChoice < BinData::MultiValue

then try something like the following.
If you really *must* be able to programmatically adjust the selection

This is deliberate to promote the declarative nature of BinData.
There is no #selection= method to complement the #selection method.
This method does not exist. This stub only exists to document why.
def selection=(v)
  raise NoMethodError
end

def the_choice

Returns the selected data object.
def the_choice
  key = eval_param(:selection)
  if key.nil?
    raise IndexError, ":selection returned nil value"
  end
  obj = @choices[key]
  if obj.nil?
    # instantiate choice object
    choice_klass, choice_params = no_eval_param(:choices)[key]
    if choice_klass.nil?
      raise IndexError, "selection #{key} does not exist in :choices"
    end
    obj = choice_klass.new(choice_params, self)
    @choices[key] = obj
  end
  # for single_values copy the value when the selected object changes
  if key != @last_key
    if @last_key != nil
      prev = @choices[@last_key]
      if prev != nil and prev.single_value? and obj.single_value?
        obj.value = prev.value
      end
    end
    @last_key = key
  end
  obj
end