require 'bindata/base' module BinData # A Choice is a collection of data objects of which only one is active # at any particular time. # # require 'bindata' # require 'stringio' # # choices = [ [:int8, {:value => 3}], [:int8, {:value => 5}] ] # a = BinData::Choice.new(:choices => choices, :selection => 1) # a.value # => 5 # # == Parameters # # Parameters may be provided at initialisation to control the behaviour of # an object. These params are: # # :choices:: An array specifying the possible data objects. # The format of the array is a list of symbols # representing the data object type. If a choice # is to have params passed to it, then it should be # provided as [type_symbol, hash_params]. # :selection:: An index into the :choices array which specifies # the currently active choice. class Choice < Base # Register this class register(self.name, self) # These are the parameters used by this class. mandatory_parameters :choices, :selection def initialize(params = {}, env = nil) super(params, env) # instantiate all choices @choices = [] param(:choices).each do |choice_type, choice_params| choice_params ||= {} klass = self.class.lookup(choice_type) if klass.nil? raise TypeError, "unknown type '#{choice_type.id2name}' for #{self}" end @choices << klass.new(choice_params, create_env) end end # Resets the internal state to that of a newly created object. def clear the_choice.clear end # Returns if the selected data object is clear?. def clear? the_choice.clear? end # Reads the value of the selected data object from +io+. def _do_read(io) the_choice.do_read(io) end # To be called after calling #do_read. def done_read the_choice.done_read end # Writes the value of the selected data object to +io+. def _write(io) the_choice.write(io) end # Returns the number of bytes it will take to write the # selected data object. def _num_bytes(what) the_choice.num_bytes(what) end # Returns a snapshot of the selected data object. def snapshot the_choice.snapshot end # Returns a list of the names of all fields of the selected data object. def field_names the_choice.field_names end # Returns the data object that stores values for +name+. def find_obj_for_name(name) field_names.include?(name) ? the_choice.find_obj_for_name(name) : nil end # Override to include selected data object. def respond_to?(symbol, include_private = false) super || the_choice.respond_to?(symbol, include_private) end def method_missing(symbol, *args) if the_choice.respond_to?(symbol) the_choice.__send__(symbol, *args) else super end end #--------------- private # Returns the selected data object. def the_choice index = eval_param(:selection) if index < 0 or index >= @choices.length raise IndexError, "selection #{index} is out of range" end @choices[index] end end end