bit-struct 0.13.5 → 0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/History.txt +22 -1
  3. data/LICENSE +56 -0
  4. data/{README.txt → README.md} +94 -92
  5. data/Rakefile +56 -30
  6. data/examples/field-ripper.rb +1 -1
  7. data/examples/ip.rb +6 -6
  8. data/examples/longlong.rb +2 -2
  9. data/examples/md.rb +1 -1
  10. data/examples/modular-def.rb +2 -2
  11. data/examples/native.rb +3 -3
  12. data/examples/ping.rb +1 -1
  13. data/examples/raw.rb +1 -1
  14. data/examples/switch-endian.rb +2 -2
  15. data/examples/vector.rb +2 -2
  16. data/lib/bit-struct.rb +0 -11
  17. data/lib/bit-struct/bit-struct.rb +61 -143
  18. data/lib/bit-struct/char-field.rb +3 -3
  19. data/lib/bit-struct/field.rb +94 -0
  20. data/lib/bit-struct/fields.rb +13 -13
  21. data/lib/bit-struct/float-field.rb +4 -4
  22. data/lib/bit-struct/hex-octet-field.rb +3 -3
  23. data/lib/bit-struct/nested-field.rb +8 -8
  24. data/lib/bit-struct/octet-field.rb +4 -4
  25. data/lib/bit-struct/signed-field.rb +23 -28
  26. data/lib/bit-struct/text-field.rb +2 -2
  27. data/lib/bit-struct/unsigned-field.rb +24 -27
  28. data/lib/bit-struct/vector-field.rb +7 -7
  29. data/lib/bit-struct/vector.rb +24 -22
  30. data/lib/bit-struct/yaml.rb +22 -3
  31. data/test/test-endian.rb +5 -5
  32. data/test/test-vector.rb +6 -6
  33. data/test/test.rb +71 -46
  34. metadata +43 -69
  35. data/.gitignore +0 -3
  36. data/TODO +0 -20
  37. data/tasks/ann.rake +0 -80
  38. data/tasks/bones.rake +0 -20
  39. data/tasks/gem.rake +0 -201
  40. data/tasks/git.rake +0 -40
  41. data/tasks/notes.rake +0 -27
  42. data/tasks/post_load.rake +0 -34
  43. data/tasks/rdoc.rake +0 -51
  44. data/tasks/rubyforge.rake +0 -55
  45. data/tasks/setup.rb +0 -292
  46. data/tasks/spec.rake +0 -54
  47. data/tasks/svn.rake +0 -47
  48. data/tasks/test.rake +0 -40
  49. data/tasks/zentest.rake +0 -36
data/examples/longlong.rb CHANGED
@@ -10,8 +10,8 @@ pkt = MyPacket.new
10
10
  pkt.x = 59843759843759843
11
11
  pkt.y = 59843759843759843
12
12
 
13
- p pkt.x # 59843759843759843
14
- p pkt.y # 59843759843759843
13
+ p pkt.x # 59843759843759843
14
+ p pkt.y # 59843759843759843
15
15
 
16
16
  p pkt
17
17
  # #<MyPacket x=59843759843759843, y=59843759843759843>
data/examples/md.rb CHANGED
@@ -18,6 +18,6 @@ md = MD.new
18
18
  row.col = cols
19
19
  rows[2] = row
20
20
  md.row = rows
21
-
21
+
22
22
  p md
23
23
  p md.row[2].col[7].x
@@ -6,7 +6,7 @@ module ModuleMethodSaver
6
6
  @saved ||= []
7
7
  @saved << [meth, args, block]
8
8
  end
9
-
9
+
10
10
  def included(m)
11
11
  if @saved
12
12
  @saved.each do |meth, args, block|
@@ -21,7 +21,7 @@ require 'bit-struct'
21
21
 
22
22
  module M
23
23
  extend ModuleMethodSaver
24
-
24
+
25
25
  unsigned :x, 13
26
26
  signed :y, 7
