Class: BinData::Array

Inherits:
Base
  • Object
show all
Includes:
Enumerable
Defined in:
lib/bindata/array.rb

Overview

An Array is a list of data objects of the same type.

require 'bindata'

data = "\x03\x04\x05\x06\x07\x08\x09"

obj = BinData::Array.new(:type => :int8, :initial_length => 6)
obj.read(data)
obj.snapshot #=> [3, 4, 5, 6, 7, 8]

obj = BinData::Array.new(:type => :int8,
                         :read_until => lambda { index == 1 })
obj.read(data)
obj.snapshot #=> [3, 4]

obj = BinData::Array.new(:type => :int8,
                         :read_until => lambda { element >= 6 })
obj.read(data)
obj.snapshot #=> [3, 4, 5, 6]

obj = BinData::Array.new(:type => :int8,
        :read_until => lambda { array[index] + array[index - 1] == 13 })
obj.read(data)
obj.snapshot #=> [3, 4, 5, 6, 7]

Parameters

Parameters may be provided at initialisation to control the behaviour of an object. These params are:

:type

The symbol representing the data type of the array elements. If the type is to have params passed to it, then it should be provided as [type_symbol, hash_params].

:initial_length

The initial length of the array.

:read_until

While reading, elements are read until this condition is true. This is typically used to read an array until a sentinel value is found. The variables index, element and array are made available to any lambda assigned to this parameter.

Each data object in an array has the variable index made available to any lambda evaluated as a parameter of that data object.

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

accepted_parameters, default_parameters, #do_read, #inspect, lookup, mandatory_parameters, mutually_exclusive_parameters, #num_bytes, optional_parameters, read, #read, register, #to_s, #write

Constructor Details

#initialize(params = {}, env = nil) ⇒ Array

Creates a new Array



88
89
90
91
92
93
94
95
96
# File 'lib/bindata/array.rb', line 88

def initialize(params = {}, env = nil)
  super(params, env)

  klass, el_params = param(:type)

  @element_list    = nil
  @element_klass   = klass
  @element_params  = el_params
end

Class Method Details

.all_possible_field_names(sanitized_params) ⇒ Object

An array has no fields.



82
83
84
# File 'lib/bindata/array.rb', line 82

def all_possible_field_names(sanitized_params)
  []
end

.sanitize_parameters(params, endian = nil) ⇒ Object

Returns a sanitized params that is of the form expected by #initialize.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/bindata/array.rb', line 63

def sanitize_parameters(params, endian = nil)
  params = params.dup

  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?(:type)
    type, el_params = params[:type]
    klass = lookup(type, endian)
    raise TypeError, "unknown type '#{type}' for #{self}" if klass.nil?
    params[:type] = [klass, SanitizedParameters.new(klass, el_params, endian)]
  end

  super(params, endian)
end

Instance Method Details

#[](*index) ⇒ Object Also known as: slice

Returns the element at index. If the element is a single_value then the value of the element is returned instead.



189
190
191
192
193
194
195
196
# File 'lib/bindata/array.rb', line 189

def [](*index)
  data = elements[*index]
  if data.respond_to?(:each)
    data.collect { |el| (el && el.single_value?) ? el.value : el }
  else
    (data && data.single_value?) ? data.value : data
  end
end

#[]=(index, value) ⇒ Object

Sets the element at index. If the element is a single_value then the value of the element is set instead.



201
202
203
204
205
206
207
# File 'lib/bindata/array.rb', line 201

def []=(index, value)
  obj = elements[index]
  unless obj.single_value?
    raise NoMethodError, "undefined method `[]=' for #{self}", caller
  end
  obj.value = value
end

#_do_read(io) ⇒ Object

Reads the values for all fields in this object from io.



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/bindata/array.rb', line 125

def _do_read(io)
  if has_param?(:initial_length)
    elements.each { |f| f.do_read(io) }
  else # :read_until
    @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

#_num_bytes(index) ⇒ Object

