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
- An index/key into the :choices array/hash which
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
def obj the_choice end
def respond_to?(symbol, include_private = false)
def respond_to?(symbol, include_private = false) super || the_choice.respond_to?(symbol, include_private) end
def sanitize_parameters!(sanitizer, params)
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
def selection eval_param(:selection) end
def selection=(v)
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
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