Class: Ruckus::Blob

Inherits:
Parsel show all
Defined in:
lib/ruckus/blob.rb

Overview

A Blob wraps an array. Everything within the array is rendered sequentially, returning a single string. Blob rendering is effectively preorder tree traversal (Blobs can contain any Parsel, including other Blobs)

Constant Summary

Constants inherited from Parsel

Parsel::VERBOTEN

Instance Attribute Summary

Attributes inherited from Parsel

#name, #parent, #rendered_offset, #rendering, #tag, #value

Instance Method Summary collapse

Methods inherited from Parsel

bytes_for_bits, coerce, #each_matching_selector, endian?, factory?, #find_containing, #find_tag, #find_tag_struct, #fixup, #in, #incomplete!, #index_for_selectors, #inspect, #matches_selector?, #method_missing, #native?, native?, #next, #out, #parent_structure, #permute, #prev, #resolve, #respond_to?, #root, #visit, #where_am_i?

Constructor Details

#initialize(opts = {}) ⇒ Blob

No special options needed.



11
12
13
14
15
16
17
# File 'lib/ruckus/blob.rb', line 11

def initialize(opts={})
    @value = Array.new
    (opts[:populate]||[]).each do |k|
        self << k.new
    end
    super(opts)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Ruckus::Parsel

Instance Method Details

#<<(v) ⇒ Object

This is the only way you should add elements to a Blob for now.



22
23
24
25
# File 'lib/ruckus/blob.rb', line 22

def <<(v)
    @value << v
    v.parent = self
end

#[]=(k, v) ⇒ Object

Assign a value to an element of a blob, so if you assign blob = 1, it works as expected.



35
36
37
38
# File 'lib/ruckus/blob.rb', line 35

def []=(k, v)
    return @value[k].value = v if not v.kind_of? Parsel
    @value[k] = v
end

#capture(str) ⇒ Object

As with Parsel; this will recurse through any embedded blobs.



55
56
57
58
59
60
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
# File 'lib/ruckus/blob.rb', line 55

def capture(str)
    @value.each_with_index do |it, i|
        begin
            str ||= "" # XXX bug

            # you don't always know the type of object
            # you want to instantiate at compile time;
            # it can depend on the contents of a packet.
            # when it does, there's a flag set that enables
            # a "factory" method which does the parse.
            #
            # the downside of this is once a blob has
            # been parsed with a factory, its definition
            # changes; that same blob can't be reused
            # to parse another packet. So, just don't
            # do that.

            if it.class.factory?
                @value[i], str = it.class.factory(str)
            else
                str = it.capture(str)
            end
        rescue IncompleteCapture
            err = "at item #{ i }"
            err << " named \"#{ it.name }\"" if it.name
            err << " in struct \"#{ it.parent_struct.name }\"" if it.parent_struct

            raise IncompleteCapture.new(err) if not str or str.empty?
        end
    end
    str
end

#countObject

How many elements are in the blob? (size returns the rendered size)



30
# File 'lib/ruckus/blob.rb', line 30

def count; @value.size; end

#place(o) ⇒ Object

Where is o in this blob? (Pretty sure you could just use index for this, but whatever)



43
44
45
46
47
48
49
50
# File 'lib/ruckus/blob.rb', line 43

def place(o)
    @value.each_with_index do |it, i|
        if o == it
            return i
        end
    end
    nil
end

#sizeObject

How big in bytes is this blob and everything it contains? An empty blob has size 0



91
92
93
# File 'lib/ruckus/blob.rb', line 91

def size
    @value.inject(0) {|acc, it| acc + it.size}
end

#to_s(off = nil) ⇒ Object

Render the blob, or return “” if it’s empty.



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/ruckus/blob.rb', line 97

def to_s(off=nil)
    @rendered_offset = off || 0
    voff = @rendered_offset
    r = ""
    @value.each do |it|
        s, voff = it.to_s(voff)
        r << s
    end

    if off
        return r, voff
    else
        return r
    end
end