Returns the number of bytes it will take to write the element at index. If index, then returns the number of bytes required to write all fields.



154
155
156
157
158
159
160
# File 'lib/bindata/array.rb', line 154

def _num_bytes(index)
  if index.nil?
    elements.inject(0) { |sum, f| sum + f.num_bytes }
  else
    elements[index].num_bytes
  end
end

#_write(io) ⇒ Object

Writes the values for all fields in this object to io.



147
148
149
# File 'lib/bindata/array.rb', line 147

def _write(io)
  elements.each { |f| f.write(io) }
end

#append(value = nil) ⇒ Object

Appends a new element to the end of the array. If the array contains single_values then the value may be provided to the call. Returns the appended object, or value in the case of single_values.



181
182
183
184
185
# File 'lib/bindata/array.rb', line 181

def append(value = nil)
  append_new_element
  self[-1] = value unless value.nil?
  self.last
end

#clear(index = nil) ⇒ Object

Clears the element at position index. If index is not given, then the internal state of the array is reset to that of a newly created object.



101
102
103
104
105
106
107
108
109
# File 'lib/bindata/array.rb', line 101

def clear(index = nil)
  if @element_list.nil?
    # do nothing as the array is already clear
  elsif index.nil?
    @element_list = nil
  else
    elements[index].clear
  end
end

#clear?(index = nil) ⇒ Boolean

Returns if the element at position index is clear?. If index is not given, then returns whether all fields are clear.

Returns:

  • (Boolean)


113
114
115
116
117
118
119
120
121
122
# File 'lib/bindata/array.rb', line 113

def clear?(index = nil)
  if @element_list.nil?
    true
  elsif index.nil?
    elements.each { |f| return false if not f.clear? }
    true
  else
    elements[index].clear?
  end
end

#done_readObject

To be called after calling #do_read.



142
143
144
# File 'lib/bindata/array.rb', line 142

def done_read
  elements.each { |f| f.done_read }
end

#eachObject

Iterate over each element in the array. If the elements are single_values then the values of the elements are iterated instead.



211
212
213
214
215
# File 'lib/bindata/array.rb', line 211

def each
  elements.each do |el|
    yield(el.single_value? ? el.value : el)
  end
end

#empty?Boolean

Returns true if self array contains no elements.

Returns:

  • (Boolean)


247
248
249
# File 'lib/bindata/array.rb', line 247

def empty?
  length.zero?
end

#field_namesObject

An array has no fields.



174
175
176
# File 'lib/bindata/array.rb', line 174

def field_names
  []
end

#first(n = nil) ⇒ Object

Returns the first element, or the first n elements, of the array. If the array is empty, the first form returns nil, and the second form returns an empty array.



220
221
222
223
224
225
226
# File 'lib/bindata/array.rb', line 220

def first(n = nil)
  if n.nil?
    self[0]
  else
    self[0, n]
  end
end

#last(n = nil) ⇒ Object

Returns the last element, or the last n elements, of the array. If the array is empty, the first form returns nil, and the second form returns an empty array.



231
232
233
234
235
236
237
238
# File 'lib/bindata/array.rb', line 231

def last(n = nil)
  if n.nil?
    self[-1]
  else
    n = length if n > length
    self[-n, n]
  end
end

#lengthObject Also known as: size

The number of elements in this array.



241
242
243
# File 'lib/bindata/array.rb', line 241

def length
  elements.length
end

#single_value?Boolean

Returns whether this data object contains a single value. Single value data objects respond to #value and #value=.

Returns:

  • (Boolean)


169
170
171
# File 'lib/bindata/array.rb', line 169

def single_value?
  return false
end

#snapshotObject

Returns a snapshot of the data in this array.



163
164
165
# File 'lib/bindata/array.rb', line 163

def snapshot
  elements.collect { |e| e.snapshot }
end

#to_aryObject

Allow this object to be used in array context.



252
253
254
# File 'lib/bindata/array.rb', line 252

def to_ary
  snapshot
end