databrick 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/databrick.rb +71 -8
- data/test.rb +15 -0
- metadata +4 -4
data/databrick.rb
CHANGED
@@ -109,7 +109,9 @@ class DataBrick
|
|
109
109
|
|
110
110
|
# returns a stringy representation of this DataBrick's unique content
|
111
111
|
def inspect
|
112
|
-
"<#{self.class.name}##{position}: #{parts.map {|p|
|
112
|
+
"<#{self.class.name}##{position}: #{parts.map {|p|
|
113
|
+
val = self.send(p); ".#{p}: #{val.is_a?(DataBrick) ? val.micro_inspect : val.inspect}"
|
114
|
+
}.join(', ')}>"
|
113
115
|
end
|
114
116
|
|
115
117
|
def micro_inspect; "<#{self.class.name}##{position}>"; end
|
@@ -119,27 +121,36 @@ class DataBrick
|
|
119
121
|
PointerDefaults = {:bits => 32, :nil_if => 0xFFFFFFFF}
|
120
122
|
|
121
123
|
# defines a simple string - defaults 8 bit length, :bits => 16 or 32 for longer strings!
|
122
|
-
def self.define_one_string(name, opts
|
124
|
+
def self.define_one_string(name, opts)
|
123
125
|
define_piece "#{name}_length", :string_length, {:string_name => name}.merge(opts)
|
124
126
|
define_piece name, :raw_string, {:length_from => "#{name}_length".to_sym}.merge(opts)
|
125
127
|
end
|
126
128
|
|
129
|
+
# shortcut to raw string (fixed sounds nicer than raw, I think?)
|
130
|
+
def self.define_one_fixed_string(name, opts)
|
131
|
+
define_piece name, :raw_string, opts
|
132
|
+
end
|
133
|
+
|
127
134
|
# Thing readers!
|
128
135
|
IntPacker = {8 => 'C', 16 => 'n', 32 => 'N', 64 => 'Q'}
|
129
|
-
def read_integer(io, options
|
136
|
+
def read_integer(io, options); options = {:bits => 8}.merge(options)
|
130
137
|
source.read(options[:bits] / 8).unpack(IntPacker[options[:bits]]).first
|
131
138
|
end
|
132
139
|
|
133
|
-
def read_raw_string(io, options
|
140
|
+
def read_raw_string(io, options); io.read(options[:length] || send(options[:length_from])); end
|
134
141
|
alias_method :read_string_length, :read_integer
|
135
142
|
|
136
|
-
def read_pointer(io, options
|
143
|
+
def read_pointer(io, options)
|
137
144
|
options = PointerDefaults.merge(options)
|
138
145
|
ref = read_integer(io, options)
|
139
146
|
return nil if ref == options[:nil_if]
|
140
147
|
(options[:type] || self.class).new(io, ref)
|
141
148
|
end
|
142
149
|
|
150
|
+
def read_array(io, options)
|
151
|
+
FixedArray.new(io, options, self)
|
152
|
+
end
|
153
|
+
|
143
154
|
|
144
155
|
# Thing blobbers!
|
145
156
|
def self.blob_integer(int, props, options = {})
|
@@ -147,7 +158,8 @@ class DataBrick
|
|
147
158
|
end
|
148
159
|
|
149
160
|
def self.blob_raw_string(str, props, options = {})
|
150
|
-
str.to_s
|
161
|
+
if options[:length] then (str.to_s + ("\000" * options[:length]))[0 ... options[:length]]
|
162
|
+
else str.to_s end
|
151
163
|
end
|
152
164
|
|
153
165
|
def self.blob_pointer(pointee, props, options = {})
|
@@ -161,12 +173,58 @@ class DataBrick
|
|
161
173
|
self.blob_integer(props[options[:string_name]].to_s.length, props, options)
|
162
174
|
end
|
163
175
|
|
176
|
+
def self.blob_array(arr, props, options = {})
|
177
|
+
accumulate = ''; options[:length].times do |i|
|
178
|
+
accumulate += send("blob_#{options[:innards]}", arr[i], props, options[:innards_options]).to_s
|
179
|
+
end; return accumulate
|
180
|
+
end
|
181
|
+
|
164
182
|
# lengths for offset calculation
|
165
183
|
def type_length_integer(opts); (opts[:bits] || 8) / 8; end
|
166
184
|
def type_length_pointer(opts); (opts[:bits] || 32) / 8; end
|
167
|
-
def type_length_raw_string(opts); send(opts[:length_from]); end
|
185
|
+
def type_length_raw_string(opts); opts[:length] || send(opts[:length_from]); end
|
168
186
|
alias_method :type_length_string_length, :type_length_integer
|
187
|
+
def type_length_array(opts)
|
188
|
+
(opts[:length] || send(opts[:length_from])) * send("type_length_#{opts[:innards]}", opts[:innards_options] || {})
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
class DataBrick::FixedArray
|
193
|
+
def initialize(io, options, parent); @io = io; @start = io.tell; @options = options; @parent = parent; end
|
194
|
+
attr_reader :io, :start, :options
|
195
|
+
include Enumerable
|
169
196
|
|
197
|
+
# get a part of the array. :)
|
198
|
+
def [] key
|
199
|
+
was_at = @io.tell; seek_to key
|
200
|
+
return @parent.send("read_#{@options[:innards]}", @io, @options[:innards_options] || {})
|
201
|
+
ensure @io.seek was_at end
|
202
|
+
|
203
|
+
# set a part of the array. :)
|
204
|
+
def []= key, value
|
205
|
+
was_at = @source.tell
|
206
|
+
seek_to key
|
207
|
+
@io.write @parent.class.send("blob_#{@options[:innards]}", value, {}, @options[:innards_options] || {})
|
208
|
+
ensure @io.seek was_at end
|
209
|
+
|
210
|
+
# Implementing #each makes Enumerable happy!
|
211
|
+
def each &blk
|
212
|
+
(0 ... length).each { |index| blk.call(self[index]) }
|
213
|
+
end
|
214
|
+
|
215
|
+
def size; @options[:length] || @options[:length_from]; end
|
216
|
+
alias_method :length, :size
|
217
|
+
|
218
|
+
def inspect; "<#{self.class.name}:#{@start}*#{length}>"; end
|
219
|
+
|
220
|
+
protected
|
221
|
+
def seek_to key
|
222
|
+
raise 'Key must be an integer.' unless key.is_a?(Integer)
|
223
|
+
raise 'Index must not be negative.' if key < 0
|
224
|
+
raise 'Key must be less than length.' if key >= length
|
225
|
+
chunk_size = @parent.send("type_length_#{@options[:innards]}", @options[:innards_options] || {})
|
226
|
+
@io.seek @start + (chunk_size * key)
|
227
|
+
end
|
170
228
|
end
|
171
229
|
|
172
230
|
# -=- BrickFu Lessons! -=-
|
@@ -205,11 +263,16 @@ end
|
|
205
263
|
# catman = catman.next
|
206
264
|
# end until catman == nil
|
207
265
|
#
|
266
|
+
#### Notes:
|
267
|
+
# Arrays can only currently contain statically lengthed things,
|
268
|
+
# numbers, pointers, and fixed_strings are great examples.
|
269
|
+
# If you want to see how more of the types work, look in the
|
270
|
+
# test.rb file at how it does it. :)
|
271
|
+
#
|
208
272
|
|
209
273
|
#### TODO:
|
210
274
|
# @ Add float types
|
211
275
|
# @ Maybe something for signed numbers?
|
212
|
-
# @ An Array type?
|
213
276
|
# @ Booleans type! (length = bools / 8)
|
214
277
|
#
|
215
278
|
|
data/test.rb
CHANGED
@@ -32,3 +32,18 @@ until catman == nil
|
|
32
32
|
catman = catman.next
|
33
33
|
end
|
34
34
|
|
35
|
+
File.unlink('cats.db')
|
36
|
+
#### TEST ARRAYS!
|
37
|
+
|
38
|
+
class ArrThing < DataBrick
|
39
|
+
define_piece :words, :array, :innards => :raw_string, :innards_options => {:length => 4}, :length => 10
|
40
|
+
end
|
41
|
+
|
42
|
+
file = open('arr-thing.db', 'w+')
|
43
|
+
thing = ArrThing.create({
|
44
|
+
:words => ['cats', 'bats', 'cake', 'macs', 'chat', 'wave', 'four', 'tofu', 'echo', 'flop']
|
45
|
+
}, file)
|
46
|
+
|
47
|
+
puts "\nThese are a few of my favourite things:"
|
48
|
+
thing.words.each { |word| puts word }
|
49
|
+
file.close
|
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: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Bluebie
|