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.
Files changed (71) hide show
  1. data/.gitignore +1 -0
  2. data/BSDL +22 -0
  3. data/COPYING +52 -0
  4. data/ChangeLog.rdoc +204 -0
  5. data/Gemfile +2 -0
  6. data/INSTALL +11 -0
  7. data/NEWS.rdoc +164 -0
  8. data/README.md +54 -0
  9. data/Rakefile +13 -0
  10. data/bindata.gemspec +31 -0
  11. data/doc/manual.haml +407 -0
  12. data/doc/manual.md +1649 -0
  13. data/examples/NBT.txt +149 -0
  14. data/examples/gzip.rb +161 -0
  15. data/examples/ip_address.rb +22 -0
  16. data/examples/list.rb +124 -0
  17. data/examples/nbt.rb +178 -0
  18. data/lib/bindata.rb +33 -0
  19. data/lib/bindata/alignment.rb +83 -0
  20. data/lib/bindata/array.rb +335 -0
  21. data/lib/bindata/base.rb +388 -0
  22. data/lib/bindata/base_primitive.rb +214 -0
  23. data/lib/bindata/bits.rb +87 -0
  24. data/lib/bindata/choice.rb +216 -0
  25. data/lib/bindata/count_bytes_remaining.rb +35 -0
  26. data/lib/bindata/deprecated.rb +50 -0
  27. data/lib/bindata/dsl.rb +312 -0
  28. data/lib/bindata/float.rb +80 -0
  29. data/lib/bindata/int.rb +184 -0
  30. data/lib/bindata/io.rb +274 -0
  31. data/lib/bindata/lazy.rb +105 -0
  32. data/lib/bindata/offset.rb +91 -0
  33. data/lib/bindata/params.rb +135 -0
  34. data/lib/bindata/primitive.rb +135 -0
  35. data/lib/bindata/record.rb +110 -0
  36. data/lib/bindata/registry.rb +92 -0
  37. data/lib/bindata/rest.rb +35 -0
  38. data/lib/bindata/sanitize.rb +290 -0
  39. data/lib/bindata/skip.rb +48 -0
  40. data/lib/bindata/string.rb +145 -0
  41. data/lib/bindata/stringz.rb +96 -0
  42. data/lib/bindata/struct.rb +388 -0
  43. data/lib/bindata/trace.rb +94 -0
  44. data/lib/bindata/version.rb +3 -0
  45. data/setup.rb +1585 -0
  46. data/spec/alignment_spec.rb +61 -0
  47. data/spec/array_spec.rb +331 -0
  48. data/spec/base_primitive_spec.rb +238 -0
  49. data/spec/base_spec.rb +376 -0
  50. data/spec/bits_spec.rb +163 -0
  51. data/spec/choice_spec.rb +263 -0
  52. data/spec/count_bytes_remaining_spec.rb +38 -0
  53. data/spec/deprecated_spec.rb +31 -0
  54. data/spec/example.rb +21 -0
  55. data/spec/float_spec.rb +37 -0
  56. data/spec/int_spec.rb +216 -0
  57. data/spec/io_spec.rb +352 -0
  58. data/spec/lazy_spec.rb +217 -0
  59. data/spec/primitive_spec.rb +202 -0
  60. data/spec/record_spec.rb +530 -0
  61. data/spec/registry_spec.rb +108 -0
  62. data/spec/rest_spec.rb +26 -0
  63. data/spec/skip_spec.rb +27 -0
  64. data/spec/spec_common.rb +58 -0
  65. data/spec/string_spec.rb +300 -0
  66. data/spec/stringz_spec.rb +118 -0
  67. data/spec/struct_spec.rb +350 -0
  68. data/spec/system_spec.rb +380 -0
  69. data/tasks/manual.rake +36 -0
  70. data/tasks/rspec.rake +17 -0
  71. metadata +208 -0
@@ -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
@@ -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