Class: BitStruct

Inherits:
String
  • Object
show all
Defined in:
lib/bit-struct/bit-struct.rb,
lib/bit-struct/yaml.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.13.6"
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



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

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).



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/bit-struct/bit-struct.rb', line 150

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.



219
220
221
# File 'lib/bit-struct/bit-struct.rb', line 219

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:



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

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.



210
211
212
213
214
215
216
# File 'lib/bit-struct/bit-struct.rb', line 210

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.



278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
# File 'lib/bit-struct/bit-struct.rb', line 278

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.



271
272
273
# File 'lib/bit-struct/bit-struct.rb', line 271

def describe_format
  DESCRIBE_FORMAT
end

.field_by_name(name) ⇒ Object



232
233
234
235
236
237
238
239
240
# File 'lib/bit-struct/bit-struct.rb', line 232

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.



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

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



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

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:



424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
# File 'lib/bit-struct/bit-struct.rb', line 424

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.



457
458
459
# File 'lib/bit-struct/bit-struct.rb', line 457

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



318
319
320
321
# File 'lib/bit-struct/bit-struct.rb', line 318

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.



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

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.)



448
449
450
451
452
# File 'lib/bit-struct/bit-struct.rb', line 448

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:



194
195
196
197
198
199
200
201
202
# File 'lib/bit-struct/bit-struct.rb', line 194

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.



547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
# File 'lib/bit-struct/bit-struct.rb', line 547

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.



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

def self.rest_field; @rest_field; end

.round_byte_lengthObject

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



224
225
226
# File 'lib/bit-struct/bit-struct.rb', line 224

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:



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/bit-struct/yaml.rb', line 53

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



396
397
398
399
400
401
402
# File 'lib/bit-struct/bit-struct.rb', line 396

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

#[]=(*args) ⇒ Object



404
405
406
407
408
409
410
# File 'lib/bit-struct/bit-struct.rb', line 404

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

#field_by_name(name) ⇒ Object

Return the field with the given name.



254
255
256
# File 'lib/bit-struct/bit-struct.rb', line 254

def field_by_name name
  self.class.field_by_name name
end

#fieldsObject

Return the list of fields for this class.



244
245
246
# File 'lib/bit-struct/bit-struct.rb', line 244

def fields
  self.class.fields
end

#inspect(opts = DEFAULT_INSPECT_OPTS) ⇒ Object

A standard inspect method which does not add newlines.



490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
# File 'lib/bit-struct/bit-struct.rb', line 490

def inspect(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

#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.)



519
520
521
# File 'lib/bit-struct/bit-struct.rb', line 519

def inspect_detailed
  inspect(DETAILED_INSPECT_OPTS)
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.



249
250
251
# File 'lib/bit-struct/bit-struct.rb', line 249

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.



382
383
384
385
386
387
388
389
390
391
392
# File 'lib/bit-struct/bit-struct.rb', line 382

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.



366
367
368
369
370
371
372
373
374
375
376
377
378
# File 'lib/bit-struct/bit-struct.rb', line 366

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:



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

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