jbangert-bindata 1.5.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/.gitignore +1 -0
- data/BSDL +22 -0
- data/COPYING +52 -0
- data/ChangeLog.rdoc +204 -0
- data/Gemfile +2 -0
- data/INSTALL +11 -0
- data/NEWS.rdoc +164 -0
- data/README.md +54 -0
- data/Rakefile +13 -0
- data/bindata.gemspec +31 -0
- data/doc/manual.haml +407 -0
- data/doc/manual.md +1649 -0
- data/examples/NBT.txt +149 -0
- data/examples/gzip.rb +161 -0
- data/examples/ip_address.rb +22 -0
- data/examples/list.rb +124 -0
- data/examples/nbt.rb +178 -0
- data/lib/bindata.rb +33 -0
- data/lib/bindata/alignment.rb +83 -0
- data/lib/bindata/array.rb +335 -0
- data/lib/bindata/base.rb +388 -0
- data/lib/bindata/base_primitive.rb +214 -0
- data/lib/bindata/bits.rb +87 -0
- data/lib/bindata/choice.rb +216 -0
- data/lib/bindata/count_bytes_remaining.rb +35 -0
- data/lib/bindata/deprecated.rb +50 -0
- data/lib/bindata/dsl.rb +312 -0
- data/lib/bindata/float.rb +80 -0
- data/lib/bindata/int.rb +184 -0
- data/lib/bindata/io.rb +274 -0
- data/lib/bindata/lazy.rb +105 -0
- data/lib/bindata/offset.rb +91 -0
- data/lib/bindata/params.rb +135 -0
- data/lib/bindata/primitive.rb +135 -0
- data/lib/bindata/record.rb +110 -0
- data/lib/bindata/registry.rb +92 -0
- data/lib/bindata/rest.rb +35 -0
- data/lib/bindata/sanitize.rb +290 -0
- data/lib/bindata/skip.rb +48 -0
- data/lib/bindata/string.rb +145 -0
- data/lib/bindata/stringz.rb +96 -0
- data/lib/bindata/struct.rb +388 -0
- data/lib/bindata/trace.rb +94 -0
- data/lib/bindata/version.rb +3 -0
- data/setup.rb +1585 -0
- data/spec/alignment_spec.rb +61 -0
- data/spec/array_spec.rb +331 -0
- data/spec/base_primitive_spec.rb +238 -0
- data/spec/base_spec.rb +376 -0
- data/spec/bits_spec.rb +163 -0
- data/spec/choice_spec.rb +263 -0
- data/spec/count_bytes_remaining_spec.rb +38 -0
- data/spec/deprecated_spec.rb +31 -0
- data/spec/example.rb +21 -0
- data/spec/float_spec.rb +37 -0
- data/spec/int_spec.rb +216 -0
- data/spec/io_spec.rb +352 -0
- data/spec/lazy_spec.rb +217 -0
- data/spec/primitive_spec.rb +202 -0
- data/spec/record_spec.rb +530 -0
- data/spec/registry_spec.rb +108 -0
- data/spec/rest_spec.rb +26 -0
- data/spec/skip_spec.rb +27 -0
- data/spec/spec_common.rb +58 -0
- data/spec/string_spec.rb +300 -0
- data/spec/stringz_spec.rb +118 -0
- data/spec/struct_spec.rb +350 -0
- data/spec/system_spec.rb +380 -0
- data/tasks/manual.rake +36 -0
- data/tasks/rspec.rake +17 -0
- metadata +208 -0
data/spec/io_spec.rb
ADDED
@@ -0,0 +1,352 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "spec_common"))
|
4
|
+
require 'bindata/io'
|
5
|
+
|
6
|
+
describe BinData::IO, "reading from non seekable stream" do
|
7
|
+
before(:each) do
|
8
|
+
@rd, @wr = IO::pipe
|
9
|
+
if fork
|
10
|
+
# parent
|
11
|
+
@wr.close
|
12
|
+
@io = BinData::IO.new(@rd)
|
13
|
+
else
|
14
|
+
# child
|
15
|
+
begin
|
16
|
+
@rd.close
|
17
|
+
@wr.write "a" * 5000
|
18
|
+
@wr.write "b" * 5000
|
19
|
+
@wr.close
|
20
|
+
rescue Exception
|
21
|
+
# ignore it
|
22
|
+
ensure
|
23
|
+
exit!
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
after(:each) do
|
29
|
+
@rd.close
|
30
|
+
Process.wait
|
31
|
+
end
|
32
|
+
|
33
|
+
it "always has an offset of 0" do
|
34
|
+
@io.readbytes(10)
|
35
|
+
@io.offset.should == 0
|
36
|
+
end
|
37
|
+
|
38
|
+
it "seeks correctly" do
|
39
|
+
@io.seekbytes(4999)
|
40
|
+
@io.readbytes(5).should == "abbbb"
|
41
|
+
end
|
42
|
+
|
43
|
+
it "returns zero for num bytes remaining" do
|
44
|
+
@io.num_bytes_remaining.should == 0
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe BinData::IO, "when reading" do
|
49
|
+
let(:stream) { StringIO.new "abcdefghij" }
|
50
|
+
let(:io) { BinData::IO.new(stream) }
|
51
|
+
|
52
|
+
it "wraps strings in StringIO" do
|
53
|
+
io.raw_io.class.should == StringIO
|
54
|
+
end
|
55
|
+
|
56
|
+
it "does not wrap IO objects" do
|
57
|
+
io.raw_io.should == stream
|
58
|
+
end
|
59
|
+
|
60
|
+
it "raises error when io is BinData::IO" do
|
61
|
+
expect {
|
62
|
+
BinData::IO.new(BinData::IO.new(""))
|
63
|
+
}.to raise_error(ArgumentError)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "returns correct offset" do
|
67
|
+
stream.seek(3, IO::SEEK_CUR)
|
68
|
+
|
69
|
+
io.offset.should == 0
|
70
|
+
io.readbytes(4).should == "defg"
|
71
|
+
io.offset.should == 4
|
72
|
+
end
|
73
|
+
|
74
|
+
it "seeks correctly" do
|
75
|
+
io.seekbytes(2)
|
76
|
+
io.readbytes(4).should == "cdef"
|
77
|
+
end
|
78
|
+
|
79
|
+
it "reads all bytes" do
|
80
|
+
io.read_all_bytes.should == "abcdefghij"
|
81
|
+
end
|
82
|
+
|
83
|
+
it "returns number of bytes remaining" do
|
84
|
+
stream_length = io.num_bytes_remaining
|
85
|
+
|
86
|
+
io.readbytes(4)
|
87
|
+
io.num_bytes_remaining.should == stream_length - 4
|
88
|
+
end
|
89
|
+
|
90
|
+
it "raises error when reading at eof" do
|
91
|
+
io.seekbytes(10)
|
92
|
+
expect {
|
93
|
+
io.readbytes(3)
|
94
|
+
}.to raise_error(EOFError)
|
95
|
+
end
|
96
|
+
|
97
|
+
it "raises error on short reads" do
|
98
|
+
expect {
|
99
|
+
io.readbytes(20)
|
100
|
+
}.to raise_error(IOError)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe BinData::IO, "when writing" do
|
105
|
+
let(:stream) { StringIO.new }
|
106
|
+
let(:io) { BinData::IO.new(stream) }
|
107
|
+
|
108
|
+
it "does not wrap IO objects" do
|
109
|
+
io.raw_io.should == stream
|
110
|
+
end
|
111
|
+
|
112
|
+
it "raises error when io is BinData::IO" do
|
113
|
+
expect {
|
114
|
+
BinData::IO.new(BinData::IO.new(""))
|
115
|
+
}.to raise_error(ArgumentError)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "writes correctly" do
|
119
|
+
io.writebytes("abcd")
|
120
|
+
|
121
|
+
stream.value.should == "abcd"
|
122
|
+
end
|
123
|
+
|
124
|
+
it "flushes" do
|
125
|
+
io.writebytes("abcd")
|
126
|
+
io.flush
|
127
|
+
|
128
|
+
stream.value.should == "abcd"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe BinData::IO, "reading bits in big endian" do
|
133
|
+
let(:b1) { 0b1111_1010 }
|
134
|
+
let(:b2) { 0b1100_1110 }
|
135
|
+
let(:b3) { 0b0110_1010 }
|
136
|
+
let(:io) { BinData::IO.new([b1, b2, b3].pack("CCC")) }
|
137
|
+
|
138
|
+
it "reads a bitfield less than 1 byte" do
|
139
|
+
io.readbits(3, :big).should == 0b111
|
140
|
+
end
|
141
|
+
|
142
|
+
it "reads a bitfield more than 1 byte" do
|
143
|
+
io.readbits(10, :big).should == 0b1111_1010_11
|
144
|
+
end
|
145
|
+
|
146
|
+
it "reads a bitfield more than 2 bytes" do
|
147
|
+
io.readbits(17, :big).should == 0b1111_1010_1100_1110_0
|
148
|
+
end
|
149
|
+
|
150
|
+
it "reads two bitfields totalling less than 1 byte" do
|
151
|
+
io.readbits(5, :big).should == 0b1111_1
|
152
|
+
io.readbits(2, :big).should == 0b01
|
153
|
+
end
|
154
|
+
|
155
|
+
it "reads two bitfields totalling more than 1 byte" do
|
156
|
+
io.readbits(6, :big).should == 0b1111_10
|
157
|
+
io.readbits(8, :big).should == 0b10_1100_11
|
158
|
+
end
|
159
|
+
|
160
|
+
it "reads two bitfields totalling more than 2 bytes" do
|
161
|
+
io.readbits(7, :big).should == 0b1111_101
|
162
|
+
io.readbits(12, :big).should == 0b0_1100_1110_011
|
163
|
+
end
|
164
|
+
|
165
|
+
it "ignores unused bits when reading bytes" do
|
166
|
+
io.readbits(3, :big).should == 0b111
|
167
|
+
io.readbytes(1).should == [b2].pack("C")
|
168
|
+
io.readbits(2, :big).should == 0b01
|
169
|
+
end
|
170
|
+
|
171
|
+
it "resets read bits to realign stream to next byte" do
|
172
|
+
io.readbits(3, :big).should == 0b111
|
173
|
+
io.reset_read_bits
|
174
|
+
io.readbits(3, :big).should == 0b110
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe BinData::IO, "reading bits in little endian" do
|
179
|
+
let(:b1) { 0b1111_1010 }
|
180
|
+
let(:b2) { 0b1100_1110 }
|
181
|
+
let(:b3) { 0b0110_1010 }
|
182
|
+
let(:io) { BinData::IO.new([b1, b2, b3].pack("CCC")) }
|
183
|
+
|
184
|
+
it "reads a bitfield less than 1 byte" do
|
185
|
+
io.readbits(3, :little).should == 0b010
|
186
|
+
end
|
187
|
+
|
188
|
+
it "reads a bitfield more than 1 byte" do
|
189
|
+
io.readbits(10, :little).should == 0b10_1111_1010
|
190
|
+
end
|
191
|
+
|
192
|
+
it "reads a bitfield more than 2 bytes" do
|
193
|
+
io.readbits(17, :little).should == 0b0_1100_1110_1111_1010
|
194
|
+
end
|
195
|
+
|
196
|
+
it "reads two bitfields totalling less than 1 byte" do
|
197
|
+
io.readbits(5, :little).should == 0b1_1010
|
198
|
+
io.readbits(2, :little).should == 0b11
|
199
|
+
end
|
200
|
+
|
201
|
+
it "reads two bitfields totalling more than 1 byte" do
|
202
|
+
io.readbits(6, :little).should == 0b11_1010
|
203
|
+
io.readbits(8, :little).should == 0b00_1110_11
|
204
|
+
end
|
205
|
+
|
206
|
+
it "reads two bitfields totalling more than 2 bytes" do
|
207
|
+
io.readbits(7, :little).should == 0b111_1010
|
208
|
+
io.readbits(12, :little).should == 0b010_1100_1110_1
|
209
|
+
end
|
210
|
+
|
211
|
+
it "ignores unused bits when reading bytes" do
|
212
|
+
io.readbits(3, :little).should == 0b010
|
213
|
+
io.readbytes(1).should == [b2].pack("C")
|
214
|
+
io.readbits(2, :little).should == 0b10
|
215
|
+
end
|
216
|
+
|
217
|
+
it "resets read bits to realign stream to next byte" do
|
218
|
+
io.readbits(3, :little).should == 0b010
|
219
|
+
io.reset_read_bits
|
220
|
+
io.readbits(3, :little).should == 0b110
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
class BitWriterHelper
|
225
|
+
def initialize
|
226
|
+
@stringio = BinData::IO.create_string_io
|
227
|
+
@io = BinData::IO.new(@stringio)
|
228
|
+
end
|
229
|
+
|
230
|
+
def writebits(val, nbits, endian)
|
231
|
+
@io.writebits(val, nbits, endian)
|
232
|
+
end
|
233
|
+
|
234
|
+
def writebytes(val)
|
235
|
+
@io.writebytes(val)
|
236
|
+
end
|
237
|
+
|
238
|
+
def value
|
239
|
+
@io.flushbits
|
240
|
+
@stringio.rewind
|
241
|
+
@stringio.read
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
describe BinData::IO, "writing bits in big endian" do
|
246
|
+
let(:io) { BitWriterHelper.new }
|
247
|
+
|
248
|
+
it "writes a bitfield less than 1 byte" do
|
249
|
+
io.writebits(0b010, 3, :big)
|
250
|
+
io.value.should == [0b0100_0000].pack("C")
|
251
|
+
end
|
252
|
+
|
253
|
+
it "writes a bitfield more than 1 byte" do
|
254
|
+
io.writebits(0b10_1001_1101, 10, :big)
|
255
|
+
io.value.should == [0b1010_0111, 0b0100_0000].pack("CC")
|
256
|
+
end
|
257
|
+
|
258
|
+
it "writes a bitfield more than 2 bytes" do
|
259
|
+
io.writebits(0b101_1000_0010_1001_1101, 19, :big)
|
260
|
+
io.value.should == [0b1011_0000, 0b0101_0011, 0b1010_0000].pack("CCC")
|
261
|
+
end
|
262
|
+
|
263
|
+
it "writes two bitfields totalling less than 1 byte" do
|
264
|
+
io.writebits(0b1_1001, 5, :big)
|
265
|
+
io.writebits(0b00, 2, :big)
|
266
|
+
io.value.should == [0b1100_1000].pack("C")
|
267
|
+
end
|
268
|
+
|
269
|
+
it "writes two bitfields totalling more than 1 byte" do
|
270
|
+
io.writebits(0b01_0101, 6, :big)
|
271
|
+
io.writebits(0b001_1001, 7, :big)
|
272
|
+
io.value.should == [0b0101_0100, 0b1100_1000].pack("CC")
|
273
|
+
end
|
274
|
+
|
275
|
+
it "writes two bitfields totalling more than 2 bytes" do
|
276
|
+
io.writebits(0b01_0111, 6, :big)
|
277
|
+
io.writebits(0b1_0010_1001_1001, 13, :big)
|
278
|
+
io.value.should == [0b0101_1110, 0b0101_0011, 0b0010_0000].pack("CCC")
|
279
|
+
end
|
280
|
+
|
281
|
+
it "pads unused bits when writing bytes" do
|
282
|
+
io.writebits(0b101, 3, :big)
|
283
|
+
io.writebytes([0b1011_1111].pack("C"))
|
284
|
+
io.writebits(0b01, 2, :big)
|
285
|
+
|
286
|
+
io.value.should == [0b1010_0000, 0b1011_1111, 0b0100_0000].pack("CCC")
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
describe BinData::IO, "writing bits in little endian" do
|
291
|
+
let(:io) { BitWriterHelper.new }
|
292
|
+
|
293
|
+
it "writes a bitfield less than 1 byte" do
|
294
|
+
io.writebits(0b010, 3, :little)
|
295
|
+
io.value.should == [0b0000_0010].pack("C")
|
296
|
+
end
|
297
|
+
|
298
|
+
it "writes a bitfield more than 1 byte" do
|
299
|
+
io.writebits(0b10_1001_1101, 10, :little)
|
300
|
+
io.value.should == [0b1001_1101, 0b0000_0010].pack("CC")
|
301
|
+
end
|
302
|
+
|
303
|
+
it "writes a bitfield more than 2 bytes" do
|
304
|
+
io.writebits(0b101_1000_0010_1001_1101, 19, :little)
|
305
|
+
io.value.should == [0b1001_1101, 0b1000_0010, 0b0000_0101].pack("CCC")
|
306
|
+
end
|
307
|
+
|
308
|
+
it "writes two bitfields totalling less than 1 byte" do
|
309
|
+
io.writebits(0b1_1001, 5, :little)
|
310
|
+
io.writebits(0b00, 2, :little)
|
311
|
+
io.value.should == [0b0001_1001].pack("C")
|
312
|
+
end
|
313
|
+
|
314
|
+
it "writes two bitfields totalling more than 1 byte" do
|
315
|
+
io.writebits(0b01_0101, 6, :little)
|
316
|
+
io.writebits(0b001_1001, 7, :little)
|
317
|
+
io.value.should == [0b0101_0101, 0b0000_0110].pack("CC")
|
318
|
+
end
|
319
|
+
|
320
|
+
it "writes two bitfields totalling more than 2 bytes" do
|
321
|
+
io.writebits(0b01_0111, 6, :little)
|
322
|
+
io.writebits(0b1_0010_1001_1001, 13, :little)
|
323
|
+
io.value.should == [0b0101_0111, 0b1010_0110, 0b0000_0100].pack("CCC")
|
324
|
+
end
|
325
|
+
|
326
|
+
it "pads unused bits when writing bytes" do
|
327
|
+
io.writebits(0b101, 3, :little)
|
328
|
+
io.writebytes([0b1011_1111].pack("C"))
|
329
|
+
io.writebits(0b01, 2, :little)
|
330
|
+
|
331
|
+
io.value.should == [0b0000_0101, 0b1011_1111, 0b0000_0001].pack("CCC")
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
describe BinData::IO, "with changing endian" do
|
336
|
+
it "does not mix different endianess when reading" do
|
337
|
+
b1 = 0b0110_1010
|
338
|
+
b2 = 0b1110_0010
|
339
|
+
str = [b1, b2].pack("CC")
|
340
|
+
io = BinData::IO.new(str)
|
341
|
+
|
342
|
+
io.readbits(3, :big).should == 0b011
|
343
|
+
io.readbits(4, :little).should == 0b0010
|
344
|
+
end
|
345
|
+
|
346
|
+
it "does not mix different endianess when writing" do
|
347
|
+
io = BitWriterHelper.new
|
348
|
+
io.writebits(0b110, 3, :big)
|
349
|
+
io.writebits(0b010, 3, :little)
|
350
|
+
io.value.should == [0b1100_0000, 0b0000_0010].pack("CC")
|
351
|
+
end
|
352
|
+
end
|
data/spec/lazy_spec.rb
ADDED
@@ -0,0 +1,217 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "spec_common"))
|
4
|
+
require 'bindata/lazy'
|
5
|
+
|
6
|
+
# A mock data object with customizable fields.
|
7
|
+
class MockBinDataObject
|
8
|
+
def initialize(methods = {}, params = {}, parent = nil)
|
9
|
+
meta = class << self ; self; end
|
10
|
+
methods.each do |k,v|
|
11
|
+
meta.send(:define_method, k.to_sym) { v }
|
12
|
+
end
|
13
|
+
@parameters = params
|
14
|
+
@parent = parent
|
15
|
+
end
|
16
|
+
attr_accessor :parent
|
17
|
+
|
18
|
+
def has_parameter?(key)
|
19
|
+
@parameters.has_key?(key)
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_parameter(key)
|
23
|
+
@parameters[key]
|
24
|
+
end
|
25
|
+
|
26
|
+
def lazy_evaluator
|
27
|
+
BinData::LazyEvaluator.new(self)
|
28
|
+
end
|
29
|
+
|
30
|
+
alias_method :safe_respond_to?, :respond_to?
|
31
|
+
end
|
32
|
+
|
33
|
+
def lazy_eval(*rest)
|
34
|
+
subject.lazy_evaluator.lazy_eval(*rest)
|
35
|
+
end
|
36
|
+
|
37
|
+
describe BinData::LazyEvaluator, "with no parents" do
|
38
|
+
subject {
|
39
|
+
methods = {:m1 => 'm1', :com => 'mC'}
|
40
|
+
params = {:p1 => 'p1', :com => 'pC'}
|
41
|
+
MockBinDataObject.new(methods, params)
|
42
|
+
}
|
43
|
+
|
44
|
+
it "evaluates raw value when instantiated" do
|
45
|
+
lazy_eval(5).should == 5
|
46
|
+
end
|
47
|
+
|
48
|
+
it "evaluates raw value" do
|
49
|
+
lazy_eval(5).should == 5
|
50
|
+
end
|
51
|
+
|
52
|
+
it "evaluates value" do
|
53
|
+
lazy_eval(lambda { 5 }).should == 5
|
54
|
+
end
|
55
|
+
|
56
|
+
it "evaluates overrides" do
|
57
|
+
lazy_eval(lambda { o1 }, :o1 => 'o1').should == 'o1'
|
58
|
+
end
|
59
|
+
|
60
|
+
it "does not resolve any unknown methods" do
|
61
|
+
expect { lazy_eval(lambda { unknown }) }.to raise_error(NameError)
|
62
|
+
expect { lazy_eval(lambda { m1 }) }.to raise_error(NameError)
|
63
|
+
expect { lazy_eval(lambda { p1 }) }.to raise_error(NameError)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "does not have a parent" do
|
67
|
+
lazy_eval(lambda { parent }).should be_nil
|
68
|
+
end
|
69
|
+
|
70
|
+
it "does not resolve #index" do
|
71
|
+
expect { lazy_eval(lambda { index }) }.to raise_error(NoMethodError)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe BinData::LazyEvaluator, "with one parent" do
|
76
|
+
subject {
|
77
|
+
parent_methods = {:m1 => 'Pm1', :com => 'PmC', :mm => 3}
|
78
|
+
parent_params = {:p1 => 'Pp1', :com => 'PpC'}
|
79
|
+
parent_obj = MockBinDataObject.new(parent_methods, parent_params)
|
80
|
+
|
81
|
+
def parent_obj.echo(a1, a2)
|
82
|
+
[a1, a2]
|
83
|
+
end
|
84
|
+
|
85
|
+
methods = {:m1 => 'm1', :com => 'mC'}
|
86
|
+
params = {:p1 => 'p1', :com => 'pC'}
|
87
|
+
MockBinDataObject.new(methods, params, parent_obj)
|
88
|
+
}
|
89
|
+
|
90
|
+
it "evaluates raw value" do
|
91
|
+
lazy_eval(5).should == 5
|
92
|
+
end
|
93
|
+
|
94
|
+
it "evaluates value" do
|
95
|
+
lazy_eval(lambda { 5 }).should == 5
|
96
|
+
end
|
97
|
+
|
98
|
+
it "evaluates overrides before params" do
|
99
|
+
lazy_eval(lambda { p1 }, :p1 => 'o1').should == 'o1'
|
100
|
+
end
|
101
|
+
|
102
|
+
it "evaluates overrides before methods" do
|
103
|
+
lazy_eval(lambda { m1 }, :m1 => 'o1').should == 'o1'
|
104
|
+
end
|
105
|
+
|
106
|
+
it "does not resolve any unknown methods" do
|
107
|
+
expect { lazy_eval(lambda { unknown }) }.to raise_error(NameError)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "resolves parameters in the parent" do
|
111
|
+
lazy_eval(lambda { p1 }).should == 'Pp1'
|
112
|
+
end
|
113
|
+
|
114
|
+
it "resolves methods in the parent" do
|
115
|
+
lazy_eval(lambda { m1 }).should == 'Pm1'
|
116
|
+
end
|
117
|
+
|
118
|
+
it "invokes methods in the parent" do
|
119
|
+
lazy_eval(lambda { echo(p1, m1) }).should == ['Pp1', 'Pm1']
|
120
|
+
end
|
121
|
+
|
122
|
+
it "resolves parameters in preference to methods in the parent" do
|
123
|
+
lazy_eval(lambda { com }).should == 'PpC'
|
124
|
+
end
|
125
|
+
|
126
|
+
it "has a parent" do
|
127
|
+
lazy_eval(lambda { parent }).should_not be_nil
|
128
|
+
end
|
129
|
+
|
130
|
+
it "does not resolve #index" do
|
131
|
+
expect { lazy_eval(lambda { index }) }.to raise_error(NoMethodError)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe BinData::LazyEvaluator, "with nested parents" do
|
136
|
+
subject {
|
137
|
+
pparent_methods = {:m1 => 'PPm1', :m2 => 'PPm2', :com => 'PPmC'}
|
138
|
+
pparent_params = {:p1 => 'PPp1', :p2 => 'PPp2', :com => 'PPpC'}
|
139
|
+
pparent_obj = MockBinDataObject.new(pparent_methods, pparent_params)
|
140
|
+
|
141
|
+
def pparent_obj.echo(arg)
|
142
|
+
["PP", arg]
|
143
|
+
end
|
144
|
+
|
145
|
+
def pparent_obj.echo2(arg)
|
146
|
+
["PP2", arg]
|
147
|
+
end
|
148
|
+
|
149
|
+
parent_methods = {:m1 => 'Pm1', :com => 'PmC', :sym1 => :m2, :sym2 => lambda { m2 }}
|
150
|
+
parent_params = {:p1 => 'Pp1', :com => 'PpC'}
|
151
|
+
parent_obj = MockBinDataObject.new(parent_methods, parent_params, pparent_obj)
|
152
|
+
|
153
|
+
def parent_obj.echo(arg)
|
154
|
+
["P", arg]
|
155
|
+
end
|
156
|
+
|
157
|
+
methods = {:m1 => 'm1', :com => 'mC'}
|
158
|
+
params = {:p1 => 'p1', :com => 'pC'}
|
159
|
+
MockBinDataObject.new(methods, params, parent_obj)
|
160
|
+
}
|
161
|
+
|
162
|
+
it "accepts symbols as a shortcut to lambdas" do
|
163
|
+
lazy_eval(:p1).should == 'Pp1'
|
164
|
+
lazy_eval(:p2).should == 'PPp2'
|
165
|
+
lazy_eval(:m1).should == 'Pm1'
|
166
|
+
lazy_eval(:m2).should == 'PPm2'
|
167
|
+
end
|
168
|
+
|
169
|
+
it "does not resolve any unknown methods" do
|
170
|
+
expect { lazy_eval(lambda { unknown }) }.to raise_error(NameError)
|
171
|
+
end
|
172
|
+
|
173
|
+
it "resolves parameters in the parent" do
|
174
|
+
lazy_eval(lambda { p1 }).should == 'Pp1'
|
175
|
+
end
|
176
|
+
|
177
|
+
it "resolves methods in the parent" do
|
178
|
+
lazy_eval(lambda { m1 }).should == 'Pm1'
|
179
|
+
end
|
180
|
+
|
181
|
+
it "resolves parameters in the parent's parent" do
|
182
|
+
lazy_eval(lambda { p2 }).should == 'PPp2'
|
183
|
+
end
|
184
|
+
|
185
|
+
it "resolves methods in the parent's parent" do
|
186
|
+
lazy_eval(lambda { m2 }).should == 'PPm2'
|
187
|
+
end
|
188
|
+
|
189
|
+
it "invokes methods in the parent" do
|
190
|
+
lazy_eval(lambda { echo(m1) }).should == ['P', 'Pm1']
|
191
|
+
end
|
192
|
+
|
193
|
+
it "invokes methods in the parent's parent" do
|
194
|
+
lazy_eval(lambda { parent.echo(m1) }, { :m1 => 'o1'}).should == ['PP', 'o1']
|
195
|
+
end
|
196
|
+
|
197
|
+
it "invokes methods in the parent's parent" do
|
198
|
+
lazy_eval(lambda { echo2(m1) }).should == ['PP2', 'Pm1']
|
199
|
+
end
|
200
|
+
|
201
|
+
it "resolves parameters in preference to methods in the parent" do
|
202
|
+
lazy_eval(lambda { com }).should == 'PpC'
|
203
|
+
end
|
204
|
+
|
205
|
+
it "resolves methods in the parent explicitly" do
|
206
|
+
lazy_eval(lambda { parent.m1 }).should == 'PPm1'
|
207
|
+
end
|
208
|
+
|
209
|
+
it "cascades lambdas " do
|
210
|
+
lazy_eval(lambda { sym1 }).should == 'PPm2'
|
211
|
+
lazy_eval(lambda { sym2 }).should == 'PPm2'
|
212
|
+
end
|
213
|
+
|
214
|
+
it "does not resolve #index" do
|
215
|
+
expect { lazy_eval(lambda { index }) }.to raise_error(NoMethodError)
|
216
|
+
end
|
217
|
+
end
|