Class: BitStruct

Inherits:
String
  • Object
show all
Defined in:
lib/bit-struct/bit-struct.rb,
lib/bit-struct/yaml.rb,
lib/bit-struct/field.rb,
lib/bit-struct/fields.rb,
lib/bit-struct/pad-field.rb,
lib/bit-struct/char-field.rb,
lib/bit-struct/text-field.rb,
lib/bit-struct/float-field.rb,
lib/bit-struct/octet-field.rb,
lib/bit-struct/nested-field.rb,
lib/bit-struct/signed-field.rb,
lib/bit-struct/vector-field.rb,
lib/bit-struct/unsigned-field.rb,
lib/bit-struct/hex-octet-field.rb

Overview

Class for packed binary data, with defined bitfields and accessors for them. See intro.txt for an overview.

Data after the end of the defined fields is accessible using the rest declaration. See examples/ip.rb. Nested fields can be declared using nest. See examples/nest.rb.

Note that all string methods are still available: length, grep, etc. The String#replace method is useful.

Defined Under Namespace

Classes: CharField, ClosedClassError, Field, FieldNameError, FloatField, HexOctetField, NestedField, OctetField, PadField, SignedField, TextField, UnsignedField, Vector, VectorField

Constant Summary collapse

VERSION =
"0.16"
NULL_FIELD =
Field.new(0, 0, :null, :display_name => "null field")
DESCRIBE_FORMAT =

Default format for describe. Fields are byte, type, name, size, and description.

"%8s: %-12s %-14s[%4s] %s"
DEFAULT_TO_H_OPTS =
{
  :convert_keys   => :to_sym,
  :include_rest   => true
}
DEFAULT_INSPECT_OPTS =

:section: inspection methods


{
  :format           => "#<%s %s>",
  :field_format     => "%s=%s",
  :separator        => ", ",
  :field_name_meth  => :name,
  :include_rest     => true,
  :brackets         => ["[", "]"],
  :include_class    => true,
  :simple_format    => "<%s>"
}
DETAILED_INSPECT_OPTS =
{
  :format           => "%s:\n%s",
  :field_format     => "%30s = %s",
  :separator        => "\n",
  :field_name_meth  => :display_name,
  :include_rest     => true,
  :brackets         => [nil, "\n"],
  :include_class    => true,
  :simple_format    => "\n%s"
}

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(value = nil) {|_self| ... } ⇒ BitStruct

Initialize the string with the given string or bitstruct, or with a hash of field=>value pairs, or with the defaults for the BitStruct subclass, or with an IO or other object with a #read method. Fields can be strings or symbols. Finally, if a block is given, yield the instance for modification using accessors.

Yields:

  • (_self)

Yield Parameters:

  • _self (BitStruct)

    the object that the method was called on



245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/bit-struct/bit-struct.rb', line 245

def initialize(value = nil)   # :yields: instance
  self << self.class.initial_value

  case value
  when Hash
    value.each do |k, v|
      send "#{k}=", v
    end

  when nil

  else
    if value.respond_to?(:read)
      value = value.read(self.class.round_byte_length)
    end

    self[0, value.length] = value
  end

  self.class.closed!
  yield self if block_given?
end

Class Method Details

.add_field(name, length, opts = {}) ⇒ Object

Add a field to the BitStruct (usually, this is only used internally).



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/bit-struct/bit-struct.rb', line 61

def add_field(name, length, opts = {})
  round_byte_length ## just to make sure this has been calculated
  ## before adding anything

  name = name.to_sym

  if @closed
    raise ClosedClassError, "Cannot add field #{name}: " +
      "The definition of the #{self.inspect} BitStruct class is closed."
  end

  if fields.find {|f|f.name == name}
    raise FieldNameError, "Field #{name} is already defined as a field."
  end

  if instance_methods(true).find {|m| m == name}
    if opts[:allow_method_conflict] || opts["allow_method_conflict"]
      warn "Field #{name} is already defined as a method."
    else
      raise FieldNameError,"Field #{name} is already defined as a method."
    end
  end

  field_class = opts[:field_class]

  prev = fields[-1] || NULL_FIELD
  offset = prev.offset + prev.length
  field = field_class.new(offset, length, name, opts)
  field.add_accessors_to(self)
  fields << field
  own_fields << field
  @bit_length += field.length
  @round_byte_length = (bit_length/8.0).ceil

  if @initial_value
    diff = @round_byte_length - @initial_value.length
    if diff > 0
      @initial_value << "\0" * diff
    end
  end

  field