27
27
  end
data/examples/native.rb CHANGED
@@ -6,15 +6,15 @@ class NativeNumbers < BitStruct
6
6
  unsigned :x1, 13, :endian => :native
7
7
  unsigned :x2, 2, :endian => :native
8
8
  unsigned :x3, 32, :endian => :native
9
-
9
+
10
10
  float :f1, 32, :endian => :native
11
11
  float :f2, 64, :endian => :native
12
12
  float :f3, 32
13
13
  float :f4, 64
14
-
14
+
15
15
  default_options :endian => :native
16
16
  # affects fields defined after this and in subclasses
17
-
17
+
18
18
  unsigned :y1, 32
19
19
 
20
20
  end
data/examples/ping.rb CHANGED
@@ -61,7 +61,7 @@ addr = Socket.pack_sockaddr_in(1024, "localhost")
61
61
  b.ip_len = b.length
62
62
  b.ip_sum = 0 ## ?
63
63
  end
64
-
64
+
65
65
  out = "-"*80,
66
66
  "packet sent:",
67
67
  icmp.inspect_detailed,
data/examples/raw.rb CHANGED
@@ -50,7 +50,7 @@ addr = Socket.pack_sockaddr_in(1024, "localhost")
50
50
  b.ip_len = b.length
51
51
  b.ip_sum = 0 # linux will calculate this for us (QNX won't?)
52
52
  end
53
-
53
+
54
54
  out = "-"*80,
55
55
  "packet sent:",
56
56
  ip.inspect_detailed,
@@ -3,7 +3,7 @@ module ModuleMethodSaver
3
3
  @saved ||= []
4
4
  @saved << [meth, args, block]
5
5
  end
6
-
6
+
7
7
  def included(m)
8
8
  if @saved
9
9
  @saved.each do |meth, args, block|
@@ -18,7 +18,7 @@ require 'bit-struct'
18
18
 
19
19
  module MyFields
20
20
  extend ModuleMethodSaver
21
-
21
+
22
22
  unsigned :x, 16
23
23
  end
24
24
 
data/examples/vector.rb CHANGED
@@ -5,7 +5,7 @@ class Vec < BitStruct::Vector
5
5
  # these declarations apply to *each* entry in the vector:
6
6
  unsigned :x, 16
7
7
  signed :y, 32
8
-
8
+
9
9
  Entry = struct_class # Give it a name, just for inspect to look nice
10
10
  end
11
11
 
@@ -72,7 +72,7 @@ puts
72
72
  # Example 4: vector field in a bitstruct
73
73
  class Packet < BitStruct
74
74
  unsigned :stuff, 32, "whatever"
75
-
75
+
76
76
  # Using the Vec class defined above
77
77
  vector :v, Vec, "a vector", 5
78
78
 
data/lib/bit-struct.rb CHANGED
@@ -1,14 +1,3 @@
1
- # A Convenience to load all field classes and yaml handling.
2
-
3
- if "a"[0].kind_of? Fixnum
4
- unless Fixnum.methods.include? :ord
5
- class Fixnum
6
- def ord; self; end
7
- end
8
- end
9
- end
10
-
11
1
  require 'bit-struct/bit-struct'
12
2
  require 'bit-struct/fields'
13
3
  require 'bit-struct/yaml'
14
-
@@ -9,100 +9,11 @@
9
9
  # The String#replace method is useful.
10
10
  #
11
11
  class BitStruct < String
