class BinData::Array
- to any lambda evaluated as a parameter of that data object.
Each data object in an array has the variableindex
made available
as much data from the stream as possible.
is the symbol :eof, then the array will read
this parameter. If the value of this parameter
are made available to any lambda assigned to
The variablesindex
,element
andarray
read an array until a sentinel value is found.
condition is true. This is typically used to:read_until
- While reading, elements are read until this
:initial_length
- The initial length of the array.
[type_symbol, hash_params]
.
passed to it, then it should be provided as
array elements. If the type is to have params:type
-
The symbol representing the data type of the
an object. These params are:
Parameters may be provided at initialisation to control the behaviour of
== Parameters
obj.snapshot #=> [3, 4, 5, 6, 7, 8, 9]
obj.read(data)
obj = BinData::Array.new(:type => :int8, :read_until => :eof)
obj.snapshot #=> [3, 4, 5, 6, 7]
obj.read(data)
:read_until => lambda { array + array[index - 1] == 13 })
obj = BinData::Array.new(:type => :int8,
obj.snapshot #=> [3, 4, 5, 6]
obj.read(data)
:read_until => lambda { element >= 6 })
obj = BinData::Array.new(:type => :int8,
obj.snapshot #=> [3, 4]
obj.read(data)
:read_until => lambda { index == 1 })
obj = BinData::Array.new(:type => :int8,
obj.snapshot #=> [3, 4, 5, 6, 7, 8]
obj.read(data)
obj = BinData::Array.new(:type => :int8, :initial_length => 6)
data = “x03x04x05x06x07x08x09”
require ‘bindata’
An Array is a list of data objects of the same type.
- The initial length of the array.
- While reading, elements are read until this
def [](*args)
Returns the element at +index+. If the element is a single_value
def [](*args) if args.length == 1 and ::Integer === args[0] # extend array automatically while args[0] >= elements.length append_new_element end end data = elements[*args] if args.length > 1 or ::Range === args[0] data.collect { |el| (el && el.single_value?) ? el.value : el } else (data && data.single_value?) ? data.value : data end end
def []=(index, value)
Sets the element at +index+. If the element is a single_value
def []=(index, value) # extend array automatically while index >= elements.length append_new_element end obj = elements[index] unless obj.single_value? # TODO: allow setting objects, not just values raise NoMethodError, "undefined method `[]=' for #{self}", caller end obj.value = value end
def _do_num_bytes(index)
+index+. If +index+, then returns the number of bytes required
Returns the number of bytes it will take to write the element at
def _do_num_bytes(index) if index.nil? (elements.inject(0) { |sum, f| sum + f.do_num_bytes }).ceil else elements[index].do_num_bytes end end
def _do_read(io)
def _do_read(io) if has_param?(:initial_length) elements.each { |f| f.do_read(io) } elsif has_param?(:read_until) if no_eval_param(:read_until) == :eof @element_list = nil loop do element = append_new_element begin element.do_read(io) rescue @element_list.pop break end end else @element_list = nil loop do element = append_new_element element.do_read(io) variables = { :index => self.length - 1, :element => self.last, :array => self } finished = eval_param(:read_until, variables) break if finished end end end end
def _do_write(io)
def _do_write(io) elements.each { |f| f.do_write(io) } end
def _snapshot
def _snapshot elements.collect { |e| e.snapshot } end
def append(value = nil)
single_values then the +value+ may be provided to the call.
Appends a new element to the end of the array. If the array contains
def append(value = nil) # TODO: deprecate #append as it can be replaced with #push append_new_element self[-1] = value unless value.nil? self.last end
def append_new_element
Creates a new element and appends it to the end of @element_list.
def append_new_element # ensure @element_list is initialised elements() element = @element_klass.new(@element_params, self) @element_list << element element end
def clear(index = nil)
the internal state of the array is reset to that of a newly created
Clears the element at position +index+. If +index+ is not given, then
def clear(index = nil) if @element_list.nil? # do nothing as the array is already clear elsif index.nil? @element_list = nil elsif index < elements.length elements[index].clear end end
def clear?(index = nil)
Returns if the element at position +index+ is clear?. If +index+
def clear?(index = nil) if @element_list.nil? true elsif index.nil? elements.each { |f| return false if not f.clear? } true else (index < elements.length) ? elements[index].clear? : true end end
def done_read
def done_read elements.each { |f| f.done_read } end
def each
Iterate over each element in the array. If the elements are
def each elements.each do |el| yield(el.single_value? ? el.value : el) end end
def elements
Returns the list of all elements in the array. The elements
def elements if @element_list.nil? @element_list = [] if has_param?(:initial_length) # create the desired number of instances eval_param(:initial_length).times do append_new_element end end end @element_list end
def empty?
def empty? length.zero? end
def first(n = nil)
If the array is empty, the first form returns nil, and the second
Returns the first element, or the first +n+ elements, of the array.
def first(n = nil) if n.nil? and elements.empty? # explicitly return nil as arrays grow automatically nil elsif n.nil? self[0] else self[0, n] end end
def index(obj)
def index(obj) # TODO handle single values elements.index(obj) end
def initialize(params = {}, parent = nil)
def initialize(params = {}, parent = nil) super(params, parent) klass, el_params = no_eval_param(:type) @element_list = nil @element_klass = klass @element_params = el_params end
def last(n = nil)
If the array is empty, the first form returns nil, and the second
Returns the last element, or the last +n+ elements, of the array.
def last(n = nil) if n.nil? self[-1] else n = length if n > length self[-n, n] end end
def length
def length elements.length end
def push(*args)
This expression returns the array itself, so several appends may
Pushes the given object(s) on to the end of this array.
def push(*args) args.each do |arg| if @element_klass == arg.class # TODO: need to modify arg.env to add_variable(:index) and # to link arg.env to self.env elements.push(arg) else append(arg) end end self end
def sanitize_parameters!(sanitizer, params)
def sanitize_parameters!(sanitizer, params) unless params.has_key?(:initial_length) or params.has_key?(:read_until) # ensure one of :initial_length and :read_until exists params[:initial_length] = 0 end if params.has_key?(:read_length) warn ":read_length is not used with arrays. You probably want to change this to :initial_length" end if params.has_key?(:type) type, el_params = params[:type] klass = sanitizer.lookup_klass(type) sanitized_params = sanitizer.sanitize_params(klass, el_params) params[:type] = [klass, sanitized_params] end super(sanitizer, params) end
def single_value?
Returns whether this data object contains a single value. Single
def single_value? return false end
def to_ary
def to_ary snapshot end