Class: BinData::MultiValue

Inherits:
Struct show all
Defined in:
lib/bindata/multi_value.rb

Overview

A MultiValue is a declarative wrapper around Struct.

require 'bindata'

class Tuple < BinData::MultiValue
  int8  :x
  int8  :y
  int8  :z
end

class SomeDataType < BinData::MultiValue
  hide 'a'

  int32le :a
  int16le :b
  tuple   nil
end

obj = SomeDataType.new
obj.field_names   =># ["b", "x", "y", "z"]

Parameters

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

:fields

An array specifying the fields for this struct. Each element of the array is of the form [type, name, params]. Type is a symbol representing a registered type. Name is the name of this field. Name may be nil as in the example above. Params is an optional hash of parameters to pass to this field when instantiating it.

:hide

A list of the names of fields that are to be hidden from the outside world. Hidden fields don’t appear in #snapshot or #field_names but are still accessible by name.

:endian

Either :little or :big. This specifies the default endian of any numerics in this struct, or in any nested data objects.

Class Method Summary collapse

Methods inherited from Struct

#_do_read, #_num_bytes, #_write, all_possible_field_names, #clear, #clear?, deprecated_hack, #done_read, #field_names, #find_obj_for_name, #initialize, #method_missing, #offset_of, #orig_respond_to?, #respond_to?, #single_value?, #snapshot

Methods inherited from Base

accepted_parameters, #clear, default_parameters, #do_read, #done_read, #field_names, #initialize, #inspect, lookup, mandatory_parameters, mutually_exclusive_parameters, #num_bytes, optional_parameters, #read, read, register, #single_value?, #snapshot, #to_s, #write

Constructor Details

This class inherits a constructor from BinData::Struct

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class BinData::Struct

Class Method Details

.endian(endian = nil) ⇒ Object

Returns or sets the endianess of numerics used in this stucture. Endianess is applied to the fields of this structure. Valid values are :little and :big.



56
57
58
59
60
61
62
63
64
# File 'lib/bindata/multi_value.rb', line 56

def endian(endian = nil)
  @endian ||= nil
  if [:little, :big].include?(endian)
    @endian = endian
  elsif endian != nil
    raise ArgumentError, "unknown value for endian '#{endian}'"
  end
  @endian
end

.fieldsObject

Returns all stored fields. Should only be called by #sanitize_parameters



79
80
81
# File 'lib/bindata/multi_value.rb', line 79

def fields
  @fields || []
end

.hide(*args) ⇒ Object

Returns the names of any hidden fields in this struct. Any given args are appended to the hidden list.



68
69
70
71
72
73
74
75
76
# File 'lib/bindata/multi_value.rb', line 68

def hide(*args)
  # note that fields are stored in an instance variable not a class var
  @hide ||= []
  args.each do |name|
    next if name.nil?
    @hide << name.to_s
  end
  @hide
end

.inherited(subclass) ⇒ Object

Register the names of all subclasses of this class.



49
50
51
# File 'lib/bindata/multi_value.rb', line 49

def inherited(subclass) #:nodoc:
  register(subclass.name, subclass)
end

.method_missing(symbol, *args) ⇒ Object

Used to define fields for this structure.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/bindata/multi_value.rb', line 84

def method_missing(symbol, *args)
  name, params = args

  type = symbol
  name = (name.nil? or name == "") ? nil : name.to_s
  params ||= {}

  # note that fields are stored in an instance variable not a class var
  @fields ||= []

  # check that type is known
  if lookup(type, endian).nil?
    raise TypeError, "unknown type '#{type}' for #{self}", caller
  end

  # check that name is okay
  if name != nil
    # check for duplicate names
    @fields.each do |t, n, p|
      if n == name
        raise SyntaxError, "duplicate field '#{name}' in #{self}", caller
      end
    end

    # check that name doesn't shadow an existing method
    if self.instance_methods.include?(name)
      raise NameError.new("", name),
            "field '#{name}' shadows an existing method", caller
    end

    # check that name isn't reserved
    if ::Hash.instance_methods.include?(name)
      raise NameError.new("", name),
            "field '#{name}' is a reserved name", caller
    end
  end

  # remember this field.  These fields will be recalled upon creating
  # an instance of this class
  @fields.push([type, name, params])
end

.sanitize_parameters(params, endian = nil) ⇒ Object

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



128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/bindata/multi_value.rb', line 128

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

  # possibly override endian
  endian = params[:endian] || self.endian || endian
  unless endian.nil?
    params[:endian] = endian
  end

  params[:fields] = params[:fields] || self.fields
  params[:hide] = params[:hide] || self.hide

  super(params, endian)
end