evilr 1.0.0-x86-mingw32
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/MIT-LICENSE +19 -0
- data/README.rdoc +148 -0
- data/Rakefile +41 -0
- data/ext/evilr/evilr.c +993 -0
- data/ext/evilr/extconf.rb +7 -0
- data/lib/1.8/evilr.so +0 -0
- data/lib/1.9/evilr.so +0 -0
- data/lib/evilr.rb +1 -0
- data/spec/evilr_spec.rb +1157 -0
- metadata +88 -0
@@ -0,0 +1,7 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
$CFLAGS << " -DRUBY19" if RUBY_VERSION >= '1.9.0'
|
3
|
+
$CFLAGS << " -Wall " unless RUBY_PLATFORM =~ /solaris/
|
4
|
+
$CFLAGS << ' -g -ggdb -O0 -DDEBUG' if ENV['DEBUG']
|
5
|
+
$CFLAGS << " -Wconversion -Wsign-compare -Wno-unused-parameter -Wwrite-strings -Wpointer-arith -fno-common -pedantic -Wno-long-long" if ENV['STRICT']
|
6
|
+
$CFLAGS << (ENV['CFLAGS'] || '')
|
7
|
+
create_makefile("evilr")
|
data/lib/1.8/evilr.so
ADDED
Binary file
|
data/lib/1.9/evilr.so
ADDED
Binary file
|
data/lib/evilr.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "#{RUBY_VERSION[0...3]}/evilr"
|
data/spec/evilr_spec.rb
ADDED
@@ -0,0 +1,1157 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(File.dirname(File.expand_path(__FILE__)))), 'lib')
|
2
|
+
require 'evilr'
|
3
|
+
|
4
|
+
describe "" do
|
5
|
+
after{GC.start} # GC after spec to make sure nothing broke
|
6
|
+
|
7
|
+
describe "Proc#self" do
|
8
|
+
specify "should be the object the proc will call methods on by default" do
|
9
|
+
c = Class.new
|
10
|
+
c.class_eval{proc{}}.self.should == c
|
11
|
+
c.instance_eval{proc{}}.self.should == c
|
12
|
+
o = c.new
|
13
|
+
o.instance_eval{proc{}}.self.should == o
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "Proc#self=" do
|
18
|
+
specify "should change the object the proc will call methods on by default" do
|
19
|
+
o1 = Object.new
|
20
|
+
o2 = Object.new
|
21
|
+
pr1 = o1.instance_eval{def a() 1 end; proc{a}}
|
22
|
+
pr2 = o2.instance_eval{def a() 2 end; proc{a}}
|
23
|
+
pr1.call.should == 1
|
24
|
+
pr2.call.should == 2
|
25
|
+
pr1.self = o2
|
26
|
+
pr2.self = o1
|
27
|
+
pr1.call.should == 2
|
28
|
+
pr2.call.should == 1
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "UnboundMethod#force_bind" do
|
33
|
+
specify "should make the method bindable to another object even if the class differs" do
|
34
|
+
c = Class.new{def a() self.class end}
|
35
|
+
um = c.instance_method(:a)
|
36
|
+
c2 = Class.new
|
37
|
+
o = c2.new
|
38
|
+
proc{um.bind(o)}.should raise_error(TypeError)
|
39
|
+
m = um.force_bind(o)
|
40
|
+
m.should be_a_kind_of(Method)
|
41
|
+
m.call.should == c2
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "Object#class=" do
|
46
|
+
before do
|
47
|
+
@o = Class.new.new
|
48
|
+
@c = Class.new
|
49
|
+
end
|
50
|
+
|
51
|
+
specify "should make given object this object's class" do
|
52
|
+
@o.should_not be_a_kind_of(@c)
|
53
|
+
@o.class = @c
|
54
|
+
@o.should be_a_kind_of(@c)
|
55
|
+
end
|
56
|
+
|
57
|
+
specify "should raise an exception for immediate objects" do
|
58
|
+
[0, :a, true, false, nil].each do |x|
|
59
|
+
proc{x.class = @c}.should raise_error(TypeError)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
specify "should raise an exception if a class is not used as an argument" do
|
64
|
+
proc{@o.class = @o}.should raise_error(TypeError)
|
65
|
+
end
|
66
|
+
|
67
|
+
specify "should raise an exception if a class used is not the same underlying type" do
|
68
|
+
proc{@o.class = Hash}.should raise_error(TypeError)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "Object#dup_singleton_class" do
|
73
|
+
specify "should raise an exception for immediate values" do
|
74
|
+
proc{nil.dup_singleton_class}.should raise_error(TypeError)
|
75
|
+
end
|
76
|
+
|
77
|
+
specify "should return nil if the object has no singleton class" do
|
78
|
+
Object.new.dup_singleton_class.should == nil
|
79
|
+
end
|
80
|
+
|
81
|
+
specify "should return a copy of the singleton class as a non-singleton class" do
|
82
|
+
o = Object.new
|
83
|
+
o.instance_eval{def a() 1 end}
|
84
|
+
o.dup_singleton_class.new.a.should == 1
|
85
|
+
end
|
86
|
+
|
87
|
+
specify "should make the given class a subclass of Object by default" do
|
88
|
+
o = Object.new
|
89
|
+
o.instance_eval{def a() 1 end}
|
90
|
+
o.dup_singleton_class.superclass.should == Object
|
91
|
+
end
|
92
|
+
|
93
|
+
specify "should accept a class argument to make the dup a subclass of" do
|
94
|
+
o = Object.new
|
95
|
+
o.instance_eval{def a() 1 end}
|
96
|
+
c = Class.new
|
97
|
+
o.dup_singleton_class(c).superclass.should == c
|
98
|
+
end
|
99
|
+
|
100
|
+
specify "should handle extended modules by making them included modules in the class" do
|
101
|
+
o = Object.new
|
102
|
+
o.instance_eval{def a() [1] + super end}
|
103
|
+
o.extend(Module.new{def a() [2] + super end})
|
104
|
+
c = Class.new{def a() [4] + super end; include Module.new{def a() [8] end}}
|
105
|
+
o.dup_singleton_class(c).new.a.should == [1, 2, 4, 8]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe "Object\#{push,pop}_singleton_class" do
|
110
|
+
specify "both should raise an exception for immediate values" do
|
111
|
+
proc{nil.push_singleton_class(Class.new)}.should raise_error(TypeError)
|
112
|
+
proc{nil.pop_singleton_class}.should raise_error(TypeError)
|
113
|
+
end
|
114
|
+
|
115
|
+
specify "push_singleton_class should raise an exception if a class is not given" do
|
116
|
+
proc{{}.push_singleton_class(Object.new)}.should raise_error(TypeError)
|
117
|
+
end
|
118
|
+
|
119
|
+
specify "both should return the class" do
|
120
|
+
c = Class.new
|
121
|
+
o = {}
|
122
|
+
o.push_singleton_class(c).should == c
|
123
|
+
o.pop_singleton_class.should == c
|
124
|
+
end
|
125
|
+
|
126
|
+
specify "pop_singleton_class should return nil if no singleton class exists" do
|
127
|
+
{}.pop_singleton_class.should == nil
|
128
|
+
end
|
129
|
+
|
130
|
+
specify "should add and remove singleton classes" do
|
131
|
+
o = Class.new{def a() [1] end}.new
|
132
|
+
o.a.should == [1]
|
133
|
+
o.push_singleton_class(Class.new{def a() [2] + super end})
|
134
|
+
o.a.should == [2, 1]
|
135
|
+
o.push_singleton_class(Class.new{def a() [4] + super end})
|
136
|
+
o.a.should == [4, 2, 1]
|
137
|
+
o.push_singleton_class(Class.new{def a() [8] + super end})
|
138
|
+
o.a.should == [8, 4, 2, 1]
|
139
|
+
o.pop_singleton_class
|
140
|
+
o.a.should == [4, 2, 1]
|
141
|
+
o.push_singleton_class(Class.new{def a() [16] + super end})
|
142
|
+
o.a.should == [16, 4, 2, 1]
|
143
|
+
o.pop_singleton_class
|
144
|
+
o.a.should == [4, 2, 1]
|
145
|
+
o.pop_singleton_class
|
146
|
+
o.a.should == [2, 1]
|
147
|
+
o.pop_singleton_class
|
148
|
+
o.a.should == [1]
|
149
|
+
end
|
150
|
+
|
151
|
+
specify "should handle modules included in the classes" do
|
152
|
+
o = Class.new{def a() [1] end}.new
|
153
|
+
o.a.should == [1]
|
154
|
+
o.push_singleton_class(Class.new{def a() [2] + super end; include Module.new{def a() [32] + super end}})
|
155
|
+
o.a.should == [2, 32, 1]
|
156
|
+
o.push_singleton_class(Class.new{def a() [4] + super end; include Module.new{def a() [64] + super end}})
|
157
|
+
o.a.should == [4, 64, 2, 32, 1]
|
158
|
+
o.push_singleton_class(Class.new{def a() [8] + super end; include Module.new{def a() [128] + super end}})
|
159
|
+
o.a.should == [8, 128, 4, 64, 2, 32, 1]
|
160
|
+
o.pop_singleton_class
|
161
|
+
o.a.should == [4, 64, 2, 32, 1]
|
162
|
+
o.push_singleton_class(Class.new{def a() [16] + super end; include Module.new{def a() [256] + super end}})
|
163
|
+
o.a.should == [16, 256, 4, 64, 2, 32, 1]
|
164
|
+
o.pop_singleton_class
|
165
|
+
o.a.should == [4, 64, 2, 32, 1]
|
166
|
+
o.pop_singleton_class
|
167
|
+
o.a.should == [2, 32, 1]
|
168
|
+
o.pop_singleton_class
|
169
|
+
o.a.should == [1]
|
170
|
+
end
|
171
|
+
|
172
|
+
specify "pop_singleton_class should have no effect if the object has no singleton class" do
|
173
|
+
o = Class.new{def a() [1] end}.new
|
174
|
+
o.pop_singleton_class
|
175
|
+
o.a.should == [1]
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe "Objec#remove_singleton_classes" do
|
180
|
+
specify "should raise an exception for immediate values" do
|
181
|
+
proc{nil.remove_singleton_classes}.should raise_error(TypeError)
|
182
|
+
end
|
183
|
+
|
184
|
+
specify "should return nil" do
|
185
|
+
{}.remove_singleton_classes.should == nil
|
186
|
+
end
|
187
|
+
|
188
|
+
specify "should add and remove singleton classes" do
|
189
|
+
o = Class.new{def a() [1] end}.new
|
190
|
+
o.a.should == [1]
|
191
|
+
o.push_singleton_class(Class.new{def a() [2] + super end})
|
192
|
+
o.a.should == [2, 1]
|
193
|
+
o.push_singleton_class(Class.new{def a() [4] + super end})
|
194
|
+
o.a.should == [4, 2, 1]
|
195
|
+
o.push_singleton_class(Class.new{def a() [8] + super end})
|
196
|
+
o.a.should == [8, 4, 2, 1]
|
197
|
+
o.remove_singleton_classes
|
198
|
+
o.a.should == [1]
|
199
|
+
end
|
200
|
+
|
201
|
+
specify "should handle modules included in the classes" do
|
202
|
+
o = Class.new{def a() [1] end}.new
|
203
|
+
o.a.should == [1]
|
204
|
+
o.push_singleton_class(Class.new{def a() [2] + super end; include Module.new{def a() [32] + super end}})
|
205
|
+
o.a.should == [2, 32, 1]
|
206
|
+
o.push_singleton_class(Class.new{def a() [4] + super end; include Module.new{def a() [64] + super end}})
|
207
|
+
o.a.should == [4, 64, 2, 32, 1]
|
208
|
+
o.push_singleton_class(Class.new{def a() [8] + super end; include Module.new{def a() [128] + super end}})
|
209
|
+
o.a.should == [8, 128, 4, 64, 2, 32, 1]
|
210
|
+
o.remove_singleton_classes
|
211
|
+
o.a.should == [1]
|
212
|
+
end
|
213
|
+
|
214
|
+
specify "should have no effect if the object has no singleton classes" do
|
215
|
+
o = Class.new{def a() [1] end}.new
|
216
|
+
o.remove_singleton_classes
|
217
|
+
o.a.should == [1]
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe "Object#swap_singleton_class" do
|
222
|
+
before do
|
223
|
+
@o1 = Class.new.new
|
224
|
+
@o2 = Class.new.new
|
225
|
+
end
|
226
|
+
|
227
|
+
specify "should swap singleton class with argument" do
|
228
|
+
def @o2.a; 1; end
|
229
|
+
def @o1.b; 2; end
|
230
|
+
@o1.swap_singleton_class(@o2)
|
231
|
+
@o1.a.should == 1
|
232
|
+
@o2.b.should == 2
|
233
|
+
proc{@o1.b}.should raise_error(NoMethodError)
|
234
|
+
proc{@o2.a}.should raise_error(NoMethodError)
|
235
|
+
|
236
|
+
def @o2.c; 3; end
|
237
|
+
def @o1.d; 4; end
|
238
|
+
@o2.c.should == 3
|
239
|
+
@o1.d.should == 4
|
240
|
+
proc{@o2.d}.should raise_error(NoMethodError)
|
241
|
+
proc{@o1.c}.should raise_error(NoMethodError)
|
242
|
+
end
|
243
|
+
|
244
|
+
specify "should handle singleton classes that don't exist" do
|
245
|
+
@o2.swap_singleton_class(@o1)
|
246
|
+
def @o2.c; 3; end
|
247
|
+
def @o1.d; 4; end
|
248
|
+
@o2.c.should == 3
|
249
|
+
@o1.d.should == 4
|
250
|
+
proc{@o2.d}.should raise_error(NoMethodError)
|
251
|
+
proc{@o1.c}.should raise_error(NoMethodError)
|
252
|
+
end
|
253
|
+
|
254
|
+
specify "should raise an exception for immediate objects" do
|
255
|
+
[0, :a, true, false, nil].each do |x|
|
256
|
+
proc{x.swap_singleton_class(@o2)}.should raise_error(TypeError)
|
257
|
+
proc{@o1.swap_singleton_class(x)}.should raise_error(TypeError)
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
specify "should return self" do
|
262
|
+
@o2.swap_singleton_class(@o1).should equal(@o2)
|
263
|
+
end
|
264
|
+
|
265
|
+
specify "should keep existing class hierarchy the same, other than the singleton classes" do
|
266
|
+
oc1 = Class.new
|
267
|
+
oc2 = Class.new
|
268
|
+
o1 = oc1.new
|
269
|
+
o2 = oc2.new
|
270
|
+
o1.swap_singleton_class(o2)
|
271
|
+
o1.class.should == oc1
|
272
|
+
o2.class.should == oc2
|
273
|
+
end
|
274
|
+
|
275
|
+
specify "should also swap modules that extend the class" do
|
276
|
+
oc1 = Class.new{def a() [16] end}
|
277
|
+
oc2 = Class.new{def a() [32] end}
|
278
|
+
o1 = oc1.new
|
279
|
+
o2 = oc2.new
|
280
|
+
o1.instance_eval{def a() [1] + super end; extend Module.new{def a() [2] + super end}}
|
281
|
+
o2.instance_eval{def a() [4] + super end; extend Module.new{def a() [8] + super end}}
|
282
|
+
o1.swap_singleton_class(o2)
|
283
|
+
o1.a.should == [4, 8, 16]
|
284
|
+
o2.a.should == [1, 2, 32]
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
describe "Object#unfreeze" do
|
289
|
+
before do
|
290
|
+
@o = Object.new
|
291
|
+
@o.freeze
|
292
|
+
end
|
293
|
+
|
294
|
+
specify "should unfreeze object" do
|
295
|
+
@o.unfreeze
|
296
|
+
@o.frozen?.should == false
|
297
|
+
@o.instance_variable_set(:@a, 1)
|
298
|
+
@o.instance_variable_get(:@a).should == 1
|
299
|
+
end
|
300
|
+
|
301
|
+
specify "should be idempotent" do
|
302
|
+
@o.frozen?.should == true
|
303
|
+
@o.unfreeze
|
304
|
+
@o.frozen?.should == false
|
305
|
+
@o.unfreeze
|
306
|
+
@o.frozen?.should == false
|
307
|
+
@o.instance_variable_set(:@a, 1)
|
308
|
+
@o.instance_variable_get(:@a).should == 1
|
309
|
+
end
|
310
|
+
|
311
|
+
specify "should be no-op for immediate objects" do
|
312
|
+
[0, :a, true, false, nil].each do |x|
|
313
|
+
proc{x.unfreeze}.should_not raise_error
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
specify "should not be allowed if $SAFE > 0" do
|
318
|
+
x = @o
|
319
|
+
Thread.new do
|
320
|
+
$SAFE = 1
|
321
|
+
proc{x.unfreeze}.should raise_error(SecurityError)
|
322
|
+
end.join
|
323
|
+
end
|
324
|
+
|
325
|
+
specify "should return self" do
|
326
|
+
@o.unfreeze.should equal(@o)
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
describe "Kernel#set_safe_level" do
|
331
|
+
specify "should allow the lowering of the $SAFE level" do
|
332
|
+
$SAFE = 1
|
333
|
+
set_safe_level(0)
|
334
|
+
$SAFE.should == 0
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
describe "Module#to_class" do
|
339
|
+
specify "should return the module in class form" do
|
340
|
+
Module.new{def a() 1 end}.to_class.new.a.should == 1
|
341
|
+
end
|
342
|
+
|
343
|
+
specify "should accept an optional argument for the new class type" do
|
344
|
+
Module.new{def a() 1 end}.to_class(Object).new.a.should == 1
|
345
|
+
Module.new{def a() super + 2 end}.to_class(Class.new{def a() 1 end}).new.a.should == 3
|
346
|
+
end
|
347
|
+
|
348
|
+
specify "should raise exception if attempting to instantiate a builtin class other than Object" do
|
349
|
+
proc{Module.new.to_class(Hash)}.should raise_error(TypeError)
|
350
|
+
proc{Module.new.to_class(Array)}.should raise_error(TypeError)
|
351
|
+
proc{Module.new.to_class(String)}.should raise_error(TypeError)
|
352
|
+
end
|
353
|
+
|
354
|
+
specify "should return copy of self (possibly reparented) if already a class" do
|
355
|
+
Class.new{def a() 1 end}.to_class.new.a.should == 1
|
356
|
+
Class.new{def a() 1 end}.to_class(Object).new.a.should == 1
|
357
|
+
Class.new{def a() super + 2 end}.to_class(Class.new{def a() 1 end}).new.a.should == 3
|
358
|
+
|
359
|
+
osc = Class.new
|
360
|
+
c = Class.new(osc)
|
361
|
+
sc = Class.new
|
362
|
+
c.to_class(sc).superclass.should == sc
|
363
|
+
c.superclass.should == osc
|
364
|
+
end
|
365
|
+
|
366
|
+
specify "should use Object as the default superclass" do
|
367
|
+
Module.new.to_class.superclass.should == Object
|
368
|
+
end
|
369
|
+
|
370
|
+
specify "should use given class as the superclass" do
|
371
|
+
c = Class.new
|
372
|
+
Module.new.to_class(c).superclass.should == c
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
describe "Class#to_module" do
|
377
|
+
specify "should return the class in module form" do
|
378
|
+
c = Class.new{def a() 1 end}
|
379
|
+
Class.new{include c.to_module}.new.a.should == 1
|
380
|
+
end
|
381
|
+
|
382
|
+
specify "should not modify the class's superclass" do
|
383
|
+
c = Class.new{def a() [1] end}
|
384
|
+
sc = Class.new(c){def a() [2] + (super rescue [0]) end}
|
385
|
+
Class.new{include sc.to_module}.new.a.should == [2, 0]
|
386
|
+
sc.superclass.should == c
|
387
|
+
sc.new.a.should == [2, 1]
|
388
|
+
end
|
389
|
+
|
390
|
+
specify "should not modify the class's superclass if modules are included" do
|
391
|
+
c = Class.new{def a() [1] end}
|
392
|
+
sc = Class.new(c){def a() [2] + (super rescue [0]) end; include Module.new}
|
393
|
+
Class.new{include sc.to_module}.new.a.should == [2, 0]
|
394
|
+
sc.superclass.should == c
|
395
|
+
sc.new.a.should == [2, 1]
|
396
|
+
end
|
397
|
+
|
398
|
+
specify "should handle the order of multiple included modules correctly" do
|
399
|
+
c = Class.new{def a() [1] end}
|
400
|
+
sc = Class.new(c){def a() [2] + (super rescue [0]) end}
|
401
|
+
sc.send :include, Module.new{def a() [4] + (super rescue [0]) end}
|
402
|
+
sc.send :include, Module.new{def a() [8] + (super rescue [0]) end}
|
403
|
+
Class.new{include sc.to_module}.new.a.should == [2, 8, 4, 0]
|
404
|
+
sc.superclass.should == c
|
405
|
+
sc.new.a.should == [2, 8, 4, 1]
|
406
|
+
end
|
407
|
+
|
408
|
+
specify "should handle singleton classes without modifying them" do
|
409
|
+
o = Object.new
|
410
|
+
o.instance_eval{def a() 1 end}
|
411
|
+
Class.new{include((class << o; self; end).to_module)}.new.a.should == 1
|
412
|
+
o.instance_eval{def a() super end}
|
413
|
+
proc{o.a}.should raise_error(NoMethodError)
|
414
|
+
end
|
415
|
+
|
416
|
+
specify "should handle singleton classes without modifying them if modules are included" do
|
417
|
+
o = Object.new
|
418
|
+
o.instance_eval{def a() 1 end}
|
419
|
+
o.extend Module.new
|
420
|
+
Class.new{include((class << o; self; end).to_module)}.new.a.should == 1
|
421
|
+
o.instance_eval{def a() super end}
|
422
|
+
proc{o.a}.should raise_error(NoMethodError)
|
423
|
+
end
|
424
|
+
|
425
|
+
specify "should include modules included in class" do
|
426
|
+
c = Class.new{def a() [1] + super end; include Module.new{def a() [2] + (super rescue [0]) end}}
|
427
|
+
Class.new{def a() [4] + super end; include c.to_module}.new.a.should == [4, 1, 2, 0]
|
428
|
+
end
|
429
|
+
|
430
|
+
specify "should not include superclass or modules included in superclass" do
|
431
|
+
c = Class.new{def a() [1] + super end; include Module.new{def a() [2] end}}
|
432
|
+
sc = Class.new(c){def a() [4] + super end; include Module.new{def a() [8] + (super rescue [0]) end}}
|
433
|
+
Class.new{def a() [16] + super end; include sc.to_module}.new.a.should == [16, 4, 8, 0]
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
describe "Class#detach_singleton" do
|
438
|
+
specify "should be a no-op on a non-singleton class" do
|
439
|
+
Class.new{def a() 1 end}.detach_singleton.new.a.should == 1
|
440
|
+
end
|
441
|
+
|
442
|
+
specify "should detach singleton class from object" do
|
443
|
+
o = Object.new
|
444
|
+
o.instance_eval{def a() 1 end}
|
445
|
+
sc = (class << o; self; end)
|
446
|
+
sc.detach_singleton.singleton_class_instance.should == nil
|
447
|
+
end
|
448
|
+
|
449
|
+
specify "should allow another singleton class to be created" do
|
450
|
+
o = Object.new
|
451
|
+
o.instance_eval{def a() 1 end}
|
452
|
+
sc = (class << o; self; end)
|
453
|
+
sc.detach_singleton
|
454
|
+
o.instance_eval{def a() super + 2 end}
|
455
|
+
o.a.should == 3
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
describe "Object#set_singleton_class" do
|
460
|
+
specify "should raise an exception for immediate values" do
|
461
|
+
proc{nil.set_singleton_class(Class.new)}.should raise_error(TypeError)
|
462
|
+
end
|
463
|
+
|
464
|
+
specify "should raise an exception for non-class arguments" do
|
465
|
+
proc{Object.new.set_singleton_class(Object.new)}.should raise_error(TypeError)
|
466
|
+
end
|
467
|
+
|
468
|
+
specify "should return the class" do
|
469
|
+
c = Class.new
|
470
|
+
Object.new.set_singleton_class(c).should == c
|
471
|
+
end
|
472
|
+
|
473
|
+
specify "should make object the new singleton class's instance" do
|
474
|
+
o = Object.new
|
475
|
+
o.set_singleton_class(Class.new).singleton_class_instance.should == o
|
476
|
+
end
|
477
|
+
|
478
|
+
specify "should make class the object's singleton class" do
|
479
|
+
o = Object.new
|
480
|
+
c = Class.new{def a() 1 end}
|
481
|
+
o.set_singleton_class(c)
|
482
|
+
(class << o; self; end).should == c
|
483
|
+
o.a.should == 1
|
484
|
+
end
|
485
|
+
|
486
|
+
specify "should replace an existing singleton class" do
|
487
|
+
o = Object.new
|
488
|
+
o.instance_eval{def a() 3 end}
|
489
|
+
c = Class.new{def a() 1 + (super rescue 10) end}
|
490
|
+
o.set_singleton_class(c)
|
491
|
+
o.a.should == 11
|
492
|
+
end
|
493
|
+
|
494
|
+
specify "should remove any modules currently extending the class" do
|
495
|
+
o = Object.new
|
496
|
+
o.instance_eval{def a() 3 end}
|
497
|
+
o.extend(Module.new{def a() 4 end})
|
498
|
+
c = Class.new{def a() 1 + (super rescue 10) end}
|
499
|
+
o.set_singleton_class(c)
|
500
|
+
o.a.should == 11
|
501
|
+
end
|
502
|
+
|
503
|
+
specify "should keep any existing class" do
|
504
|
+
oc = Class.new
|
505
|
+
o = oc.new
|
506
|
+
c = Class.new
|
507
|
+
sc = Class.new(c)
|
508
|
+
o.set_singleton_class(sc)
|
509
|
+
o.class.should == oc
|
510
|
+
end
|
511
|
+
|
512
|
+
specify "should make modules included in class as modules that extend the new class" do
|
513
|
+
oc = Class.new{def a() [1] end}
|
514
|
+
o = oc.new
|
515
|
+
c = Class.new{def a() [2] + super end}
|
516
|
+
sc = Class.new(c){def a() [4] + super end; include Module.new{def a() [8] + super end}}
|
517
|
+
o.set_singleton_class(sc)
|
518
|
+
o.a.should == [4, 8, 1]
|
519
|
+
end
|
520
|
+
end
|
521
|
+
|
522
|
+
describe "Object#swap" do
|
523
|
+
specify "should raise an exception for immediate values" do
|
524
|
+
proc{nil.swap(Object.new)}.should raise_error(TypeError)
|
525
|
+
proc{Object.new.swap(nil)}.should raise_error(TypeError)
|
526
|
+
end
|
527
|
+
|
528
|
+
specify "should raise an exception for swapping a class with a non-class value" do
|
529
|
+
proc{Object.new.swap(Class.new)}.should raise_error(TypeError)
|
530
|
+
proc{Class.new.swap(Object.new)}.should raise_error(TypeError)
|
531
|
+
proc{Class.new.swap(Module.new)}.should raise_error(TypeError)
|
532
|
+
end
|
533
|
+
|
534
|
+
specify "should raise an exception for swapping a module with a non-module value" do
|
535
|
+
proc{Object.new.swap(Module.new)}.should raise_error(TypeError)
|
536
|
+
proc{Module.new.swap(Object.new)}.should raise_error(TypeError)
|
537
|
+
proc{Module.new.swap(Class.new)}.should raise_error(TypeError)
|
538
|
+
end
|
539
|
+
|
540
|
+
specify "should swap the objects' classes, singleton classes, and instance variables" do
|
541
|
+
c1 = Class.new{attr_accessor :b; def a() 1 end}
|
542
|
+
c2 = Class.new{attr_accessor :b; def a() 2 end}
|
543
|
+
o1 = c1.new
|
544
|
+
o2 = c2.new
|
545
|
+
o1.instance_eval{def a() 4 + super end}
|
546
|
+
o2.instance_eval{def a() 8 + super end}
|
547
|
+
o1.b = 3
|
548
|
+
o2.b = 4
|
549
|
+
o1.swap(o2)
|
550
|
+
o1.b.should == 4
|
551
|
+
o1.a.should == 10
|
552
|
+
o1.class.should == c2
|
553
|
+
o2.b.should == 3
|
554
|
+
o2.a.should == 5
|
555
|
+
o2.class.should == c1
|
556
|
+
end
|
557
|
+
|
558
|
+
specify "should work for classes" do
|
559
|
+
c1 = Class.new{def a() 1 end}
|
560
|
+
c2 = Class.new{def a() 2 end}
|
561
|
+
c1.instance_eval{@a = 16; def a() 4 end}
|
562
|
+
c2.instance_eval{@a = 32; def a() 8 end}
|
563
|
+
c1.swap(c2)
|
564
|
+
c1.a.should == 8
|
565
|
+
c2.a.should == 4
|
566
|
+
c1.instance_eval{@a.should == 32}
|
567
|
+
c2.instance_eval{@a.should == 16}
|
568
|
+
c1.new.a.should == 2
|
569
|
+
c2.new.a.should == 1
|
570
|
+
end
|
571
|
+
|
572
|
+
specify "should work for different types of objects" do
|
573
|
+
a = {}
|
574
|
+
b = []
|
575
|
+
a.swap(b)
|
576
|
+
a.should == []
|
577
|
+
b.should == {}
|
578
|
+
end
|
579
|
+
|
580
|
+
specify "should return self (the new self)" do
|
581
|
+
o = Object.new
|
582
|
+
i = o.object_id
|
583
|
+
no = o.swap(Class.new{def a() 1 end}.new)
|
584
|
+
no.should == o
|
585
|
+
no.object_id.should == i
|
586
|
+
no.a.should == 1
|
587
|
+
end
|
588
|
+
end
|
589
|
+
|
590
|
+
describe "Object#detach_singleton_class" do
|
591
|
+
specify "should raise an exception for immediate values" do
|
592
|
+
proc{nil.detach_singleton_class}.should raise_error(TypeError)
|
593
|
+
end
|
594
|
+
|
595
|
+
specify "should be a no-op an object without a singleton class" do
|
596
|
+
a = {:a=>1}
|
597
|
+
a.detach_singleton_class
|
598
|
+
a[:a].should == 1
|
599
|
+
end
|
600
|
+
|
601
|
+
specify "should return the class" do
|
602
|
+
Object.new.detach_singleton_class.should == Object
|
603
|
+
o = Object.new
|
604
|
+
sc = (class << o; self; end)
|
605
|
+
o.detach_singleton_class.should == sc
|
606
|
+
end
|
607
|
+
|
608
|
+
specify "should remove singleton status from singleton class" do
|
609
|
+
o = Object.new
|
610
|
+
o.instance_eval{def a() 1 end}
|
611
|
+
o.detach_singleton_class.new.a.should == 1
|
612
|
+
end
|
613
|
+
|
614
|
+
specify "should detach singleton class from object, becoming the object's actual class" do
|
615
|
+
o = Object.new
|
616
|
+
o.instance_eval{def a() 1 end}
|
617
|
+
sc = (class << o; self; end)
|
618
|
+
o.detach_singleton_class
|
619
|
+
o.class.should == sc
|
620
|
+
end
|
621
|
+
|
622
|
+
specify "should have singleton class's methods remain in the method chain" do
|
623
|
+
o = Object.new
|
624
|
+
o.instance_eval{def a() 1 end}
|
625
|
+
o.detach_singleton_class
|
626
|
+
o.instance_eval{def a() super + 2 end}
|
627
|
+
o.a.should == 3
|
628
|
+
end
|
629
|
+
end
|
630
|
+
|
631
|
+
describe "Object#remove_singleton_class" do
|
632
|
+
specify "should raise an exception for immediate values" do
|
633
|
+
proc{nil.remove_singleton_class}.should raise_error(TypeError)
|
634
|
+
end
|
635
|
+
|
636
|
+
specify "should be a no-op an object without a singleton class" do
|
637
|
+
a = {:a=>1}
|
638
|
+
a.remove_singleton_class
|
639
|
+
a[:a].should == 1
|
640
|
+
end
|
641
|
+
|
642
|
+
specify "should return nil if the class does not exist" do
|
643
|
+
Object.new.remove_singleton_class.should == nil
|
644
|
+
end
|
645
|
+
|
646
|
+
specify "should return the class if it exists" do
|
647
|
+
o = Object.new
|
648
|
+
sc = (class << o; self; end)
|
649
|
+
o.remove_singleton_class.should == sc
|
650
|
+
end
|
651
|
+
|
652
|
+
specify "should remove singleton status from singleton class" do
|
653
|
+
o = Object.new
|
654
|
+
o.instance_eval{def a() 1 end}
|
655
|
+
o.remove_singleton_class.new.a.should == 1
|
656
|
+
end
|
657
|
+
|
658
|
+
specify "should remove singleton class from object, restoring the object's original class" do
|
659
|
+
o = Object.new
|
660
|
+
o.instance_eval{def a() 1 end}
|
661
|
+
sc = (class << o; self; end)
|
662
|
+
o.remove_singleton_class
|
663
|
+
o.class.should == Object
|
664
|
+
end
|
665
|
+
|
666
|
+
specify "should have singleton class's methods not remain in the method chain" do
|
667
|
+
o = Object.new
|
668
|
+
o.instance_eval{def a() 1 end}
|
669
|
+
o.remove_singleton_class
|
670
|
+
o.instance_eval{def a() super + 2 end}
|
671
|
+
proc{o.a}.should raise_error(NoMethodError)
|
672
|
+
end
|
673
|
+
|
674
|
+
specify "should handle modules that extend the object" do
|
675
|
+
o = Object.new
|
676
|
+
o.instance_eval{def a() 1 end}
|
677
|
+
o.extend(Module.new{def b() 2 end})
|
678
|
+
o.remove_singleton_class
|
679
|
+
proc{o.a}.should raise_error(NoMethodError)
|
680
|
+
proc{o.b}.should raise_error(NoMethodError)
|
681
|
+
end
|
682
|
+
end
|
683
|
+
|
684
|
+
describe "Class#singleton_class_instance" do
|
685
|
+
specify "should return nil for a non-singleton class" do
|
686
|
+
Class.new.singleton_class_instance.should == nil
|
687
|
+
end
|
688
|
+
|
689
|
+
specify "should return instance attached to singleton class" do
|
690
|
+
o = Object.new.instance_eval{def a() 1 end}
|
691
|
+
(class << o; self; end).singleton_class_instance.should equal(o)
|
692
|
+
end
|
693
|
+
end
|
694
|
+
|
695
|
+
describe "Class#superclass=" do
|
696
|
+
specify "should raise an exception for immediate values" do
|
697
|
+
proc{Class.new.superclass = nil}.should raise_error(TypeError)
|
698
|
+
end
|
699
|
+
|
700
|
+
specify "should raise an exception for non-class arguments" do
|
701
|
+
proc{Class.new.superclass = Object.new}.should raise_error(TypeError)
|
702
|
+
end
|
703
|
+
|
704
|
+
specify "should raise an exception for incompatible types" do
|
705
|
+
proc{Class.new.superclass = String}.should raise_error(TypeError)
|
706
|
+
end
|
707
|
+
|
708
|
+
specify "should change the superclass of the class" do
|
709
|
+
c = Class.new
|
710
|
+
c2 = Class.new
|
711
|
+
c.superclass.should == Object
|
712
|
+
c.superclass = c2
|
713
|
+
c.superclass.should == c2
|
714
|
+
end
|
715
|
+
|
716
|
+
specify "should keep any included modules" do
|
717
|
+
c = Class.new{def a() [1] + super end; include Module.new{def a() [2] + (super rescue [0]) end}}
|
718
|
+
c2 = Class.new{def a() [4] + super end; include Module.new{def a() [8] + (super rescue [0]) end}}
|
719
|
+
c.new.a.should == [1, 2, 0]
|
720
|
+
c2.new.a.should == [4, 8, 0]
|
721
|
+
c.superclass = c2
|
722
|
+
c.new.a.should == [1, 2, 4, 8, 0]
|
723
|
+
end
|
724
|
+
|
725
|
+
specify "should ignore existing superclasses and modules included in them" do
|
726
|
+
c = Class.new{def a() [1] + super end; include Module.new{def a() [2] + (super rescue [0]) end}}
|
727
|
+
c2 = Class.new(c){def a() [4] + super end; include Module.new{def a() [8] + (super rescue [0]) end}}
|
728
|
+
c2.new.a.should == [4, 8, 1, 2, 0]
|
729
|
+
c2.superclass = Object
|
730
|
+
c2.new.a.should == [4, 8, 0]
|
731
|
+
end
|
732
|
+
end
|
733
|
+
|
734
|
+
describe "Class#inherit" do
|
735
|
+
specify "should raise an exception for immediate values" do
|
736
|
+
proc{Class.new.inherit nil}.should raise_error(TypeError)
|
737
|
+
end
|
738
|
+
|
739
|
+
specify "should raise an exception for non-class arguments" do
|
740
|
+
proc{Class.new.inherit Object.new}.should raise_error(TypeError)
|
741
|
+
end
|
742
|
+
|
743
|
+
specify "should raise an exception for incompatible types" do
|
744
|
+
proc{Class.new.inherit String}.should raise_error(TypeError)
|
745
|
+
end
|
746
|
+
|
747
|
+
specify "should include the classes as modules" do
|
748
|
+
c = Class.new{def a() [1] + (super rescue [0]) end}
|
749
|
+
c2 = Class.new{def a() [2] + super end}
|
750
|
+
sc = Class.new{def a() [4] + super end; inherit c, c2}
|
751
|
+
sc.new.a.should == [4, 2, 1, 0]
|
752
|
+
end
|
753
|
+
|
754
|
+
specify "should keep any included modules" do
|
755
|
+
c = Class.new{def a() [1] + super end; include Module.new{def a() [2] + (super rescue [0]) end}}
|
756
|
+
c2 = Class.new{def a() [4] + super end; include Module.new{def a() [8] + (super rescue [0]) end}}
|
757
|
+
sc = Class.new{def a() [16] + super end; inherit c, c2}
|
758
|
+
sc.new.a.should == [16, 4, 8, 1, 2, 0]
|
759
|
+
end
|
760
|
+
|
761
|
+
specify "should ignore superclasses of arguments, and keep superclass of current class" do
|
762
|
+
c = Class.new{def a() [1] + super end; include Module.new{def a() [2] + (super rescue [0]) end}}
|
763
|
+
sc1 = Class.new(c){def a() [4] + super end; include Module.new{def a() [8] + (super rescue [0]) end}}
|
764
|
+
sc2 = Class.new(c){def a() [16] + super end; include Module.new{def a() [32] + (super rescue [0]) end}}
|
765
|
+
Class.new{def a() [64] + super end; inherit sc1, sc2}.new.a.should == [64, 16, 32, 4, 8, 0]
|
766
|
+
Class.new(sc2){def a() [64] + super end; inherit sc1}.new.a.should == [64, 4, 8, 16, 32, 1, 2, 0]
|
767
|
+
Class.new(sc2){def a() [64] + super end; inherit sc1}.superclass.should == sc2
|
768
|
+
end
|
769
|
+
end
|
770
|
+
|
771
|
+
describe "Object#flags" do
|
772
|
+
specify "should raise an exception for immediate values" do
|
773
|
+
proc{nil.flags}.should raise_error(TypeError)
|
774
|
+
end
|
775
|
+
|
776
|
+
specify "should return a Fixnum" do
|
777
|
+
Object.new.flags.should be_a_kind_of(Fixnum)
|
778
|
+
Class.new.flags.should be_a_kind_of(Fixnum)
|
779
|
+
Module.new.flags.should be_a_kind_of(Fixnum)
|
780
|
+
Object.new.flags.should_not == Class.new.flags
|
781
|
+
Module.new.flags.should_not == Class.new.flags
|
782
|
+
end
|
783
|
+
end
|
784
|
+
|
785
|
+
describe "Object#swap_instance_variables" do
|
786
|
+
specify "should raise an exception for immediate values" do
|
787
|
+
proc{nil.swap_instance_variables(Object.new)}.should raise_error(TypeError)
|
788
|
+
proc{Object.new.swap_instance_variables(nil)}.should raise_error(TypeError)
|
789
|
+
end
|
790
|
+
|
791
|
+
specify "should raise an exception for swapping between modules and objects" do
|
792
|
+
proc{Class.new.swap_instance_variables(Object.new)}.should raise_error(TypeError)
|
793
|
+
proc{Object.new.swap_instance_variables(Class.new)}.should raise_error(TypeError)
|
794
|
+
end
|
795
|
+
|
796
|
+
specify "should raise an exception for other types" do
|
797
|
+
proc{{}.swap_instance_variables([])}.should raise_error(TypeError)
|
798
|
+
proc{"".swap_instance_variables(//)}.should raise_error(TypeError)
|
799
|
+
end
|
800
|
+
|
801
|
+
specify "should swap the instance's instance variables" do
|
802
|
+
o1 = Object.new
|
803
|
+
o2 = Object.new
|
804
|
+
o1.instance_eval{@a = 1; @c = 3}
|
805
|
+
o2.instance_eval{@a = 4; @b = 2}
|
806
|
+
o1.swap_instance_variables(o2)
|
807
|
+
o2.instance_eval{@a.should == 1; @c.should == 3}
|
808
|
+
o1.instance_eval{@a.should == 4; @b.should == 2}
|
809
|
+
end
|
810
|
+
|
811
|
+
specify "should allow swapping between modules" do
|
812
|
+
c = Class.new
|
813
|
+
m = Module.new
|
814
|
+
c.instance_eval{@a = 1; @c = 3}
|
815
|
+
m.instance_eval{@a = 4; @b = 2}
|
816
|
+
c.swap_instance_variables(m)
|
817
|
+
m.instance_eval{@a.should == 1; @c.should == 3}
|
818
|
+
c.instance_eval{@a.should == 4; @b.should == 2}
|
819
|
+
end
|
820
|
+
|
821
|
+
specify "should return self" do
|
822
|
+
o = Object.new
|
823
|
+
o.swap_instance_variables(Object.new).should equal(o)
|
824
|
+
end
|
825
|
+
end
|
826
|
+
|
827
|
+
describe "Module#swap_method_tables" do
|
828
|
+
specify "should raise an exception for immediate values" do
|
829
|
+
proc{Class.new.swap_method_tables(nil)}.should raise_error(TypeError)
|
830
|
+
end
|
831
|
+
|
832
|
+
specify "should raise an exception for non-module arguments" do
|
833
|
+
proc{Class.new.swap_method_tables(Object.new)}.should raise_error(TypeError)
|
834
|
+
end
|
835
|
+
|
836
|
+
specify "should swap the module's method tables" do
|
837
|
+
c1 = Class.new{def a() 1 end; def b() 3 end}
|
838
|
+
c2 = Class.new{def a() 4 end; def c() 2 end}
|
839
|
+
c1.new.a.should == 1
|
840
|
+
c2.new.a.should == 4
|
841
|
+
c1.new.b.should == 3
|
842
|
+
c2.new.c.should == 2
|
843
|
+
proc{c1.new.c}.should raise_error(NoMethodError)
|
844
|
+
proc{c2.new.b}.should raise_error(NoMethodError)
|
845
|
+
c1.swap_method_tables(c2)
|
846
|
+
c2.new.a.should == 1
|
847
|
+
c1.new.a.should == 4
|
848
|
+
c2.new.b.should == 3
|
849
|
+
c1.new.c.should == 2
|
850
|
+
proc{c2.new.c}.should raise_error(NoMethodError)
|
851
|
+
proc{c1.new.b}.should raise_error(NoMethodError)
|
852
|
+
end
|
853
|
+
|
854
|
+
specify "should return self" do
|
855
|
+
c = Class.new
|
856
|
+
c.swap_method_tables(Class.new).should equal(c)
|
857
|
+
end
|
858
|
+
end
|
859
|
+
|
860
|
+
describe "Module#uninclude" do
|
861
|
+
specify "should raise an exception for immediate values" do
|
862
|
+
proc{Module.new.uninclude nil}.should raise_error(TypeError)
|
863
|
+
end
|
864
|
+
|
865
|
+
specify "should raise an exception for non-module arguments" do
|
866
|
+
proc{Module.new.uninclude Object.new}.should raise_error(TypeError)
|
867
|
+
proc{Module.new.uninclude Class.new}.should raise_error(TypeError)
|
868
|
+
end
|
869
|
+
|
870
|
+
specify "should uninclude the given module from the module/class" do
|
871
|
+
m1 = Module.new{def a() [1] + (super rescue [0]) end}
|
872
|
+
m2 = Module.new{def a() [2] + (super rescue [0]) end}
|
873
|
+
m3 = Module.new{def a() [4] + (super rescue [0]) end}
|
874
|
+
m1.send :include, m2
|
875
|
+
m1.send :include, m3
|
876
|
+
|
877
|
+
c = Class.new{include m1}
|
878
|
+
c.new.a.should == [1, 4, 2, 0]
|
879
|
+
c.uninclude m1
|
880
|
+
c.new.a.should == [4, 2, 0]
|
881
|
+
c.uninclude m2
|
882
|
+
c.new.a.should == [4, 0]
|
883
|
+
|
884
|
+
m1.uninclude m3
|
885
|
+
Class.new{include m1}.new.a.should == [1, 2, 0]
|
886
|
+
m1.uninclude m2
|
887
|
+
Class.new{include m1}.new.a.should == [1, 0]
|
888
|
+
end
|
889
|
+
|
890
|
+
specify "should traverse into superclasses" do
|
891
|
+
m1 = Module.new{def a() [1] + (super rescue [0]) end}
|
892
|
+
m2 = Module.new{def a() [2] + (super rescue [0]) end}
|
893
|
+
m3 = Module.new{def a() [4] + (super rescue [0]) end}
|
894
|
+
m1.send :include, m2
|
895
|
+
|
896
|
+
c = Class.new{def a() [8] + (super rescue [0]) end; include m1}
|
897
|
+
c = Class.new(c){def a() [16] + (super rescue [0]) end; include m3}
|
898
|
+
c.new.a.should == [16, 4, 8, 1, 2, 0]
|
899
|
+
c.uninclude m1
|
900
|
+
c.new.a.should == [16, 4, 8, 2, 0]
|
901
|
+
c.uninclude m2
|
902
|
+
c.new.a.should == [16, 4, 8, 0]
|
903
|
+
c.uninclude m3
|
904
|
+
c.new.a.should == [16, 8, 0]
|
905
|
+
end
|
906
|
+
|
907
|
+
specify "should return module if module included" do
|
908
|
+
m = Module.new
|
909
|
+
m2 = Module.new{include m}
|
910
|
+
m2.uninclude(m).should == m
|
911
|
+
end
|
912
|
+
|
913
|
+
specify "should return nil if module not included" do
|
914
|
+
Module.new.uninclude(Module.new).should == nil
|
915
|
+
end
|
916
|
+
end
|
917
|
+
|
918
|
+
describe "Module#include_between" do
|
919
|
+
specify "should raise an exception for immediate values" do
|
920
|
+
proc{Module.new.include_between(nil){|p,c|}}.should raise_error(TypeError)
|
921
|
+
end
|
922
|
+
|
923
|
+
specify "should raise an exception for non-module arguments" do
|
924
|
+
proc{Module.new.include_between(Object.new){|p,c|}}.should raise_error(TypeError)
|
925
|
+
proc{Module.new.include_between(Class.new){|p,c|}}.should raise_error(TypeError)
|
926
|
+
end
|
927
|
+
|
928
|
+
specify "should raise an exception if a block is not given" do
|
929
|
+
proc{Module.new.include_between(Module.new)}.should raise_error(LocalJumpError)
|
930
|
+
end
|
931
|
+
|
932
|
+
specify "should include the module between the block's modules if the block returns true" do
|
933
|
+
m1 = Module.new{def a() [1] + (super rescue [0]) end}
|
934
|
+
m2 = Module.new{def a() [2] + (super rescue [0]) end}
|
935
|
+
m3 = Module.new{def a() [4] + (super rescue [0]) end}
|
936
|
+
|
937
|
+
c = Class.new
|
938
|
+
c.include_between(m1){|prev, cur| true}
|
939
|
+
c.include_between(m2){|prev, cur| cur == Object}
|
940
|
+
c.include_between(m3){|prev, cur| prev == m1}
|
941
|
+
c.new.a.should == [1, 4, 2, 0]
|
942
|
+
end
|
943
|
+
|
944
|
+
specify "should traverse into superclasses" do
|
945
|
+
m1 = Module.new{def a() [1] + (super rescue [0]) end}
|
946
|
+
m2 = Module.new{def a() [2] + (super rescue [0]) end}
|
947
|
+
m3 = Module.new{def a() [4] + (super rescue [0]) end}
|
948
|
+
|
949
|
+
c = Class.new{def a() [8] + (super rescue [0]) end}
|
950
|
+
sc = Class.new(c){def a() [16] + (super rescue [0]) end}
|
951
|
+
sc.include_between(m1){|prev, cur| prev == c}
|
952
|
+
sc.include_between(m2){|prev, cur| cur == m1}
|
953
|
+
sc.include_between(m3){|prev, cur| true}
|
954
|
+
c.new.a.should == [8, 2, 1, 0]
|
955
|
+
sc.new.a.should == [16, 4, 8, 2, 1, 0]
|
956
|
+
end
|
957
|
+
|
958
|
+
specify "should have first block call first argument be current module/class" do
|
959
|
+
c = Class.new
|
960
|
+
c.include_between(Module.new){|prev, cur| prev.should == c; break}
|
961
|
+
end
|
962
|
+
|
963
|
+
specify "should have last block call last argument be nil" do
|
964
|
+
c = Class.new
|
965
|
+
x = 1
|
966
|
+
c.include_between(Module.new){|prev, cur| x = cur}
|
967
|
+
x.should == nil
|
968
|
+
end
|
969
|
+
|
970
|
+
specify "should have superclass as both last and first argument at some point, if not returned" do
|
971
|
+
c = Class.new
|
972
|
+
a = []
|
973
|
+
c.include_between(Module.new){|prev, cur| a << :prev if prev == c.superclass; a << :cur if cur == c.superclass}
|
974
|
+
a.should == [:cur, :prev]
|
975
|
+
end
|
976
|
+
|
977
|
+
specify "should return module if module included" do
|
978
|
+
m = Module.new
|
979
|
+
m2 = Module.new{include m}
|
980
|
+
m2.include_between(m){|p, c| true}.should == m
|
981
|
+
end
|
982
|
+
|
983
|
+
specify "should return nil if module not included" do
|
984
|
+
Module.new.include_between(Module.new){|p, c|}.should == nil
|
985
|
+
end
|
986
|
+
end
|
987
|
+
|
988
|
+
describe "Object#unextend" do
|
989
|
+
specify "should raise an exception if called on immediate values" do
|
990
|
+
proc{nil.unextend Module.new}.should raise_error(TypeError)
|
991
|
+
end
|
992
|
+
|
993
|
+
specify "should raise an exception for immediate value arguments" do
|
994
|
+
proc{Object.new.unextend nil}.should raise_error(TypeError)
|
995
|
+
end
|
996
|
+
|
997
|
+
specify "should raise an exception for non-module arguments" do
|
998
|
+
proc{Object.new.unextend Object.new}.should raise_error(TypeError)
|
999
|
+
proc{Object.new.unextend Class.new}.should raise_error(TypeError)
|
1000
|
+
end
|
1001
|
+
|
1002
|
+
specify "should unextend the given module from the object" do
|
1003
|
+
m1 = Module.new{def a() [1] + (super rescue [0]) end}
|
1004
|
+
m2 = Module.new{def a() [2] + (super rescue [0]) end}
|
1005
|
+
m3 = Module.new{def a() [4] + (super rescue [0]) end}
|
1006
|
+
m1.send :include, m2
|
1007
|
+
m1.send :include, m3
|
1008
|
+
|
1009
|
+
o = Object.new
|
1010
|
+
o.extend m1
|
1011
|
+
o.a.should == [1, 4, 2, 0]
|
1012
|
+
o.unextend m1
|
1013
|
+
o.a.should == [4, 2, 0]
|
1014
|
+
o.unextend m2
|
1015
|
+
o.a.should == [4, 0]
|
1016
|
+
end
|
1017
|
+
|
1018
|
+
specify "should not traverse above the object's class" do
|
1019
|
+
m1 = Module.new{def a() [1] + (super rescue [0]) end}
|
1020
|
+
m2 = Module.new{def a() [2] + (super rescue [0]) end}
|
1021
|
+
m3 = Module.new{def a() [4] + (super rescue [0]) end}
|
1022
|
+
m1.send :include, m2
|
1023
|
+
|
1024
|
+
c = Class.new{def a() [8] + (super rescue [0]) end; include m1}
|
1025
|
+
o = c.new
|
1026
|
+
o.extend m3
|
1027
|
+
o.a.should == [4, 8, 1, 2, 0]
|
1028
|
+
o.unextend m3
|
1029
|
+
o.a.should == [8, 1, 2, 0]
|
1030
|
+
o.unextend m2
|
1031
|
+
o.a.should == [8, 1, 2, 0]
|
1032
|
+
end
|
1033
|
+
|
1034
|
+
specify "should return module if module extended the object" do
|
1035
|
+
m = Module.new
|
1036
|
+
o = Object.new
|
1037
|
+
o.extend(m)
|
1038
|
+
o.unextend(m).should == m
|
1039
|
+
end
|
1040
|
+
|
1041
|
+
specify "should return nil if module did not extend the object" do
|
1042
|
+
Object.new.unextend(Module.new).should == nil
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
specify "should correctly handle objects without existing singleton classes" do
|
1046
|
+
m = Module.new{def a() [2] + (super rescue [0]) end}
|
1047
|
+
c = Class.new{def a() [1] + (super rescue [0]) end; include m}
|
1048
|
+
o = c.new
|
1049
|
+
o.unextend(Module.new).should == nil
|
1050
|
+
o.a.should == [1, 2, 0]
|
1051
|
+
end
|
1052
|
+
end
|
1053
|
+
|
1054
|
+
describe "Object#extend_between" do
|
1055
|
+
specify "should raise an exception if called on an immediate value" do
|
1056
|
+
proc{nil.extend_between(Module.new){|p,c|}}.should raise_error(TypeError)
|
1057
|
+
end
|
1058
|
+
|
1059
|
+
specify "should raise an exception for immediate value arguments" do
|
1060
|
+
proc{Object.new.extend_between(nil){|p,c|}}.should raise_error(TypeError)
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
specify "should raise an exception for non-module arguments" do
|
1064
|
+
proc{Object.new.extend_between(Object.new){|p,c|}}.should raise_error(TypeError)
|
1065
|
+
proc{Object.new.extend_between(Class.new){|p,c|}}.should raise_error(TypeError)
|
1066
|
+
end
|
1067
|
+
|
1068
|
+
specify "should raise an exception if a block is not given" do
|
1069
|
+
proc{Object.new.extend_between(Module.new)}.should raise_error(LocalJumpError)
|
1070
|
+
end
|
1071
|
+
|
1072
|
+
specify "should raise an exception if module already included in object's class or superclass" do
|
1073
|
+
m = Module.new
|
1074
|
+
c = Class.new{include m}
|
1075
|
+
proc{c.new.extend_between(m){|p, c|}}.should raise_error(ArgumentError)
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
specify "should include the module between the block's modules if the block returns true" do
|
1079
|
+
m1 = Module.new{def a() [1] + (super rescue [0]) end}
|
1080
|
+
m2 = Module.new{def a() [2] + (super rescue [0]) end}
|
1081
|
+
m3 = Module.new{def a() [4] + (super rescue [0]) end}
|
1082
|
+
|
1083
|
+
o = Object.new
|
1084
|
+
o.extend_between(m1){|prev, cur| true}
|
1085
|
+
o.extend_between(m2){|prev, cur| cur == Object}
|
1086
|
+
o.extend_between(m3){|prev, cur| prev == m1}
|
1087
|
+
o.a.should == [1, 4, 2, 0]
|
1088
|
+
def o.a() [8] + super end
|
1089
|
+
o.a.should == [8, 1, 4, 2, 0]
|
1090
|
+
end
|
1091
|
+
|
1092
|
+
specify "should have first block call first argument be the receiver's singleton class" do
|
1093
|
+
o = Object.new
|
1094
|
+
o.extend_between(Module.new){|prev, cur| prev.should == class << o; self end; break}
|
1095
|
+
end
|
1096
|
+
|
1097
|
+
specify "should have last block call last argument be object's class" do
|
1098
|
+
c = Class.new
|
1099
|
+
x = 1
|
1100
|
+
c.new.extend_between(Module.new){|prev, cur| x = cur}
|
1101
|
+
x.should == c
|
1102
|
+
end
|
1103
|
+
|
1104
|
+
specify "should have extended modules as both last and first argument at some point" do
|
1105
|
+
m = Module.new
|
1106
|
+
c = Class.new
|
1107
|
+
o = c.new
|
1108
|
+
o.extend m
|
1109
|
+
a = []
|
1110
|
+
o.extend_between(Module.new){|prev, cur| a << :prev if prev == m; a << :cur if cur == m}
|
1111
|
+
a.should == [:cur, :prev]
|
1112
|
+
end
|
1113
|
+
|
1114
|
+
specify "should return module if module included" do
|
1115
|
+
m = Module.new
|
1116
|
+
Object.new.extend_between(m){|p, c| true}.should == m
|
1117
|
+
end
|
1118
|
+
|
1119
|
+
specify "should return nil if module not included" do
|
1120
|
+
Object.new.extend_between(Module.new){|p, c|}.should == nil
|
1121
|
+
end
|
1122
|
+
|
1123
|
+
specify "should handle objects without existing singleton classes" do
|
1124
|
+
o = Object.new
|
1125
|
+
i = 0
|
1126
|
+
o.extend_between(Module.new){|p, c| p.should == (class << o; self end); c.should == Object; i += 1}
|
1127
|
+
i.should == 1
|
1128
|
+
end
|
1129
|
+
end
|
1130
|
+
|
1131
|
+
describe "Empty" do
|
1132
|
+
specify "should be able to be instantiated" do
|
1133
|
+
proc{Empty.new}.should_not raise_error
|
1134
|
+
end
|
1135
|
+
|
1136
|
+
specify "should raise an error if instantiated with arguments" do
|
1137
|
+
proc{Empty.new 1}.should raise_error(ArgumentError)
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
specify "should not raise an error if subclass instantiated with arguments and supports those arguments" do
|
1141
|
+
c = Class.new(Empty){def initialize(*) end}
|
1142
|
+
proc{c.new 1, 2, 3}.should_not raise_error
|
1143
|
+
end
|
1144
|
+
|
1145
|
+
specify "should have nil superclass" do
|
1146
|
+
Empty.superclass.should == nil
|
1147
|
+
end
|
1148
|
+
|
1149
|
+
specify "subclasses should have correct superclass" do
|
1150
|
+
Class.new(Empty).superclass.should == Empty
|
1151
|
+
end
|
1152
|
+
|
1153
|
+
specify "should have instances that aren't objects" do
|
1154
|
+
Object.instance_method(:is_a?).force_bind(Empty.new).call(Object).should be_false
|
1155
|
+
end
|
1156
|
+
end
|
1157
|
+
end
|