end

.bit_lengthObject

Length, in bits, of this object.



130
131
132
# File 'lib/bit-struct/bit-struct.rb', line 130

def bit_length
  @bit_length ||= fields.inject(0) {|a, f| a + f.length}
end

.char(name, length, *rest) ⇒ Object Also known as: string

Define a char string field in the current subclass of BitStruct, with the given name and length (in bits). Trailing nulls are considered part of the string.

If a class is provided, use it for the Field class. If a string is provided, use it for the display_name. If a hash is provided, use it for options.

Note that the accessors have COPY semantics, not reference.



13
14
15
16
# File 'lib/bit-struct/fields.rb', line 13

def char(name, length, *rest)
  opts = parse_options(rest, name, CharField)
  add_field(name, length, opts)
end

.closed!Object

:nodoc:



139
140
141
# File 'lib/bit-struct/bit-struct.rb', line 139

def closed! # :nodoc:
  @closed = true
end

.default_options(h = nil) ⇒ Object

Get or set the hash of default options for the class, which apply to all fields. Changes take effect immediately, so can be used alternatingly with blocks of field declarations. If h is provided, update the default options with that hash. Default options are inherited.

This is especially useful with the :endian => val option.



121
122
123
124
125
126
127
# File 'lib/bit-struct/bit-struct.rb', line 121

def default_options h = nil
  @default_options ||= superclass.default_options.dup
  if h
    @default_options.merge! h
  end
  @default_options
end

.describe(fmt = nil, opts = {}) ⇒ Object

Textually describe the fields of this class of BitStructs. Returns a printable table (array of line strings), based on fmt, which defaults to #describe_format, which defaults to DESCRIBE_FORMAT.



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/bit-struct/bit-struct.rb', line 189

def describe(fmt = nil, opts = {})
  if fmt.kind_of? Hash
    opts = fmt; fmt = nil
  end

  if block_given?
    fields.each do |field|
      field.describe(opts) do |desc|
        yield desc
      end
    end
    nil

  else
    fmt ||= describe_format

    result = []

    unless opts[:omit_header]
      result << fmt % ["byte", "type", "name", "size", "description"]
      result << "-"*70
    end

    fields.each do |field|
      field.describe(opts) do |desc|
        result << fmt % desc
      end
    end

    unless opts[:omit_footer]
      result << @note if @note
    end

    result
  end
end

.describe_formatObject

Can be overridden to use a different format.



182
183
184
# File 'lib/bit-struct/bit-struct.rb', line 182

def describe_format
  DESCRIBE_FORMAT
end

.field_by_name(name) ⇒ Object



143
144
145
146
147
148
149
150
151
# File 'lib/bit-struct/bit-struct.rb', line 143

def field_by_name name
  @field_by_name ||= {}
  field = @field_by_name[name]
  unless field
    field = fields.find {|f| f.name == name}
    @field_by_name[name] = field if field
  end
  field
end

.fieldsObject

Return the list of fields for this class.



50
51
52
# File 'lib/bit-struct/bit-struct.rb', line 50

def fields
  @fields ||= self == BitStruct ? [] : superclass.fields.dup
end

.float(name, length, *rest) ⇒ Object

Define a floating point field in the current subclass of BitStruct, with the given name and length (in bits).

If a class is provided, use it for the Field class. If a string is provided, use it for the display_name. If a hash is provided, use it for options.

The :endian => :native option overrides the default of :network byte ordering, in favor of native byte ordering. Also permitted are :big (same as :network) and :little.



32
33
34
35
# File 'lib/bit-struct/fields.rb', line 32

def float name, length, *rest
  opts = parse_options(rest, name, FloatField)
  add_field(name, length, opts)
end

.hex_octets(name, length, *rest) ⇒ Object

Define an octet string field in the current subclass of BitStruct, with the given name and length (in bits). Trailing nulls are not considered part of the string. The field is accessed using period-separated hex digits.

If a class is provided, use it for the Field class. If a string is provided, use it for the display_name. If a hash is provided, use it for options.



47
48
49
50
# File 'lib/bit-struct/fields.rb', line 47

def hex_octets(name, length, *rest)
  opts = parse_options(rest, name, HexOctetField)
  add_field(name, length, opts)
end

.inherited(cl) ⇒ Object



33
34
35
36
37
38
39
40
# File 'lib/bit-struct/bit-struct.rb', line 33

def inherited cl
  cl.instance_eval do
    @initial_value = nil
    @closed = nil
    @rest_field = nil
    @note = nil
  end