12
- VERSION = "0.13.5"
13
-
14
- class Field
15
- # Offset of field in bits.
16
- attr_reader :offset
17
-
18
- # Length of field in bits.
19
- attr_reader :length
20
- alias size length
21
-
22
- # Name of field (used for its accessors).
23
- attr_reader :name
24
-
25
- # Options, such as :default (varies for each field subclass).
26
- # In general, options can be provided as strings or as symbols.
27
- attr_reader :options
28
-
29
- # Display name of field (used for printing).
30
- attr_reader :display_name
31
-
32
- # Default value.
33
- attr_reader :default
34
-
35
- # Format for printed value of field.
36
- attr_reader :format
37
-
38
- # Subclasses can override this to define a default for all fields of this
39
- # class, not just the one currently being added to a BitStruct class, a
40
- # "default default" if you will. The global default, if #default returns
41
- # nil, is to fill the field with zero. Most field classes just let this
42
- # default stand. The default can be overridden per-field when a BitStruct
43
- # class is defined.
44
- def self.default; nil; end
45
-
46
- # Used in describe.
47
- def self.class_name
48
- @class_name ||= name[/\w+$/]
49
- end
50
-
51
- # Used in describe. Can be overridden per-subclass, as in NestedField.
52
- def class_name
53
- self.class.class_name
54
- end
55
-
56
- # Yield the description of this field, as an array of 5 strings: byte
57
- # offset, type, name, size, and description. The opts hash may have:
58
- #
59
- # :expand :: if the value is true, expand complex fields
60
- #
61
- # (Subclass implementations may yield more than once for complex fields.)
62
- #
63
- def describe opts
64
- bits = size
65
- if bits > 32 and bits % 8 == 0
66
- len_str = "%dB" % (bits/8)
67
- else
68
- len_str = "%db" % bits
69
- end
70
-
71
- byte_offset = offset / 8 + (opts[:byte_offset] || 0)
12
+ VERSION = "0.17"
72
13
 
73
- yield ["@%d" % byte_offset, class_name, name, len_str, display_name]
74
- end
75
-
76
- # Options are _display_name_, _default_, and _format_ (subclasses of Field
77
- # may add other options).
78
- def initialize(offset, length, name, opts = {})
79
- @offset, @length, @name, @options =
80
- offset, length, name, opts
81
-
82
- @display_name = opts[:display_name] || opts["display_name"]
83
- @default = opts[:default] || opts["default"] || self.class.default
84
- @format = opts[:format] || opts["format"]
85
- end
86
-
87
- # Inspect the value of this field in the specified _obj_.
88
- def inspect_in_object(obj, opts)
89
- val = obj.send(name)
90
- str =
91
- begin
92
- val.inspect(opts)
93
- rescue ArgumentError # assume: "wrong number of arguments (1 for 0)"
94
- val.inspect
95
- end
96
- (f=@format) ? (f % str) : str
97
- end
98
-
99
- # Normally, all fields show up in inspect, but some, such as padding,
100
- # should not.
101
- def inspectable?; true; end
102
- end
103
-
14
+ require 'bit-struct/field'
104
15
  NULL_FIELD = Field.new(0, 0, :null, :display_name => "null field")
105
-
16
+
106
17
  # Raised when a field is added after an instance has been created. Fields
107
18
  # cannot be added after this point.
108
19
  class ClosedClassError < StandardError; end
@@ -110,9 +21,9 @@ class BitStruct < String
110
21
  # Raised if the chosen field name is not allowed, either because another
111
22
  # field by that name exists, or because a method by that name exists.
112
23
  class FieldNameError < StandardError; end
113
-
24
+
114
25
  @default_options = {}
115
-
26
+
116
27
  @initial_value = nil
117
28
  @closed = nil
118
29
  @rest_field = nil
@@ -127,7 +38,7 @@ class BitStruct < String
127
38
  @note = nil
128
39
  end
129
40
  end
130
-
41
+
131
42
  # ------------------------
132
43
  # :section: field access methods
133
44
  #
@@ -139,7 +50,7 @@ class BitStruct < String
139
50
  def fields
140
51
  @fields ||= self == BitStruct ? [] : superclass.fields.dup
141
52
  end
142
-
53
+
143
54
  # Return the list of fields defined by this class, not inherited
144
55
  # from the superclass.
145
56
  def own_fields
@@ -150,9 +61,9 @@ class BitStruct < String
150
61
  def add_field(name, length, opts = {})
151
62
  round_byte_length ## just to make sure this has been calculated
