Class: Depix::Field
- Inherits:
-
Object
- Object
- Depix::Field
- Defined in:
- lib/depix/dict.rb
Overview
A basic C structs library (only works by value).
Here's the basic mode of operation:
1) You define a struct, with a number of fields in it
3) Each field knows how big it is and how to produce a pattern to get it's value from the byte stream
by using Ruby's "pack/unpack". Each field thus provides an unpack pattern, and patterns are ordered
into a stack, starting with the first unpack pattern
4) When you parse some bytes using the struct, heres what will happen:
- An unpack pattern will be compiled from all of the fields composing the struct,
and it will be a single string. The string gets applied to the bytes passed to parse()
- An array of unpacked values returned by unpack is then passed to the struct's consumption engine,
which lets each field take as many items off the stack as it needs. A field might happily produce
4 items for unpacking and then take the same 4 items off the stack of parsed values. Or not.
- A new structure gets created and for every named field it defines an attr_accessor. When consuming,
the values returned by Field objects get set using the accessors (so accessors can be overridden too!)
5) When you save out the struct roughly the same happens but in reverse (readers are called per field,
then it's checked whether the data can be packed and fits into the alloted number of bytes, and then
one big array of values is composed and passed on to Array#pack)
Direct Known Subclasses
ArrayField, CharField, Filler, InnerField, R32Field, U16Field, U32Field, U8Field
Instance Attribute Summary collapse
-
#desc ⇒ Object
Field name.
-
#length ⇒ Object
Field name.
-
#name ⇒ Object
Field name.
-
#pattern ⇒ Object
Field name.
-
#req ⇒ Object
(also: #req?)
Field name.
-
#rtype ⇒ Object
Field name.
Class Method Summary collapse
-
.emit_char(o = {}) ⇒ Object
Emit a char field.
-
.emit_r32(o = {}) ⇒ Object
Emit a float field.
-
.emit_u16(o = {}) ⇒ Object
Emit a double int field.
-
.emit_u32(o = {}) ⇒ Object
Emit an unsigned int field.
-
.emit_u8(o = {}) ⇒ Object
Emit a short int field.
Instance Method Summary collapse
-
#clean(v) ⇒ Object
Return a cleaned value (like a null-terminated string truncated up to null).
-
#consume!(stack) ⇒ Object
Return the actual values from the stack.
-
#explain ⇒ Object
Show a nice textual explanation of the field.
-
#initialize(opts = {}) ⇒ Field
constructor
Hash init.
-
#pack(value) ⇒ Object
Pack a value passed into a string.
-
#validate!(value) ⇒ Object
Check that the passed value: a) Matches the Ruby type expected b) Fits into the slot c) Does not overflow When the validation fails should raise.
Constructor Details
#initialize(opts = {}) ⇒ Field
Hash init
35 36 37 |
# File 'lib/depix/dict.rb', line 35 def initialize(opts = {}) opts.each_pair {|k, v| send(k.to_s + '=', v) } end |
Instance Attribute Details
#desc ⇒ Object
Field name
26 27 28 |
# File 'lib/depix/dict.rb', line 26 def desc @desc end |
#length ⇒ Object
Field name
26 27 28 |
# File 'lib/depix/dict.rb', line 26 def length @length end |
#name ⇒ Object
Field name
26 27 28 |
# File 'lib/depix/dict.rb', line 26 def name @name end |
#pattern ⇒ Object
Field name
26 27 28 |
# File 'lib/depix/dict.rb', line 26 def pattern @pattern end |
#req ⇒ Object Also known as: req?
Field name
26 27 28 |
# File 'lib/depix/dict.rb', line 26 def req @req end |
#rtype ⇒ Object
Field name
26 27 28 |
# File 'lib/depix/dict.rb', line 26 def rtype @rtype end |
Class Method Details
.emit_char(o = {}) ⇒ Object
Emit a char field
55 56 57 58 |
# File 'lib/depix/dict.rb', line 55 def self.emit_char(o = {}) opts = {:length => 1}.merge(o) CharField.new(opts) end |
.emit_r32(o = {}) ⇒ Object
Emit a float field
61 62 63 |
# File 'lib/depix/dict.rb', line 61 def self.emit_r32(o = {}) R32Field.new(o) end |
.emit_u16(o = {}) ⇒ Object
Emit a double int field
50 51 52 |
# File 'lib/depix/dict.rb', line 50 def self.emit_u16(o = {}) U16Field.new(o) end |
Instance Method Details
#clean(v) ⇒ Object
Return a cleaned value (like a null-terminated string truncated up to null)
66 67 68 |
# File 'lib/depix/dict.rb', line 66 def clean(v) v end |
#consume!(stack) ⇒ Object
Return the actual values from the stack. The stack will begin on the element we need, so the default consumption is shift. Normally all fields shift the stack as they go, and if they contain nested substructs they will pop the stack as well
78 79 80 |
# File 'lib/depix/dict.rb', line 78 def consume!(stack) clean(stack.shift) end |
#explain ⇒ Object
Show a nice textual explanation of the field
71 72 73 |
# File 'lib/depix/dict.rb', line 71 def explain [rtype ? ("(%s)" % rtype) : nil, desc, (req? ? "- required" : nil)].compact.join(' ') end |
#pack(value) ⇒ Object
Pack a value passed into a string
93 94 95 96 97 98 99 100 |
# File 'lib/depix/dict.rb', line 93 def pack(value) raise "No pattern defined for #{self}" unless pattern if value.nil? [self.class.const_get(:BLANK)].pack(pattern) else [value].pack(pattern) end end |
#validate!(value) ⇒ Object
Check that the passed value: a) Matches the Ruby type expected b) Fits into the slot c) Does not overflow When the validation fails should raise
87 88 89 90 |
# File 'lib/depix/dict.rb', line 87 def validate!(value) raise "#{name} value required, but got nil in #{name}".strip if value.nil? && req? raise "Value expected to be #{rtype} but was #{value.class}" if !value.nil? && rtype && !value.is_a?(rtype) end |