end

.initial_value {|@initial_value| ... } ⇒ Object

The unique “prototype” object from which new instances are copied. The fields of this instance can be modified in the class definition to set default values for the fields in that class. (Otherwise, defaults defined by the fields themselves are used.) A copy of this object is inherited in subclasses, which they may override using defaults and by writing to the initial_value object itself.

If called with a block, yield the initial value object before returning it. Useful for customization within a class definition.

Yields:



334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
# File 'lib/bit-struct/bit-struct.rb', line 334

def initial_value   # :yields: the initial value
  unless @initial_value
    iv = defined?(superclass.initial_value) ?
      superclass.initial_value.dup : ""
    if iv.length < round_byte_length
      iv << "\0" * (round_byte_length - iv.length)
    end

    @initial_value = "" # Serves as initval while the real initval is inited
    @initial_value = new(iv)
    @closed = false # only creating the first _real_ instance closes.

    fields.each do |field|
      @initial_value.send("#{field.name}=", field.default) if field.default
    end
  end
  yield @initial_value if block_given?
  @initial_value
end

.join(*structs) ⇒ Object

Join the given structs (array or multiple args) as a string. Actually, the inherited String#+ instance method is the same, as is using Array#join.



367
368
369
# File 'lib/bit-struct/bit-struct.rb', line 367

def join(*structs)
  structs.flatten.map {|struct| struct.to_s}.join("")
end

.nest(name, *rest, &block) ⇒ Object Also known as: struct

Define a nested field in the current subclass of BitStruct, with the given name and nested_class. Length is determined from nested_class.

If a class is provided, use it for the Field class (i.e. <=NestedField). If a string is provided, use it for the display_name. If a hash is provided, use it for options.

For example:

class Sub < BitStruct
  unsigned :x,    8
end

class A < BitStruct
  nest    :n,  Sub
end

a = A.new

p a  # ==> #<A n=#<Sub x=0>>

If a block is given, use it to define the nested fields. For example, the following is equivalent to the above example:

class A < BitStruct
  nest :n do
    unsigned :x, 8
  end
end

WARNING: the accessors have COPY semantics, not reference. When you call a reader method to get the nested structure, you get a copy of that data. Expressed in terms of the examples above:

# This fails to set x in a.
a.n.x = 3
p a  # ==> #<A n=#<Sub x=0>>

# This works
n = a.n
n.x = 3
a.n = n
p a  # ==> #<A n=#<Sub x=3>>


98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/bit-struct/fields.rb', line 98

def nest(name, *rest, &block)
  nested_class = rest.grep(Class).find {|cl| cl <= BitStruct}
  rest.delete nested_class
  opts = parse_options(rest, name, NestedField)
  nested_class = opts[:nested_class] ||= nested_class

  unless (block and not nested_class) or (nested_class and not block)
    raise ArgumentError,
      "nested field must have either a nested_class option or a block," +
      " but not both"
  end

  unless nested_class
    nested_class = Class.new(BitStruct)
    nested_class.class_eval(&block)
  end

  opts[:default] ||= nested_class.initial_value.dup
  opts[:nested_class] = nested_class
  field = add_field(name, nested_class.bit_length, opts)
  field
end

.note(*str) ⇒ Object

Subclasses can use this to append a string (or several) to the #describe output. Notes are not cumulative with inheritance. When used with no arguments simply returns the note string



229
230
231
232
# File 'lib/bit-struct/bit-struct.rb', line 229

def note(*str)
  @note = str unless str.empty?
  @note
end

.octets(name, length, *rest) ⇒ Object

Define an octet string field in the current subclass of BitStruct, with the given name and length (in bits). Trailing nulls are not considered part of the string. The field is accessed using period-separated decimal digits.

If a class is provided, use it for the Field class. If a string is provided, use it for the display_name. If a hash is provided, use it for options.



132
133
134
135
# File 'lib/bit-struct/fields.rb', line 132

def octets(name, length, *rest)
  opts = parse_options(rest, name, OctetField)
  add_field(name, length, opts)
end

.own_fieldsObject

Return the list of fields defined by this class, not inherited from the superclass.



56
57
58
# File 'lib/bit-struct/bit-struct.rb', line 56

def own_fields
  @own_fields ||= []
end

.pad(name, length, *rest) ⇒ Object Also known as: padding

Define a padding field in the current subclass of BitStruct, with the given name and length (in bits).

If a class is provided, use it for the Field class. If a string is provided, use it for the display_name. If a hash is provided, use it for options.