152
63
  ## before adding anything
153
-
64
+
154
65
  name = name.to_sym
155
-
66
+
156
67
  if @closed
157
68
  raise ClosedClassError, "Cannot add field #{name}: " +
158
69
  "The definition of the #{self.inspect} BitStruct class is closed."
@@ -169,9 +80,9 @@ class BitStruct < String
169
80
  raise FieldNameError,"Field #{name} is already defined as a method."
170
81
  end
171
82
  end
172
-
83
+
173
84
  field_class = opts[:field_class]
174
-
85
+
175
86
  prev = fields[-1] || NULL_FIELD
176
87
  offset = prev.offset + prev.length
177
88
  field = field_class.new(offset, length, name, opts)
@@ -194,13 +105,13 @@ class BitStruct < String
194
105
  def parse_options(ary, default_name, default_field_class) # :nodoc:
195
106
  opts = ary.grep(Hash).first || {}
196
107
  opts = default_options.merge(opts)
197
-
108
+
198
109
  opts[:display_name] = ary.grep(String).first || default_name
199
110
  opts[:field_class] = ary.grep(Class).first || default_field_class
200
-
111
+
201
112
  opts
202
113
  end
203
-
114
+
204
115
  # Get or set the hash of default options for the class, which apply to all
205
116
  # fields. Changes take effect immediately, so can be used alternatingly with
206
117
  # blocks of field declarations. If +h+ is provided, update the default
@@ -214,17 +125,17 @@ class BitStruct < String
214
125
  end
215
126
  @default_options
216
127
  end
217
-
128
+
218
129
  # Length, in bits, of this object.
219
130
  def bit_length
220
131
  @bit_length ||= fields.inject(0) {|a, f| a + f.length}
221
132
  end
222
-
133
+
223
134
  # Length, in bytes (rounded up), of this object.
224
135
  def round_byte_length
225
136
  @round_byte_length ||= (bit_length/8.0).ceil
226
137
  end
227
-
138
+
228
139
  def closed! # :nodoc:
229
140
  @closed = true
230
141
  end
@@ -239,12 +150,17 @@ class BitStruct < String
239
150
  field
240
151
  end
241
152
  end
242
-
153
+
243
154
  # Return the list of fields for this class.
244
155
  def fields
245
156
  self.class.fields
246
157
  end
247
-
158
+
159
+ # Return the rest field for this class.
160
+ def rest_field
161
+ self.class.rest_field
162
+ end
163
+
248
164
  # Return the field with the given name.
249
165
  def field_by_name name
250
166
  self.class.field_by_name name
@@ -261,7 +177,7 @@ class BitStruct < String
261
177
  # Default format for describe. Fields are byte, type, name, size,
262
178
  # and description.
263
179
  DESCRIBE_FORMAT = "%8s: %-12s %-14s[%4s] %s"
264
-
180
+
265
181
  # Can be overridden to use a different format.
266
182
  def describe_format
267
183
  DESCRIBE_FORMAT
@@ -274,7 +190,7 @@ class BitStruct < String
274
190
  if fmt.kind_of? Hash
275
191
  opts = fmt; fmt = nil
276
192
  end
277
-
193
+
278
194
  if block_given?
279
195
  fields.each do |field|
280
196
  field.describe(opts) do |desc|
@@ -282,7 +198,7 @@ class BitStruct < String
282
198
  end
283
199
  end
284
200
  nil
285
-
201
+
286
202
  else
287
203
  fmt ||= describe_format
288
204
 
@@ -306,7 +222,7 @@ class BitStruct < String
306
222
  result
307
223
  end
308
224
  end
309
-
225
+
310
226
  # Subclasses can use this to append a string (or several) to the #describe
311
227
  # output. Notes are not cumulative with inheritance. When used with no
312
228
  # arguments simply returns the note string
@@ -315,7 +231,7 @@ class BitStruct < String
315
231
  @note
316
232
  end
317
233
  end
