databrick 0.2.2 → 0.2.4
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.
- data/databrick.rb +48 -27
- data/test.rb +0 -1
- metadata +3 -3
data/databrick.rb
CHANGED
@@ -41,14 +41,19 @@ class DataBrick
|
|
41
41
|
define_method("#{name}=") do |value|
|
42
42
|
begin; was_at = @source.tell
|
43
43
|
@source.seek @position
|
44
|
-
update({name => value}
|
44
|
+
update({name => value});
|
45
45
|
ensure; @source.seek was_at; end
|
46
46
|
end
|
47
47
|
else
|
48
48
|
define_method("#{name}=") do |value|
|
49
49
|
begin; was_at = @source.tell
|
50
50
|
@source.seek @position + offset_for(name)
|
51
|
-
@source.write self.class.send("blob_#{type}", value, {}, options)
|
51
|
+
@source.write(blobbed = self.class.send("blob_#{type}", value, {}, options))
|
52
|
+
if blobbed.bytesize != send("length_for_#{name}")
|
53
|
+
# refresh these silly bits because lengths are all wonky!
|
54
|
+
part_list = self.parts; next_parts = part_list[part_list.index(name) ... part_list.size]
|
55
|
+
next_parts.each { |nname| self.send("#{nname}=", self.send(nname)) }
|
56
|
+
end
|
52
57
|
@source.flush
|
53
58
|
ensure; @source.seek was_at; end
|
54
59
|
end
|
@@ -77,21 +82,25 @@ class DataBrick
|
|
77
82
|
end
|
78
83
|
|
79
84
|
def update properties
|
85
|
+
was_at = @source.tell
|
80
86
|
blob = self.class.create(to_h.merge(properties))
|
81
|
-
raise 'Length of brick is longer! cannot safely update without overflowing! Aborting!' if length < blob.length
|
87
|
+
#raise 'Length of brick is longer! cannot safely update without overflowing! Aborting!' if length < blob.length
|
82
88
|
@source.seek @position
|
83
|
-
@source.write
|
89
|
+
@source.write blob
|
84
90
|
@source.flush
|
85
|
-
end
|
91
|
+
ensure; @source.seek was_at; end
|
92
|
+
alias_method :merge!, :update
|
86
93
|
|
87
94
|
# returns the byte length of this block serialized
|
88
95
|
def length; parts.inject(0) { |sofar, part| sofar + send("length_for_#{part}") }; end
|
89
96
|
|
90
|
-
#
|
91
|
-
def offset_for(part)
|
92
|
-
|
93
|
-
|
94
|
-
|
97
|
+
# get the start position of a defined piece, considering any variable length bits
|
98
|
+
def offset_for(part); parts[0...parts.index(part)].inject(0) { |sofar, part| sofar + send("length_for_#{part}") }; end
|
99
|
+
|
100
|
+
# get them all
|
101
|
+
def offsets
|
102
|
+
sofar = 0
|
103
|
+
([0] + parts.map { |part| sofar += self.send("length_for_#{part}") })
|
95
104
|
end
|
96
105
|
|
97
106
|
# returns a hash version of this DataBrick
|
@@ -109,20 +118,25 @@ class DataBrick
|
|
109
118
|
|
110
119
|
# returns a stringy representation of this DataBrick's unique content
|
111
120
|
def inspect
|
112
|
-
"
|
113
|
-
val = self.send(p); ".#{p}: #{val.
|
114
|
-
}.join(', ')}
|
121
|
+
"[#{self.class.name}+#{position}: #{parts.map {|p|
|
122
|
+
val = self.send(p); ".#{p}: #{val.respond_to?(:micro_inspect) ? val.micro_inspect : val.inspect}"
|
123
|
+
}.join(', ')}]"
|
115
124
|
end
|
116
125
|
|
117
|
-
def micro_inspect; "
|
126
|
+
def micro_inspect; "[#{self.class.name}+#{position}]"; end
|
127
|
+
|
128
|
+
# If loaded via a :pointer, this lets you get back to the parent, or set that pointer to some other thing
|
129
|
+
def parent; @parent; end
|
130
|
+
def parents_child= value; @parental_setter.call(value); end
|
118
131
|
|
119
132
|
protected
|
133
|
+
def set_parent_accessors(parent, &set); @parent = parent; @parental_setter = set; self end
|
120
134
|
def parts; self.class.instance_variable_get(:@parts); end
|
121
135
|
PointerDefaults = {:bits => 32, :nil_if => 0xFFFFFFFF}
|
122
136
|
|
123
137
|
# defines a simple string - defaults 8 bit length, :bits => 16 or 32 for longer strings!
|
124
138
|
def self.define_one_string(name, opts)
|
125
|
-
define_piece "#{name}_length", :string_length, {:string_name => name}.merge(opts)
|
139
|
+
define_piece "#{name}_length", :string_length, {:string_name => name}.merge(opts) unless opts[:length] || opts[:length_from]
|
126
140
|
define_piece name, :raw_string, {:length_from => "#{name}_length".to_sym}.merge(opts)
|
127
141
|
end
|
128
142
|
|
@@ -137,14 +151,18 @@ class DataBrick
|
|
137
151
|
source.read(options[:bits] / 8).unpack(IntPacker[options[:bits]]).first
|
138
152
|
end
|
139
153
|
|
140
|
-
def read_raw_string(io, options); io.read(options[:length] || send(options[:length_from])); end
|
154
|
+
def read_raw_string(io, options); io.read(options[:length] || send(options[:length_from])).freeze; end
|
141
155
|
alias_method :read_string_length, :read_integer
|
142
156
|
|
143
157
|
def read_pointer(io, options)
|
144
158
|
options = PointerDefaults.merge(options)
|
159
|
+
pos = io.tell
|
145
160
|
ref = read_integer(io, options)
|
146
161
|
return nil if ref == options[:nil_if]
|
147
|
-
(options[:type] || self.class).new(io, ref)
|
162
|
+
obj = (options[:type] || self.class).new(io, ref)
|
163
|
+
obj.send(:set_parent_accessors, self) do |value|
|
164
|
+
w = io.tell; io.seek pos; io.write self.blob_pointer(value, {}, options); io.seek w
|
165
|
+
end
|
148
166
|
end
|
149
167
|
|
150
168
|
def read_array(io, options)
|
@@ -157,10 +175,7 @@ class DataBrick
|
|
157
175
|
[int.to_i].pack(IntPacker[options[:bits] || 8])
|
158
176
|
end
|
159
177
|
|
160
|
-
def self.blob_raw_string(str, props, options = {})
|
161
|
-
if options[:length] then (str.to_s + ("\000" * options[:length]))[0 ... options[:length]]
|
162
|
-
else str.to_s end
|
163
|
-
end
|
178
|
+
def self.blob_raw_string(str, props, options = {}); str.to_s; end
|
164
179
|
|
165
180
|
def self.blob_pointer(pointee, props, options = {})
|
166
181
|
options = PointerDefaults.merge(options)
|
@@ -174,9 +189,9 @@ class DataBrick
|
|
174
189
|
end
|
175
190
|
|
176
191
|
def self.blob_array(arr, props, options = {})
|
177
|
-
|
178
|
-
|
179
|
-
|
192
|
+
arr.inject('') { |result, item|
|
193
|
+
result += send("blob_#{options[:innards]}", item, props, options[:innards_options]).to_s
|
194
|
+
}
|
180
195
|
end
|
181
196
|
|
182
197
|
# lengths for offset calculation
|
@@ -195,7 +210,10 @@ class DataBrick::FixedArray
|
|
195
210
|
include Enumerable
|
196
211
|
|
197
212
|
# get a part of the array. :)
|
198
|
-
def [] key
|
213
|
+
def [] key, length = nil
|
214
|
+
key = (key.to_i ... key.to_i + length.to_i) if length
|
215
|
+
return key.map { |i| self[i] } if key.is_a?(Range)
|
216
|
+
|
199
217
|
was_at = @io.tell; seek_to key
|
200
218
|
return @parent.send("read_#{@options[:innards]}", @io, @options[:innards_options] || {})
|
201
219
|
ensure @io.seek was_at end
|
@@ -213,10 +231,12 @@ class DataBrick::FixedArray
|
|
213
231
|
(0 ... length).each { |index| blk.call(self[index]) }
|
214
232
|
end
|
215
233
|
|
216
|
-
def size; @options[:length] || @options[:length_from]; end
|
234
|
+
def size; @options[:length] || @parent.send(@options[:length_from]); end
|
217
235
|
alias_method :length, :size
|
218
236
|
|
219
|
-
def inspect; "<#{self.class.name}:#{@start}
|
237
|
+
def inspect; "<#{self.class.name}:#{@start}+#{length}>"; end
|
238
|
+
|
239
|
+
def to_a; (0...size).map { |i| self[i] }; end
|
220
240
|
|
221
241
|
protected
|
222
242
|
def seek_to key
|
@@ -272,6 +292,7 @@ end
|
|
272
292
|
#
|
273
293
|
|
274
294
|
#### TODO:
|
295
|
+
# !!! Update the raw_string writer to only rewrite stuff _after_ the changed string, and only if it's length actually changed.
|
275
296
|
# @ Add float types
|
276
297
|
# @ Maybe something for signed numbers?
|
277
298
|
# @ Booleans type! (length = bools / 8)
|
data/test.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: databrick
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 31
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 4
|
10
|
+
version: 0.2.4
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Bluebie
|