145
146
147
148
# File 'lib/bit-struct/fields.rb', line 145

def pad(name, length, *rest)
  opts = parse_options(rest, name, PadField)
  add_field(name, length, opts)
end

.parse(data, *classes) ⇒ Object

Take data (a string or BitStruct) and parse it into instances of the classes, returning them in an array. The classes can be given as an array or a separate arguments. (For parsing a string into a single BitStruct instance, just use the #new method with the string as an arg.)



358
359
360
361
362
# File 'lib/bit-struct/bit-struct.rb', line 358

def parse(data, *classes)
  classes.flatten.map do |c|
    c.new(data.slice!(0...c.round_byte_length))
  end
end

.parse_options(ary, default_name, default_field_class) ⇒ Object

:nodoc:



105
106
107
108
109
110
111
112
113
# File 'lib/bit-struct/bit-struct.rb', line 105

def parse_options(ary, default_name, default_field_class) # :nodoc:
  opts = ary.grep(Hash).first || {}
  opts = default_options.merge(opts)

  opts[:display_name]  = ary.grep(String).first || default_name
  opts[:field_class]   = ary.grep(Class).first || default_field_class

  opts
end

.rest(name, *ary) ⇒ Object

Define accessors for a variable length substring from the end of the defined fields to the end of the BitStruct. The rest may behave as a String or as some other String or BitStruct subclass.

This does not add a field, which is useful because a superclass can have a rest method which accesses subclass data. In particular, #rest does not affect the #round_byte_length class method. Of course, any data in rest does add to the #length of the BitStruct, calculated as a string. Also, rest is not inherited.

The ary argument(s) work as follows:

If a class is provided, use it for the Field class (String by default). If a string is provided, use it for the display_name (name by default). If a hash is provided, use it for options.

Warning: the rest reader method returns a copy of the field, so accessors on that returned value do not affect the original rest field.



459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
# File 'lib/bit-struct/bit-struct.rb', line 459

def self.rest(name, *ary)
  if @rest_field
    raise ArgumentError, "Duplicate rest field: #{name.inspect}."
  end

  opts = parse_options(ary, name, String)
  offset = round_byte_length
  byte_range = offset..-1
  class_eval do
    field_class = opts[:field_class]
    define_method name do ||
      field_class.new(self[byte_range])
    end

    define_method "#{name}=" do |val|
      self[byte_range] = val
    end

    @rest_field = Field.new(offset, -1, name, {
      :display_name => opts[:display_name],
      :rest_class => field_class
    })
  end
end

.rest_fieldObject

Not included with the other fields, but accessible separately.



485
# File 'lib/bit-struct/bit-struct.rb', line 485

def self.rest_field; @rest_field; end

.round_byte_lengthObject

Length, in bytes (rounded up), of this object.



135
136
137
# File 'lib/bit-struct/bit-struct.rb', line 135

def round_byte_length
  @round_byte_length ||= (bit_length/8.0).ceil
end

.signed(name, length, *rest) ⇒ Object

Define a signed integer field in the current subclass of BitStruct, with the given name and length (in bits).

If a class is provided, use it for the Field class. If a string is provided, use it for the display_name. If a hash is provided, use it for options.

SignedField adds the :fixed => divisor option, which specifies that the internally stored value is interpreted as a fixed point real number with the specified divisor.

The :endian => :native option overrides the default of :network byte ordering, in favor of native byte ordering. Also permitted are :big (same as :network) and :little.



168
169
170
171
# File 'lib/bit-struct/fields.rb', line 168

def signed name, length, *rest
  opts = parse_options(rest, name, SignedField)
  add_field(name, length, opts)
end

.text(name, length, *rest) ⇒ Object

Define a printable text string field in the current subclass of BitStruct, with the given name and length (in bits). Trailing nulls are not considered part of the string.

If a class is provided, use it for the Field class. If a string is provided, use it for the display_name. If a hash is provided, use it for options.

Note that the accessors have COPY semantics, not reference.



184
185
186
187
# File 'lib/bit-struct/fields.rb', line 184

def text(name, length, *rest)
  opts = parse_options(rest, name, TextField)
  add_field(name, length, opts)
end

.unsigned(name, length, *rest) ⇒ Object

Define a unsigned integer field in the current subclass of BitStruct, with the given name and length (in bits).

If a class is provided, use it for the Field class. If a string is provided, use it for the display_name. If a hash is provided, use it for options.

UnsignedField adds the :fixed => divisor option, which specifies that the internally stored value is interpreted as a fixed point real number with the specified divisor.

The :endian => :native option overrides the default of :network byte ordering, in favor of native byte ordering. Also permitted are :big (same as :network) and :little.



206
207
208
209
# File 'lib/bit-struct/fields.rb', line 206

def unsigned name, length, *rest
  opts = parse_options(rest, name, UnsignedField)
  add_field(name, length, opts)
end

.vector(name, *rest, &block) ⇒ Object

Define a vector field in the current subclass of BitStruct, with the given name.

If a class is provided, use it for the Vector class, otherwise the block must define the entry fields. The two forms looks like this:

class Vec < BitStruct::Vector
  # these declarations apply to *each* entry in the vector:
  unsigned :x,  16
  signed   :y,  32
end

class Packet < BitStruct
  # Using the Vec class defined above
  vector  :v, Vec, "a vector", :length => 5

  # equivalently, using an anonymous subclass of BitStruct::Vector
  vector :v2, "a vector", :length => 5 do
    unsigned :x,  16
    signed   :y,  32
  end
end

If a string is provided, use it for the display_name. If a hash is provided, use it for options. If a number is provided, use it for length (equivalent to using the :length option).

WARNING: the accessors have COPY semantics, not reference. When you call a reader method to get the vector structure, you get a copy of that data.

For example, to modify the numeric fields in a Packet as defined above:

pkt = Packet.new
  vec = pkt.v
    entry = vec[2]
      entry.x = 123
      entry.y = -456
    vec[2] = entry
  pkt.v = vec


254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/bit-struct/fields.rb', line 254

def vector(name, *rest, &block)
  opts = parse_options(rest, name, nil)
  cl = opts[:field_class]
  opts[:field_class] = VectorField

  unless (block and not cl) or (cl and not block)
    raise ArgumentError,
      "vector must have either a class or a block, but not both"
  end

  case
  when cl == nil
    vector_class = Class.new(BitStruct::Vector)
    vector_class.class_eval(&block)

  when cl < BitStruct
    vector_class = Class.new(BitStruct::Vector)
    vector_class.struct_class cl

  when cl < BitStruct::Vector
    vector_class = cl

  else raise ArgumentError, "Bad vector class: #{cl.inspect}"
  end

  vector_class.default_options default_options

  length = opts[:length] || rest.grep(Integer).first
    ## what about :length => :lenfield
  unless length
    raise ArgumentError,
      "Must provide length as argument N or as option :length => N"
  end

  opts[:default] ||= vector_class.new(length) ## nil if variable length
  opts[:vector_class] = vector_class

  bit_length = vector_class.struct_class.round_byte_length * 8 * length

  field = add_field(name, bit_length, opts)
  field
end

.yaml_new(klass, tag, val) ⇒ Object

:nodoc:



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/bit-struct/yaml.rb', line 72

def self.yaml_new( klass, tag, val ) # :nodoc:
  unless Hash === val
    raise YAML::TypeError, "Invalid BitStruct: " + val.inspect
  end

  _bitstruct_name, bitstruct_type = YAML.read_type_class( tag, BitStruct )

  st = bitstruct_type.new

  val.each do |k,v|
    st.send( "#{k}=", v )
  end

  st
end

Instance Method Details

#[](*args) ⇒ Object



306
307
308
309
310
311
312
# File 'lib/bit-struct/bit-struct.rb', line 306

def [](*args)
  if args.size == 1 and args[0].kind_of?(Integer)
    super.ord
  else
    super
  end
end

#[]=(*args) ⇒ Object



314
315
316
317
318
319
320
# File 'lib/bit-struct/bit-struct.rb', line 314

def []=(*args)
  if args.size == 2 and (i=args[0]).kind_of?(Integer)
    super(i, args[1].chr)
  else
    super
  end
end

#encode_with(coder) ⇒ Object



31
32
33
34
35
36
37
38
39
40
# File 'lib/bit-struct/yaml.rb', line 31

def encode_with coder
  yaml_fields = fields.select {|field| field.inspectable?}
  props = yaml_fields.map {|f| f.name.to_s}
  if (rest_field = self.class.rest_field)
    props << rest_field.name.to_s
  end
  props.each do |prop|
    coder[prop] = send(prop)
  end
end

#field_by_name(name) ⇒ Object

Return the field with the given name.



165
166
167
# File 'lib/bit-struct/bit-struct.rb', line 165

def field_by_name name
  self.class.field_by_name name
end

#fieldsObject

Return the list of fields for this class.



155
156
157
# File 'lib/bit-struct/bit-struct.rb', line 155

def fields
  self.class.fields
end

#init_with(coder) ⇒ Object



42
43
44
45
46
47
# File 'lib/bit-struct/yaml.rb', line 42

def init_with coder
  self << self.class.initial_value
  coder.map.each do |k, v|
    send("#{k}=", v)
  end
end

#inspect_detailedObject

A more visually appealing inspect method that puts each field/value on a separate line. Very useful when output is scrolling by on a screen.

(This is actually a convenience method to call #inspect with the DETAILED_INSPECT_OPTS opts.)



431
432
433
# File 'lib/bit-struct/bit-struct.rb', line 431

def inspect_detailed
  inspect(DETAILED_INSPECT_OPTS)
end

#inspect_with_options(opts = DEFAULT_INSPECT_OPTS) ⇒ Object Also known as: inspect

A standard inspect method which does not add newlines.



400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
# File 'lib/bit-struct/bit-struct.rb', line 400

def inspect_with_options(opts = DEFAULT_INSPECT_OPTS)
  field_format = opts[:field_format]
  field_name_meth = opts[:field_name_meth]

  fields_for_inspect = fields.select {|field| field.inspectable?}
  if opts[:include_rest] and (rest_field = self.class.rest_field)
    fields_for_inspect << rest_field
  end

  ary = fields_for_inspect.map do |field|
    field_format %
     [field.send(field_name_meth),
      field.inspect_in_object(self, opts)]
  end

  body = ary.join(opts[:separator])

  if opts[:include_class]
    opts[:format] % [self.class, body]
  else
    opts[:simple_format] % body
  end
end

#is_complex_yaml?Boolean

:nodoc:

Returns:

  • (Boolean)


5
6
7
# File 'lib/bit-struct/yaml.rb', line 5

def is_complex_yaml? # :nodoc:
  true
end

#rest_fieldObject

Return the rest field for this class.



160
161
162
# File 'lib/bit-struct/bit-struct.rb', line 160

def rest_field
  self.class.rest_field
end

#to_a(include_rest = true) ⇒ Object

Returns an array of values of the fields of the BitStruct. By default, include the rest field.



293
294
295
296
297
298
299
300
301
302
303
# File 'lib/bit-struct/bit-struct.rb', line 293

def to_a(include_rest = true)
  ary =
    fields.map do |f|
      send(f.name)
    end

  if include_rest and (rest_field = self.class.rest_field)
    ary << send(rest_field.name)
  end
  ary
end

#to_h(opts = DEFAULT_TO_H_OPTS) ⇒ Object

Returns a hash of name=>value,… for each field. By default, include the rest field. Keys are symbols derived from field names using to_sym, unless <tt>opts<tt> is set to some other method name.



277
278
279
280
281
282
283
284
285
286
287
288
289
# File 'lib/bit-struct/bit-struct.rb', line 277

def to_h(opts = DEFAULT_TO_H_OPTS)
  converter = opts[:convert_keys] || :to_sym

  fields_for_to_h = fields
  if opts[:include_rest] and (rest_field = self.class.rest_field)
    fields_for_to_h += [rest_field]
  end

  fields_for_to_h.inject({}) do |h,f|
    h[f.name.send(converter)] = send(f.name)
    h
  end
end

#to_yaml(opts = {}) ⇒ Object

Return YAML representation of the BitStruct.



18
19
20
21
22
23
24
25
26
27
28
# File 'lib/bit-struct/yaml.rb', line 18

def to_yaml( opts = {} ) # :nodoc:
  opts[:DocType] = self.class if Hash === opts
  YAML.quick_emit(self.object_id, opts) do |out|
    out.map(to_yaml_type) do |map|
      fields.each do |field|
        fn = field.name
        map.add(fn, send(fn))
      end
    end
  end
end

#to_yaml_propertiesObject

:nodoc:



52
53
54
55
56
57
58
59
# File 'lib/bit-struct/yaml.rb', line 52

def to_yaml_properties # :nodoc:
  yaml_fields = fields.select {|field| field.inspectable?}
  props = yaml_fields.map {|f| f.name.to_s}
  if (rest_field = self.class.rest_field)
    props << rest_field.name.to_s
  end
  props
end

#to_yaml_typeObject

:nodoc:



14
15
16
# File 'lib/bit-struct/yaml.rb', line 14

def to_yaml_type # :nodoc:
  "!ruby/bitstruct:#{self.class}"
end