318
-
234
+
319
235
  # ------------------------
320
236
  # :section: initialization and conversion methods
321
237
  #
@@ -334,9 +250,9 @@ class BitStruct < String
334
250
  value.each do |k, v|
335
251
  send "#{k}=", v
336
252
  end
337
-
253
+
338
254
  when nil
339
-
255
+
340
256
  else
341
257
  if value.respond_to?(:read)
342
258
  value = value.read(self.class.round_byte_length)
@@ -344,16 +260,16 @@ class BitStruct < String
344
260
 
345
261
  self[0, value.length] = value
346
262
  end
347
-
263
+
348
264
  self.class.closed!
349
265
  yield self if block_given?
350
266
  end
351
-
267
+
352
268
  DEFAULT_TO_H_OPTS = {
353
269
  :convert_keys => :to_sym,
354
270
  :include_rest => true
355
271
  }
356
-
272
+
357
273
  # Returns a hash of {name=>value,...} for each field. By default, include
358
274
  # the rest field.
359
275
  # Keys are symbols derived from field names using +to_sym+, unless
@@ -365,13 +281,13 @@ class BitStruct < String
365
281
  if opts[:include_rest] and (rest_field = self.class.rest_field)
366
282
  fields_for_to_h += [rest_field]
367
283
  end
368
-
284
+
369
285
  fields_for_to_h.inject({}) do |h,f|
370
286
  h[f.name.send(converter)] = send(f.name)
371
287
  h
372
288
  end
373
289
  end
374
-
290
+
375
291
  # Returns an array of values of the fields of the BitStruct. By default,
376
292
  # include the rest field.
377
293
  def to_a(include_rest = true)
@@ -379,16 +295,16 @@ class BitStruct < String
379
295
  fields.map do |f|
380
296
  send(f.name)
381
297
  end
382
-
298
+
383
299
  if include_rest and (rest_field = self.class.rest_field)
384
300
  ary << send(rest_field.name)
385
301
  end
302
+ ary
386
303
  end
387
-
388
- ## temporary hack for 1.9
304
+
389
305
  if "a"[0].kind_of? String
390
306
  def [](*args)
391
- if args.size == 1 and args[0].kind_of?(Fixnum)
307
+ if args.size == 1 and args[0].kind_of?(Integer)
392
308
  super.ord
393
309
  else
394
310
  super
@@ -396,14 +312,14 @@ class BitStruct < String
396
312
  end
397
313
 
398
314
  def []=(*args)
399
- if args.size == 2 and (i=args[0]).kind_of?(Fixnum)
315
+ if args.size == 2 and (i=args[0]).kind_of?(Integer)
400
316
  super(i, args[1].chr)
401
317
  else
402
318
  super
403
319
  end
404
320
  end
405
321
  end
406
-
322
+
407
323
  class << self
408
324
  # The unique "prototype" object from which new instances are copied.
409
325
  # The fields of this instance can be modified in the class definition
@@ -417,7 +333,7 @@ class BitStruct < String
417
333
  #
418
334
  def initial_value # :yields: the initial value
419
335
  unless @initial_value
420
- iv = defined?(superclass.initial_value) ?
336
+ iv = defined?(superclass.initial_value) ?
421
337
  superclass.initial_value.dup : ""
422
338
  if iv.length < round_byte_length
423
339
  iv << "\0" * (round_byte_length - iv.length)
@@ -426,7 +342,7 @@ class BitStruct < String
426
342
  @initial_value = "" # Serves as initval while the real initval is inited
427
343
  @initial_value = new(iv)
428
344
  @closed = false # only creating the first _real_ instance closes.
429
-
345
+
430
346
  fields.each do |field|
431
347
  @initial_value.send("#{field.name}=", field.default) if field.default
432
348
  end
@@ -434,7 +350,7 @@ class BitStruct < String
434
350
  yield @initial_value if block_given?
435
351
  @initial_value
436
352
  end
