databrick 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/databrick.rb +71 -8
  2. data/test.rb +15 -0
  3. metadata +4 -4
@@ -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| val = self.send(p); ".#{p}: #{val.is_a?(DataBrick) ? val.micro_inspect : val.inspect}" }.join(', ')}>"
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 = {}); options = {:bits => 8}.merge(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 = {}); io.read(send(options[:length_from])); end
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: 25
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
9
- - 1
10
- version: 0.1.1
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Bluebie