databrick 0.1.1 → 0.2.0
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 +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
|