437
-
353
+
438
354
  # Take +data+ (a string or BitStruct) and parse it into instances of
439
355
  # the +classes+, returning them in an array. The classes can be given
440
356
  # as an array or a separate arguments. (For parsing a string into a _single_
@@ -444,7 +360,7 @@ class BitStruct < String
444
360
  c.new(data.slice!(0...c.round_byte_length))
445
361
  end
446
362
  end
447
-
363
+
448
364
  # Join the given structs (array or multiple args) as a string.
449
365
  # Actually, the inherited String#+ instance method is the same, as is using
450
366
  # Array#join.
@@ -468,7 +384,7 @@ class BitStruct < String
468
384
  :include_class => true,
469
385
  :simple_format => "<%s>"
470
386
  }
471
-
387
+
472
388
  DETAILED_INSPECT_OPTS = {
473
389
  :format => "%s:\n%s",
474
390
  :field_format => "%30s = %s",
@@ -479,32 +395,34 @@ class BitStruct < String
479
395
  :include_class => true,
480
396
  :simple_format => "\n%s"
481
397
  }
482
-
398
+
483
399
  # A standard inspect method which does not add newlines.
484
- def inspect(opts = DEFAULT_INSPECT_OPTS)
400
+ def inspect_with_options(opts = DEFAULT_INSPECT_OPTS)
485
401
  field_format = opts[:field_format]
486
402
  field_name_meth = opts[:field_name_meth]
487
-
403
+
488
404
  fields_for_inspect = fields.select {|field| field.inspectable?}
489
405
  if opts[:include_rest] and (rest_field = self.class.rest_field)
490
406
  fields_for_inspect << rest_field
491
407
  end
492
-
408
+
493
409
  ary = fields_for_inspect.map do |field|
494
410
  field_format %
495
411
  [field.send(field_name_meth),
496
412
  field.inspect_in_object(self, opts)]
497
413
  end
498
-
414
+
499
415
  body = ary.join(opts[:separator])
500
-
416
+
501
417
  if opts[:include_class]
502
418
  opts[:format] % [self.class, body]
503
419
  else
504
420
  opts[:simple_format] % body
505
421
  end
506
422
  end
507
-
423
+
424
+ alias inspect inspect_with_options
425
+
508
426
  # A more visually appealing inspect method that puts each field/value on
509
427
  # a separate line. Very useful when output is scrolling by on a screen.
510
428
  #
@@ -518,7 +436,7 @@ class BitStruct < String
518
436
  # :section: field declaration methods
519
437
  #
520
438
  # ------------------------
521
-
439
+
522
440
  # Define accessors for a variable length substring from the end of
523
441
  # the defined fields to the end of the BitStruct. The _rest_ may behave as
524
442
  # a String or as some other String or BitStruct subclass.
@@ -536,13 +454,13 @@ class BitStruct < String
536
454
  # If a hash is provided, use it for options.
537
455
  #
538
456
  # *Warning*: the rest reader method returns a copy of the field, so
539
- # accessors on that returned value do not affect the original rest field.
457
+ # accessors on that returned value do not affect the original rest field.
540
458
  #
541
459
  def self.rest(name, *ary)
542
460
  if @rest_field
543
461
  raise ArgumentError, "Duplicate rest field: #{name.inspect}."
544
462
  end
545
-
463
+
546
464
  opts = parse_options(ary, name, String)
547
465
  offset = round_byte_length
548
466
  byte_range = offset..-1
@@ -555,14 +473,14 @@ class BitStruct < String
555
473
  define_method "#{name}=" do |val|
556
474
  self[byte_range] = val
557
475
  end
558
-
476
+
559
477
  @rest_field = Field.new(offset, -1, name, {
560
478
  :display_name => opts[:display_name],
561
479
  :rest_class => field_class
562
480
  })
563
481
  end
564
482
  end
565
-
483
+
566
484
  # Not included with the other fields, but accessible separately.
567
485
  def self.rest_field; @rest_field; end
568
486
  end