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.
Files changed (3) hide show
  1. data/databrick.rb +48 -27
  2. data/test.rb +0 -1
  3. metadata +3 -3
@@ -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}, @source);
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 updated
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
- # add all the lengths for the bits before the specified one, to figure out the byte offset
91
- def offset_for(part)
92
- parts[0 ... parts.index(part)].inject(0) do |sofar, piece|
93
- sofar + self.send("length_for_#{piece}")
94
- end
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
- "<#{self.class.name}##{position}: #{parts.map {|p|
113
- val = self.send(p); ".#{p}: #{val.is_a?(DataBrick) ? val.micro_inspect : val.inspect}"
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; "<#{self.class.name}##{position}>"; end
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
- accumulate = ''; options[:length].times do |i|
178
- accumulate += send("blob_#{options[:innards]}", arr[i], props, options[:innards_options]).to_s
179
- end; return accumulate
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}*#{length}>"; end
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
@@ -32,7 +32,6 @@ until catman == nil
32
32
  catman = catman.next
33
33
  end
34
34
 
35
- File.unlink('cats.db')
36
35
  #### TEST ARRAYS!
37
36
 
38
37
  class ArrThing < DataBrick
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: 19
4
+ hash: 31
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 2
10
- version: 0.2.2
9
+ - 4
10
+ version: 0.2.4
11
11
  platform: ruby
12
12
  authors:
13
13
  - Bluebie