jackbox 0.9.6.3 → 0.9.6.6

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.
@@ -4,10 +4,10 @@ include Injectors
4
4
 
5
5
  describe 'Injector Directives: ' do
6
6
 
7
- describe "<injector> :implode, the entire injector and all instances eliminated. Produces different results than
8
- ejecting individual injectors, or from using <injector> :collapse and then restored using <injector> :rebuild" do
7
+ describe "<trait> :implode, the entire trait and all instances eliminated. Produces different results than
8
+ ejecting individual traits, or from using <trait> :collapse and then restored using <trait> :rebuild" do
9
9
 
10
- an 'example of complete injector implosion' do
10
+ an 'example of complete trait implosion' do
11
11
 
12
12
  class Model
13
13
  def feature
@@ -15,7 +15,7 @@ describe 'Injector Directives: ' do
15
15
  end
16
16
  end
17
17
 
18
- injector :extras do
18
+ trait :extras do
19
19
  def feature
20
20
  super() + ' plus some extras'
21
21
  end
@@ -43,20 +43,20 @@ describe 'Injector Directives: ' do
43
43
 
44
44
  end
45
45
 
46
- describe 'difference between injector ejection/implosion' do
46
+ describe 'difference between trait ejection/implosion' do
47
47
 
48
48
  the 'Injector reconstitution after ejection is possible through reinjection
49
- but reconstitution after injector implosion is NOT AVAILABLE' do
49
+ but reconstitution after trait implosion is NOT AVAILABLE' do
50
50
 
51
51
  # code defined
52
52
  class Job
53
- injector :agent do
53
+ trait :agent do
54
54
  def call
55
55
  end
56
56
  end
57
57
  inject agent
58
58
  end
59
- Job.injectors.sym_list.should == [:agent]
59
+ Job.traits.sym_list.should == [:agent]
60
60
 
61
61
  # normal use
62
62
  expect{Job.new.call}.to_not raise_error
@@ -106,12 +106,12 @@ describe 'Injector Directives: ' do
106
106
  end
107
107
  end
108
108
 
109
- describe '<injector> :collapse. Injectors can be silenced. This description produces similar results to
110
- the previous except that further injector method calls DO NOT raise an error they just quietly return nil' do
109
+ describe '<trait> :collapse. Injectors can be silenced. This description produces similar results to
110
+ the previous except that further trait method calls DO NOT raise an error they just quietly return nil' do
111
111
 
112
112
  the 'case with objects' do
113
113
 
114
- injector :copiable do
114
+ trait :copiable do
115
115
  def object_copy
116
116
  'a dubious copy'
117
117
  end
@@ -133,7 +133,7 @@ the previous except that further injector method calls DO NOT raise an error the
133
133
  the 'case with classes' do
134
134
 
135
135
  class SomeClass
136
- injector :code do
136
+ trait :code do
137
137
  def tester
138
138
  'boo'
139
139
  end
@@ -168,7 +168,7 @@ the previous except that further injector method calls DO NOT raise an error the
168
168
  end
169
169
  end
170
170
 
171
- injector :somecode do # share member name with container
171
+ trait :somecode do # share member name with container
172
172
  def fun
173
173
  super + ' and more fun'
174
174
  end
@@ -177,23 +177,23 @@ the previous except that further injector method calls DO NOT raise an error the
177
177
  bc = BumperCar.new.enrich(somecode).enrich(somecode) # decorator pattern
178
178
  bc.fun.should == 'this is fun and more fun and more fun'
179
179
 
180
- somecode :collapse # collapse the injector
180
+ somecode :collapse # collapse the trait
181
181
 
182
182
  bc.fun.should == 'this is fun' # class memeber foo intact
183
183
 
184
- # eject all injectors
185
- bc.injectors.sym_list.each { |ij| bc.eject ij } # same as before
184
+ # eject all traits
185
+ bc.traits.sym_list.each { |ij| bc.eject ij } # same as before
186
186
  bc.fun.should == 'this is fun'
187
187
 
188
188
  end
189
189
  end
190
190
 
191
- describe '<injector> :rebuild. Quieted injectors restored without having
191
+ describe '<trait> :rebuild. Quieted traits restored without having
192
192
  to re-inject them into every object they modify' do
193
193
 
194
194
  the 'case with objects' do
195
195
 
196
- injector :reenforcer do
196
+ trait :reenforcer do
197
197
  def thick_walls
198
198
  '===== ====='
199
199
  end
@@ -217,7 +217,7 @@ to re-inject them into every object they modify' do
217
217
  the 'case with classes' do
218
218
 
219
219
  class SomeBloatedObject
220
- injector :ThinFunction do
220
+ trait :ThinFunction do
221
221
  def perform
222
222
  'do the deed'
223
223
  end
@@ -234,14 +234,14 @@ to re-inject them into every object they modify' do
234
234
 
235
235
  end
236
236
 
237
- the 'rebuild reconstructs the entire injector and all applications' do
237
+ the 'rebuild reconstructs the entire trait and all applications' do
238
238
 
239
239
  class BumperCar
240
240
  def fun
241
241
  'this is fun'
242
242
  end
243
243
  end
244
- injector :othercode do # share memeber name with container
244
+ trait :othercode do # share memeber name with container
245
245
  def fun
246
246
  super + ' and more fun'
247
247
  end
@@ -250,7 +250,7 @@ to re-inject them into every object they modify' do
250
250
  bc = BumperCar.new.enrich(othercode).enrich(othercode) # decorator pattern
251
251
  bc.fun.should == 'this is fun and more fun and more fun'
252
252
 
253
- othercode :silence # declare injector silence
253
+ othercode :silence # declare trait silence
254
254
 
255
255
  bc.fun.should == 'this is fun' # class member un-affected
256
256
 
@@ -258,7 +258,7 @@ to re-inject them into every object they modify' do
258
258
  bc.fun.should == 'this is fun and more fun and more fun' # restores all decorations !!!
259
259
 
260
260
  # restore the original
261
- bc.injectors.sym_list.each { |ij| bc.eject ij } # same as before
261
+ bc.traits.sym_list.each { |ij| bc.eject ij } # same as before
262
262
  bc.fun.should == 'this is fun'
263
263
 
264
264
  end
@@ -269,13 +269,13 @@ describe 'more interesting uses' do
269
269
 
270
270
  it 'allows the following' do
271
271
 
272
- facet :PreFunction do
272
+ jack :PreFunction do
273
273
  def pre_function
274
274
  puts '++++++++++'
275
275
  end
276
276
  end
277
277
 
278
- facet :PosFunction do
278
+ jack :PosFunction do
279
279
  def pos_function
280
280
  puts '=========='
281
281
  end
@@ -307,6 +307,4 @@ describe 'more interesting uses' do
307
307
  obj.meth( 2 )
308
308
 
309
309
  end
310
-
311
-
312
310
  end
@@ -22,14 +22,13 @@ include Injectors
22
22
 
23
23
 
24
24
 
25
- # RubyProf.start
26
25
  describe "ancestor chains" do
27
26
 
28
27
  it 'updates the ancestor chains accordingly based on: injections and ejections' do
29
28
 
30
29
  # LifeCycle Start
31
30
 
32
- injector :Parent # capitalized method
31
+ trait :Parent # capitalized method
33
32
 
34
33
  class Child
35
34
  include Parent()
@@ -55,7 +54,7 @@ describe "ancestor chains" do
55
54
  Child.ancestors.to_s.should match( /Child, Object.*BasicObject/ )
56
55
 
57
56
 
58
- # Note: cannot update empty injector
57
+ # Note: cannot update empty trait
59
58
  expect{ Child.send :update, Child.parent }.to raise_error(NoMethodError)
60
59
 
61
60
 
@@ -93,119 +92,390 @@ describe "ancestor chains" do
93
92
  end
94
93
  end
95
94
 
96
- describe "the behavior of injectors under class inheritance" do
95
+ describe "Injector Inheritance" do
96
+
97
+ it 'carries current methods onto Injector Versions/Tags' do
98
+
99
+ # Define trait
100
+
101
+ jack :bounce
102
+
103
+ bounce do
104
+ def sound
105
+ 'splat splat'
106
+ end
107
+ end
108
+
109
+
110
+ # Define Tag with new methods
111
+
112
+ TagOne = bounce do
113
+ def bounce
114
+ 'boing boing'
115
+ end
116
+ end
117
+
118
+
119
+ # Apply Tag
120
+
121
+ class Ball
122
+ inject TagOne
123
+ end
124
+ Ball.new.bounce.should == 'boing boing'
125
+
126
+
127
+ class Spring
128
+ inject TagOne
129
+ end
130
+ Spring.new.bounce.should == 'boing boing'
131
+
132
+
133
+ # Inherited methods from :bounce
134
+
135
+ Ball.new.sound.should == 'splat splat'
136
+ Spring.new.sound.should == 'splat splat'
137
+
138
+ end
139
+
140
+ a "more complex example: effectively working Ruby's multiple inheritance" do
141
+
142
+ jack :player do
143
+ def sound
144
+ 'Lets make some music'
145
+ end
146
+ end
147
+
148
+ TapePlayer = player do
149
+ def play
150
+ return 'Tape playing...' + sound()
151
+ end
152
+ end
153
+
154
+ CDPlayer = player do
155
+ def play
156
+ return 'CD playing...' + sound()
157
+ end
158
+ end
159
+
160
+ class BoomBox
161
+ include TapePlayer
162
+
163
+ def on
164
+ play
165
+ end
166
+ end
167
+
168
+ class JukeBox < BoomBox
169
+ inject CDPlayer
170
+ end
171
+
172
+ BoomBox.new.on.should == 'Tape playing...Lets make some music'
173
+ JukeBox.new.on.should == 'CD playing...Lets make some music'
174
+
175
+ #...
176
+
177
+ jack :speakers
178
+
179
+ Bass = speakers do
180
+ def sound
181
+ super + '...boom boom boom...'
182
+ end
183
+ end
184
+
185
+ JukeBox.inject Bass
186
+ JukeBox.new.on.should == 'CD playing...Lets make some music...boom boom boom...'
187
+
188
+ end
189
+
190
+
191
+ it "allows a just-in-time inheritance policy" do
192
+
193
+ trait :Functionality
194
+
195
+ #
196
+ # Our Modular Closure
197
+ #
198
+ Tag1 = Functionality do
199
+ def m1
200
+ 1
201
+ end
202
+
203
+ def m2
204
+ :m2
205
+ end
206
+ end
207
+
208
+ expect(Tag1.ancestors).to eql( [Tag1] )
209
+ expect(Functionality().ancestors).to eql( [Functionality()] )
210
+
211
+
212
+ #
213
+ # Normal Injector inheritance
214
+ #
215
+ Functionality do
216
+ def other # No overrides No inheritance
217
+ 'other' # -- same ancestors as before
218
+ end # -- normal trait inheritance
219
+ end
220
+
221
+ # test it
222
+
223
+ expect(Tag1.ancestors).to eql( [Tag1] )
224
+ expect(Functionality().ancestors).to eql( [Functionality()] )
225
+
226
+ o = Object.new.extend(Functionality())
227
+
228
+ # inherited
229
+ o.m1.should == 1
230
+ o.m2.should == :m2
231
+
232
+ # current
233
+ o.other.should == 'other'
234
+
235
+
236
+ #
237
+ # JIT inheritance
238
+ #
239
+ Tag2 = Functionality do
240
+ def m1 # The :m1 override invokes JIT inheritance
241
+ super + 1 # -- Tag1 is added as ancestor
242
+ end # -- allows the use of super
243
+
244
+ def m3
245
+ 'em3'
246
+ end
247
+ end
248
+
249
+ # test it
250
+
251
+ expect(Tag2.ancestors).to eq([Tag2])
252
+ expect(Functionality().ancestors).to eq([Functionality()])
253
+
254
+ p = Object.new.extend(Tag2)
255
+
256
+ # JIT inherited
257
+ p.m1.should == 2 # using inherited function
258
+
259
+ # regular inheritance
260
+ p.m2.should == :m2
261
+ p.m3.should == 'em3'
262
+ p.other.should == 'other'
263
+
264
+ Functionality(:implode)
265
+
266
+ end
97
267
 
98
- example "working accross class hierarchies and the effects of ejection" do
99
268
 
269
+ ########################## important ############################
270
+ # For more information on JIT Inheritance (jiti), please see: #
271
+ # the accompanying spec file jiti_rules_spec.rb in the specs #
272
+ # directory. #
273
+ #################################################################
100
274
 
101
- ###########################################
102
- # injection
103
- ###########################################
104
- injector :j
105
275
 
106
- class C
107
- end
108
- C.inject j { # #foo pre-defined at time of injection
109
- def m1
110
- 'foo'
111
- end
112
- }
113
- C.injectors.sym_list.should == [:j]
114
- C.new.injectors.sym_list.should == [:j]
276
+ end
277
+
278
+ describe "the behavior of traits under class inheritance" do
279
+
280
+ before do
281
+
282
+ suppress_warnings do
283
+
284
+ C = Class.new
285
+ D = Class.new(C)
286
+ E = Class.new(D)
287
+
288
+ trait :j
115
289
 
116
- injector :k
290
+ C.inject j { # #m1 pre-defined at time of injection
291
+ def m1
292
+ 'foo'
293
+ end
294
+ }
117
295
 
118
- C.inject k { # #faa pre-defined at injection
119
- def m2
120
- 'faa'
121
- end
122
- }
123
- C.injectors.sym_list.should == [:k, :j]
124
- C.new.injectors.sym_list.should == [:k, :j]
296
+ trait :k
297
+
298
+ C.inject k do # #m2 pre-defined at injection
299
+ def m2
300
+ 'faa'
301
+ end
302
+ end
303
+
304
+ end
305
+
306
+ end
125
307
 
126
- C.new.m1.should == 'foo'
127
- C.new.m2.should == 'faa'
308
+ after do
309
+
310
+ suppress_warnings do
311
+
312
+ j(:implode)
313
+ k(:implode)
314
+
315
+ C = nil
316
+ D = nil
317
+ E = nil
318
+
319
+ end
320
+
321
+ end
322
+
323
+ it 'works on a first level' do
324
+
325
+ C.traits.sym_list.should == [:k, :j]
326
+ C.new.traits.sym_list.should == [:k, :j]
128
327
  c = C.new
129
328
 
329
+ # New Objects
330
+ with C.new do
331
+ m1.should == 'foo'
332
+ m2.should == 'faa'
333
+ end
334
+ # Existing objects
335
+ with c do
336
+ m1.should == 'foo'
337
+ m2.should == 'faa'
338
+ end
339
+
340
+ end
341
+
342
+ example "adding another level" do
343
+
344
+
345
+ ####################################
346
+ # Preamble
347
+ ####################################
348
+ c = C.new # carry over from above
130
349
 
131
- ########################################
350
+ ####################################
132
351
  # D inherits from C
133
- ########################################
134
- class D < C # methods are inherited from j and k
352
+ ####################################
353
+ class D < C # methods are inherited from j and k
135
354
  end
136
- C.injectors.sym_list.should == [:k, :j]
137
- C.new.injectors.sym_list.should == [:k, :j]
138
- D.injectors.sym_list.should == []
139
- D.new.injectors.sym_list.should == []
140
355
 
356
+ D.traits(:all).sym_list.should == [:k, :j]
357
+ D.new.traits(:all).sym_list.should == [:k, :j]
358
+ d = D.new
359
+
141
360
  # New Objects
142
- C.new.m1.should == 'foo'
143
- C.new.m2.should == 'faa'
144
- D.new.m1.should == 'foo'
145
- D.new.m2.should == 'faa'
146
- # Existing Objects
147
- d = D.new
148
- c.m1.should == 'foo'
149
- c.m2.should == 'faa'
361
+ with D.new do
362
+ m1.should == 'foo'
363
+ m2.should == 'faa'
364
+ end
365
+ # Existing objects
366
+ with c, d do
367
+ m1.should == 'foo'
368
+ m2.should == 'faa'
369
+ end
370
+
371
+ end
150
372
 
373
+ example 'traits on second level' do
151
374
 
152
- ########################################
153
- # inject D and override C
154
- ########################################
155
- D.inject j { # new version of j pre-defined at injection
375
+ ####################################
376
+ # Preamble
377
+ ####################################
378
+ c = C.new
379
+
380
+ ####################################
381
+ # inject into D overriding C
382
+ ####################################
383
+ D.inject j { # new version of j pre-defined at injection
156
384
  def m1
157
385
  'foooo'
158
386
  end
159
387
  }
160
- C.injectors.sym_list.should == [:k, :j]
161
- C.new.injectors.sym_list.should == [:k, :j]
162
- D.injectors.sym_list.should == [:j]
163
- D.new.injectors.sym_list.should == [:j]
388
+ D.traits(:all).sym_list.should == [:j, :k, :j]
389
+ D.new.traits(:all).sym_list.should == [:j, :k, :j]
390
+ d = D.new
164
391
 
165
392
  # New Objects
166
- D.new.m1.should == 'foooo' # new version of #foo
167
- # still the same
168
- D.new.m2.should == 'faa'
169
- C.new.m1.should == 'foo'
170
- C.new.m2.should == 'faa'
393
+ with D.new do
394
+ m1.should == 'foooo' # new version of #m1
395
+ m2.should == 'faa' # still the same
396
+ end
171
397
  # Existing Objects
172
- c.m1.should == 'foo'
173
- c.m2.should == 'faa'
174
- d.m1.should == 'foooo'
175
- d.m2.should == 'faa'
398
+ with c do
399
+ m1.should == 'foo'
400
+ m2.should == 'faa'
401
+ end
402
+ with d do
403
+ m1.should == 'foooo'
404
+ m2.should == 'faa'
405
+ end
406
+ end
176
407
 
408
+ it 'class overrides at second level' do
177
409
 
178
410
  ########################################
179
- # D class overrides j
411
+ # Preamble (from above)
180
412
  ########################################
413
+ c = C.new
414
+
415
+ D.inject j { # new version of j pre-defined at injection
416
+ def m1
417
+ 'foooo'
418
+ end
419
+ }
420
+
421
+ ####################################
422
+ # Override injections at class level
423
+ ####################################
181
424
  class D < C
182
- def m1 # overrides foo from j
425
+ def m1 # overrides foo from j
183
426
  'fuu'
184
427
  end
185
428
  end
186
- C.injectors.sym_list.should == [:k, :j]
187
- C.new.injectors.sym_list.should == [:k, :j]
188
- D.injectors.sym_list.should == [:j]
189
- D.new.injectors.sym_list.should == [:j]
429
+ C.traits.sym_list.should == [:k, :j]
430
+ C.new.traits.sym_list.should == [:k, :j]
431
+ D.traits.sym_list.should == [:j]
432
+ D.new.traits.sym_list.should == [:j]
433
+ d = D.new
190
434
 
191
435
  # New Objects
192
- D.new.m1.should == 'fuu' # overrided last version from j
193
- # still the same
194
- D.new.m2.should == 'faa'
195
- C.new.m1.should == 'foo'
196
- C.new.m2.should == 'faa'
436
+ with D.new do
437
+ m1.should == 'fuu' # overrided last version from j
438
+ m2.should == 'faa' # still the same
439
+ end
440
+ with C.new do
441
+ m1.should == 'foo'
442
+ m2.should == 'faa'
443
+ end
197
444
  # Existing Objects
198
- c.m1.should == 'foo'
199
- c.m2.should == 'faa'
200
- d.m1.should == 'fuu' # overrided
201
- d.m2.should == 'faa'
445
+ with c do
446
+ c.m1.should == 'foo'
447
+ c.m2.should == 'faa'
448
+ end
449
+ with d do
450
+ d.m1.should == 'fuu' # overrided
451
+ d.m2.should == 'faa'
452
+ end
453
+
454
+ end
202
455
 
456
+ it 'allows updates to methods at their respective level' do
203
457
 
204
- ########################################
205
- # update C and inherit into D
206
- ########################################
207
- C.send :update, k { # new version of k pre-defined at update
208
- def m2 # -- no other version of k in hierarchy
458
+ ####################################
459
+ # Preamble ( carry from above)
460
+ ####################################
461
+ c = C.new
462
+
463
+ D.inject j { # new version of j pre-defined at injection
464
+ def m1
465
+ 'foooo'
466
+ end
467
+ }
468
+ class D < C
469
+ def m1 # overrides foo from j
470
+ 'fuu'
471
+ end
472
+ end
473
+
474
+ ####################################
475
+ # update K and inherit into D
476
+ ####################################
477
+ C.send :update, k { # new version of k pre-defined at update
478
+ def m2 # -- no other version of k in hierarchy
209
479
  'faaxx'
210
480
  end
211
481
  }
@@ -213,70 +483,126 @@ describe "the behavior of injectors under class inheritance" do
213
483
  # class C
214
484
  # update k # providing k is in scope
215
485
  # end
216
- C.injectors.sym_list.should == [:k, :j]
217
- C.new.injectors.sym_list.should == [:k, :j]
218
- D.injectors.sym_list.should == [:j]
219
- D.new.injectors.sym_list.should == [:j]
220
-
486
+
487
+ C.traits.sym_list.should == [:k, :j]
488
+ C.new.traits.sym_list.should == [:k, :j]
489
+ D.traits.sym_list.should == [:j]
490
+ D.new.traits.sym_list.should == [:j]
491
+ d = D.new
492
+
221
493
  # New Objects
222
- C.new.m2.should == 'faaxx' # new version of #faa
223
- D.new.m2.should == 'faaxx'
224
- # still the same
225
- C.new.m1.should == 'foo'
226
- D.new.m1.should == 'fuu'
494
+ with D.new do
495
+ m2.should == 'faaxx'
496
+ m1.should == 'fuu'
497
+ end
498
+ with C.new do
499
+ m2.should == 'faaxx' # new version of m1faa
500
+ m1.should == 'foo' # still the same
501
+ end
227
502
  # Existing Objects
228
- c.m1.should == 'foo'
229
- c.m2.should == 'faaxx'
230
- d.m1.should == 'fuu'
231
- d.m2.should == 'faaxx'
503
+ with c do
504
+ m1.should == 'foo'
505
+ m2.should == 'faaxx'
506
+ end
507
+ with d do
508
+ m1.should == 'fuu'
509
+ m2.should == 'faaxx'
510
+ end
511
+
512
+ end
232
513
 
514
+ it 'goes on to other levels' do
233
515
 
234
- ########################################
516
+ ####################################
517
+ # Preamble (carry from above)
518
+ ####################################
519
+ c = C.new
520
+
521
+ D.inject j { # new version of j pre-defined at injection
522
+ def m1
523
+ 'foooo'
524
+ end
525
+ }
526
+ class D < C
527
+ def m1 # overrides foo from j
528
+ 'fuu'
529
+ end
530
+ end
531
+ C.send :update, k { # new version of k pre-defined at update
532
+ def m2 # -- no other version of k in hierarchy
533
+ 'faaxx'
534
+ end
535
+ }
536
+
537
+ ####################################
235
538
  # E inherits from D
236
- ########################################
237
- class E < D # methods are inherited from j at C, D and k update at C
539
+ ####################################
540
+ class E < D # methods are inherited from j at C, D and k update at C
238
541
  end
239
- C.injectors.sym_list.should == [:k, :j]
240
- C.new.injectors.sym_list.should == [:k, :j]
241
- D.injectors.sym_list.should == [:j]
242
- D.new.injectors.sym_list.should == [:j]
243
- E.injectors.sym_list.should == []
244
- E.new.injectors.sym_list.should == []
542
+ C.traits.sym_list.should == [:k, :j]
543
+ C.new.traits.sym_list.should == [:k, :j]
544
+ D.traits.sym_list.should == [:j]
545
+ D.new.traits.sym_list.should == [:j]
546
+ E.traits.sym_list.should == []
547
+ E.new.traits.sym_list.should == []
548
+
549
+ d = D.new
550
+ e = E.new
245
551
 
246
552
  # New Objects
247
553
  C.new.m1.should == 'foo'
248
554
  C.new.m2.should == 'faaxx'
249
555
  D.new.m1.should == 'fuu'
250
- D.new.m2.should == 'faaxx' # new objects pass
556
+ D.new.m2.should == 'faaxx' # new objects pass
251
557
  E.new.m1.should == 'fuu'
252
558
  E.new.m2.should == 'faaxx'
253
559
  # Existing Objects
254
- e = E.new
255
560
  c.m1.should == 'foo'
256
- c.m2.should == 'faaxx' # existing objects pass
561
+ c.m2.should == 'faaxx' # existing objects pass
257
562
  d.m1.should == 'fuu'
258
563
  d.m2.should == 'faaxx'
564
+ e.m1.should == 'fuu'
565
+ e.m2.should == 'faaxx'
566
+ end
259
567
 
260
-
568
+ this 'new class level override' do
569
+
261
570
  ########################################
262
- # E overrides D
571
+ # Preamble (carry from above)
263
572
  ########################################
264
- class E < D
265
- def m1 # overrides #foo from j at C, D
266
- 'fuuuu'
267
- end
268
- end
269
- C.injectors.sym_list.should == [:k, :j]
270
- C.new.injectors.sym_list.should == [:k, :j]
271
- D.injectors.sym_list.should == [:j]
272
- D.new.injectors.sym_list.should == [:j]
273
- E.injectors.sym_list.should == []
274
- E.new.injectors.sym_list.should == []
573
+ c = C.new
275
574
 
276
- # New Objects
277
- C.new.m1.should == 'foo'
278
- C.new.m2.should == 'faaxx'
279
- D.new.m1.should == 'fuu'
575
+ D.inject j { # new version of j pre-defined at injection
576
+ def m1
577
+ 'foooo'
578
+ end
579
+ }
580
+ class D < C
581
+ def m1 # overrides foo from j
582
+ 'fuu'
583
+ end
584
+ end
585
+ C.send :update, k { # new version of k pre-defined at update
586
+ def m2 # -- no other version of k in hierarchy
587
+ 'faaxx'
588
+ end
589
+ }
590
+
591
+ ########################################
592
+ # E overrides D
593
+ ########################################
594
+ class E < D
595
+ def m1 # overrides #foo from j at C, D
596
+ 'fuuuu'
597
+ end
598
+ end
599
+ d = D.new
600
+ e = E.new
601
+
602
+ # New Objects
603
+ C.new.m1.should == 'foo'
604
+ C.new.m2.should == 'faaxx'
605
+ D.new.m1.should == 'fuu'
280
606
  D.new.m2.should == 'faaxx'
281
607
  E.new.m1.should == 'fuuuu'
282
608
  E.new.m2.should == 'faaxx'
@@ -287,92 +613,133 @@ describe "the behavior of injectors under class inheritance" do
287
613
  d.m2.should == 'faaxx'
288
614
  e.m1.should == 'fuuuu'
289
615
  e.m2.should == 'faaxx'
290
-
291
-
292
- #######################################
293
- # ejection
294
- #######################################
295
- C.eject :j # eject j from C
296
-
297
- C.new.injectors.sym_list.should == [:k]
298
- C.injectors.sym_list.should == [:k]
299
- D.new.injectors.sym_list.should == [:j]
300
- D.injectors.sym_list.should == [:j]
301
- E.new.injectors.sym_list.should == []
302
- E.injectors.sym_list.should == []
303
616
 
304
- # New Objects
305
- expect{ C.new.m1.should == 'foo'}.to raise_error(NoMethodError) # m1 errors out on C
306
- C.new.m2.should == 'faaxx'
307
- D.new.m1.should == 'fuu'
308
- D.new.m2.should == 'faaxx' # all else is the same...
309
- E.new.m1.should == 'fuuuu'
310
- E.new.m2.should == 'faaxx'
311
- # Existing Objects
312
- expect{c.m1.should == 'foo'}.to raise_error(NoMethodError) # m1 errors out on C
313
- c.m2.should == 'faaxx'
314
- d.m1.should == 'fuu'
315
- d.m2.should == 'faaxx'
316
- e.m1.should == 'fuuuu'
317
- e.m2.should == 'faaxx'
617
+ end
318
618
 
619
+ describe 'ejection' do
319
620
 
320
- ########################################
321
- # more ejection
322
- ########################################
323
- C.eject :k # eject the only k
324
-
325
- C.new.injectors.sym_list.should == []
326
- C.injectors.sym_list.should == []
327
- D.new.injectors.sym_list.should == [:j]
328
- D.injectors.sym_list.should == [:j]
329
- E.new.injectors.sym_list.should == []
330
- E.injectors.sym_list.should == []
621
+ before do
622
+ ########################################
623
+ # Preamble (carry from above)
624
+ ########################################
331
625
 
332
- # New Objects
333
- expect{ C.new.m1.should == 'foo'}.to raise_error(NoMethodError)
334
- expect{ C.new.m2.should == 'faaxx'}.to raise_error(NoMethodError) # # faa errors out
335
- D.new.m1.should == 'fuu'
336
- expect{ D.new.m2.should == 'faaxx'}.to raise_error(NoMethodError) #faa errors out
337
- E.new.m1.should == 'fuuuu'
338
- expect{ E.new.m2.should == 'faaxx'}.to raise_error(NoMethodError) #faa was only available thru k at C
339
- # Existing Objects
340
- expect{c.m1.should == 'foo'}.to raise_error(NoMethodError)
341
- expect{c.m2.should == 'faaxx'}.to raise_error(NoMethodError)
342
- d.m1.should == 'fuu' # same thing for pre-existing objects
343
- expect{d.m2.should == 'faaxx'}.to raise_error(NoMethodError)
344
- e.m1.should == 'fuuuu'
345
- expect{e.m2.should == 'faaxx'}.to raise_error(NoMethodError)
346
-
347
-
348
- ########################################
349
- # more ejection
350
- ########################################
351
- D.eject :j # eject j from D: the only one remaining
352
- # -- everything should revert back to class level
353
- C.injectors.sym_list.should == []
354
- C.new.injectors.sym_list.should == []
355
- D.injectors.sym_list.should == []
356
- D.new.injectors.sym_list.should == []
357
- E.injectors.sym_list.should == []
358
- E.new.injectors.sym_list.should == []
359
-
360
- # New Objects
361
- expect{ C.new.m1.should == 'foo'}.to raise_error(NoMethodError) # no actual #foo on class
362
- expect{ C.new.m2.should == 'faaxx'}.to raise_error(NoMethodError) # ''
363
- D.new.m1.should == 'fuu' # retains overrides from D
364
- expect{ D.new.m2.should == 'faaxx'}.to raise_error(NoMethodError)
365
- E.new.m1.should == 'fuuuu' # retains overrides from E
366
- expect{ E.new.m2.should == 'faaxx'}.to raise_error(NoMethodError)
367
- # Existing Objects
368
- expect{c.m1.should == 'foo'}.to raise_error(NoMethodError)
369
- expect{c.m2.should == 'faaxx'}.to raise_error(NoMethodError)
370
- d.m1.should == 'fuu' # same for pre-existing objects
371
- expect{d.m2.should == 'faaxx'}.to raise_error(NoMethodError)
372
- e.m1.should == 'fuuuu'
373
- expect{e.m2.should == 'faaxx'}.to raise_error(NoMethodError)
374
-
375
- end
626
+ D.inject j { # new version of j pre-defined at injection
627
+ def m1
628
+ 'foooo'
629
+ end
630
+ }
631
+ class D < C
632
+ def m1 # overrides foo from j
633
+ 'fuu'
634
+ end
635
+ end
636
+ C.send :update, k { # new version of k pre-defined at update
637
+ def m2 # -- no other version of k in hierarchy
638
+ 'faaxx'
639
+ end
640
+ }
641
+
642
+ ########################################
643
+ # E overrides D
644
+ ########################################
645
+ class E < D
646
+ def m1 # overrides #foo from j at C, D
647
+ 'fuuuu'
648
+ end
649
+ end
650
+ end
651
+
652
+ it 'works with ejection' do
653
+
654
+ c = C.new
655
+ d = D.new
656
+ e = E.new
657
+
658
+ #######################################
659
+ # ejection
660
+ #######################################
661
+ C.eject :j # eject j from C
662
+
663
+ C.new.traits.sym_list.should == [:k]
664
+ C.traits.sym_list.should == [:k]
665
+ D.new.traits.sym_list.should == [:j]
666
+ D.traits.sym_list.should == [:j]
667
+ E.new.traits.sym_list.should == []
668
+ E.traits.sym_list.should == []
669
+
670
+ # New Objects
671
+ expect{ C.new.m1.should == 'foo'}.to raise_error(NoMethodError) # m1 errors out on C
672
+ C.new.m2.should == 'faaxx'
673
+ D.new.m1.should == 'fuu'
674
+ D.new.m2.should == 'faaxx' # all else is the same...
675
+ E.new.m1.should == 'fuuuu'
676
+ E.new.m2.should == 'faaxx'
677
+ # Existing Objects
678
+ expect{c.m1.should == 'foo'}.to raise_error(NoMethodError) # m1 errors out on C
679
+ c.m2.should == 'faaxx'
680
+ d.m1.should == 'fuu'
681
+ d.m2.should == 'faaxx'
682
+ e.m1.should == 'fuuuu'
683
+ e.m2.should == 'faaxx'
684
+
685
+
686
+ ########################################
687
+ # more ejection
688
+ ########################################
689
+ C.eject :k # eject the only k
690
+
691
+ C.new.traits.sym_list.should == []
692
+ C.traits.sym_list.should == []
693
+ D.new.traits.sym_list.should == [:j]
694
+ D.traits.sym_list.should == [:j]
695
+ E.new.traits.sym_list.should == []
696
+ E.traits.sym_list.should == []
697
+
698
+ # New Objects
699
+ expect{ C.new.m1.should == 'foo'}.to raise_error(NoMethodError)
700
+ expect{ C.new.m2.should == 'faaxx'}.to raise_error(NoMethodError) # # faa errors out
701
+ D.new.m1.should == 'fuu'
702
+ expect{ D.new.m2.should == 'faaxx'}.to raise_error(NoMethodError) #faa errors out
703
+ E.new.m1.should == 'fuuuu'
704
+ expect{ E.new.m2.should == 'faaxx'}.to raise_error(NoMethodError) #faa was only available thru k at C
705
+ # Existing Objects
706
+ expect{c.m1.should == 'foo'}.to raise_error(NoMethodError)
707
+ expect{c.m2.should == 'faaxx'}.to raise_error(NoMethodError)
708
+ d.m1.should == 'fuu' # same thing for pre-existing objects
709
+ expect{d.m2.should == 'faaxx'}.to raise_error(NoMethodError)
710
+ e.m1.should == 'fuuuu'
711
+ expect{e.m2.should == 'faaxx'}.to raise_error(NoMethodError)
712
+
713
+
714
+ ########################################
715
+ # more ejection
716
+ ########################################
717
+ D.eject :j # eject j from D: the only one remaining
718
+ # -- everything should revert back to class level
719
+ C.traits.sym_list.should == []
720
+ C.new.traits.sym_list.should == []
721
+ D.traits.sym_list.should == []
722
+ D.new.traits.sym_list.should == []
723
+ E.traits.sym_list.should == []
724
+ E.new.traits.sym_list.should == []
725
+
726
+ # New Objects
727
+ expect{ C.new.m1.should == 'foo'}.to raise_error(NoMethodError) # no actual #foo on class
728
+ expect{ C.new.m2.should == 'faaxx'}.to raise_error(NoMethodError) # ''
729
+ D.new.m1.should == 'fuu' # retains overrides from D
730
+ expect{ D.new.m2.should == 'faaxx'}.to raise_error(NoMethodError)
731
+ E.new.m1.should == 'fuuuu' # retains overrides from E
732
+ expect{ E.new.m2.should == 'faaxx'}.to raise_error(NoMethodError)
733
+ # Existing Objects
734
+ expect{c.m1.should == 'foo'}.to raise_error(NoMethodError)
735
+ expect{c.m2.should == 'faaxx'}.to raise_error(NoMethodError)
736
+ d.m1.should == 'fuu' # same for pre-existing objects
737
+ expect{d.m2.should == 'faaxx'}.to raise_error(NoMethodError)
738
+ e.m1.should == 'fuuuu'
739
+ expect{e.m2.should == 'faaxx'}.to raise_error(NoMethodError)
740
+
741
+ end
742
+ end
376
743
 
377
744
  describe 'some special cases' do
378
745
 
@@ -383,12 +750,11 @@ describe "the behavior of injectors under class inheritance" do
383
750
 
384
751
  # Define a blanck Injector
385
752
 
386
- injector :j1
753
+ trait :j1
387
754
 
755
+ # Apply to hierarchy while defining
388
756
 
389
- # Apply to hierarchy root as defined
390
-
391
- C1.inject j1 do # apply definitions
757
+ C1.inject j1 do # same as pre-defined
392
758
  def m1
393
759
  'm1'
394
760
  end
@@ -411,11 +777,11 @@ describe "the behavior of injectors under class inheritance" do
411
777
 
412
778
 
413
779
  ############################
414
- # Re-define methods
780
+ # NEW VERSION!
415
781
  ############################
416
- j1 do # NEW VERSION! because previous had an application
417
- def m1 # -- was applied to C1 in the hierarchy
418
- 'm1xx' # Methods only defined in the Virtual Method Cache
782
+ j1 do
783
+ def m1 # -- previous was applied to C1
784
+ 'm1xx' # this #m1 only defined in the Virtual Method Cache
419
785
  end
420
786
  end
421
787
 
@@ -426,7 +792,7 @@ describe "the behavior of injectors under class inheritance" do
426
792
  E1.new.m1.should == 'm1'
427
793
 
428
794
 
429
- E1.inject j1 # apply to hierarchy on E
795
+ E1.inject j1 # APPLY to hierarchy on E!
430
796
 
431
797
  C1.new.m1.should == 'm1' # same
432
798
  D1.new.m1.should == 'm1' # same
@@ -441,34 +807,30 @@ describe "the behavior of injectors under class inheritance" do
441
807
 
442
808
  # Define a blank Injector
443
809
 
444
- injector :j2
445
-
810
+ trait :j2
446
811
 
447
- # Apply <full> Injector definition to an ancestor
812
+ # Apply full definition to an ancestor
448
813
 
449
814
  Object.inject j2 do
450
815
  def m1
451
816
  'm1xx'
452
817
  end
453
818
  end
454
-
455
-
456
- # Call on the Injector
457
-
819
+ # same effect as above
458
820
  C2.new.m1.should == 'm1xx' # call Injector
459
821
 
460
822
 
461
823
  ############################
462
- # Re-define methods
824
+ # NEW VERSION!
463
825
  ############################
464
826
 
465
- j2 do # NEW VERSION! because previous had an application
466
- def m1 # -- was applied to Object in the hierarchy
467
- 'm1' # Methods only defined in the Virtual Method Cache
827
+ j2 do # NEW VERSION!
828
+ def m1 # -- previous was applied to Object in the hierarchy
829
+ 'm1' # this #m1 only defined in the Virtual Method Cache
468
830
  end
469
831
  end
470
832
 
471
- # Calls un-afffected
833
+ # Calls un-afffected !!
472
834
 
473
835
  C2.new.m1.should == 'm1xx' # still using the previous version --no changes
474
836
 
@@ -488,12 +850,11 @@ describe "the behavior of injectors under class inheritance" do
488
850
 
489
851
 
490
852
  ###########################
491
- # Finally apply new version
853
+ # Apply new version on C
492
854
  ###########################
493
855
 
494
856
  C2.inject j2
495
857
 
496
-
497
858
  # Calls changed from C on up
498
859
 
499
860
  C2.new.m1.should == 'm1'
@@ -519,40 +880,41 @@ describe "the behavior of injectors under class inheritance" do
519
880
 
520
881
  # Define a Blank Injector
521
882
 
522
- injector :j3
883
+ trait :j3
523
884
 
524
885
 
525
- # Apply the blank injector
886
+ # Apply the blank trait
526
887
 
527
888
  C3.inject j3
528
889
 
890
+ ############################
891
+ # NEW VERSION!
892
+ ############################
529
893
 
530
- # Define function after the application
531
-
532
- j3 do # NEW VERSION!
894
+ j3 do #
533
895
  def m1 # -- never applied to Object in the hierarchy
534
- 'm1' # Methods only defined in the Virtual Method Cache
896
+ 'm1' # this #m1 only defined in the Virtual Method Cache
535
897
  end
536
898
  end
537
899
 
538
900
 
539
901
  # C3 calls
540
902
 
541
- C3.new.m1.should == 'm1' # call works as normal from VMC
903
+ C3.new.m1.should == 'm1' # call works from VMC
542
904
 
543
905
 
544
906
  # D3 inherits from C3
545
907
 
546
908
  class D3 < C3
547
909
  end
548
- D3.new.m1.should == 'm1' # inherited call
910
+ D3.new.m1.should == 'm1' # inherited call from VMC
549
911
 
550
912
 
551
913
  # E3 inherits from D3
552
914
 
553
915
  class E3 < D3
554
916
  end
555
- E3.new.m1.should == 'm1' # inherited call
917
+ E3.new.m1.should == 'm1' # inherited call from VMC
556
918
 
557
919
 
558
920
  ###################################
@@ -562,19 +924,20 @@ describe "the behavior of injectors under class inheritance" do
562
924
 
563
925
  j3 do # NEW VERSION!
564
926
  def m1 # -- never applied to Object in the hierarchy
565
- 'm1xx' # Methods only defined in the Virtual Method Cache
927
+ 'm1xx' # this #m1 only defined in the Virtual Method Cache
566
928
  end
567
929
  end
568
930
 
569
-
931
+ ##############################
570
932
  # Calls are also re-defined
571
-
933
+ ##############################
934
+
572
935
  C3.new.m1.should == 'm1xx' # call is redefined
573
936
  D3.new.m1.should == 'm1xx' # ''
574
937
  E3.new.m1.should == 'm1xx' # ''
575
938
 
576
939
 
577
- # Apply the <full> Injector onto E3
940
+ # Apply the full Injector onto E3
578
941
 
579
942
  E3.inject j3 # Attaches this version onto E only!!
580
943
 
@@ -586,13 +949,13 @@ describe "the behavior of injectors under class inheritance" do
586
949
  E3.new.m1.should == 'm1xx' # => from applied version
587
950
 
588
951
 
589
- ################################
590
- # Re-define cached methods
591
- #################################
952
+ ############################
953
+ # NEW VERSION!
954
+ ############################
592
955
 
593
- j3 do # NEW VERSION!
956
+ j3 do
594
957
  def m1 # -- never applied to Object in the hierarchy
595
- '-----' # Methods only defined in the Virtual Method Cache
958
+ '-----' # this #m1 only defined in the Virtual Method Cache
596
959
  end
597
960
  end
598
961
 
@@ -603,767 +966,10 @@ describe "the behavior of injectors under class inheritance" do
603
966
  D3.new.m1.should == '-----' # ''
604
967
 
605
968
  E3.new.m1.should == 'm1xx' # NOT REDEFINED!!
606
- # from applied version
607
-
608
- end
609
-
610
- end
611
- end
612
-
613
- describe "regular Injector internal inheritance" do
614
-
615
- it 'carries current methods onto Injector Versions/Tags' do
616
-
617
- # Define injector
618
-
619
- jack :bounce
620
-
621
- bounce do
622
- def sound
623
- 'splat splat'
624
- end
625
- end
626
-
627
-
628
- # Define Tag with new methods
629
-
630
- TagOne = bounce do
631
- def bounce
632
- 'boing boing'
633
- end
634
- end
635
-
636
-
637
- # Apply Tag
638
-
639
- class Ball
640
- inject TagOne
641
- end
642
- Ball.new.bounce.should == 'boing boing'
643
-
644
-
645
- class Spring
646
- inject TagOne
647
- end
648
- Spring.new.bounce.should == 'boing boing'
649
-
650
-
651
- # Inherited methods from :bounce
652
-
653
- Ball.new.sound.should == 'splat splat'
654
- Spring.new.sound.should == 'splat splat'
655
-
656
- end
657
-
658
- a "more complex example: effectively working Ruby's multiple inheritance" do
969
+ # from full applied version
659
970
 
660
- jack :player do
661
- def sound
662
- 'Lets make some music'
663
- end
664
- end
665
-
666
- TapePlayer = player do
667
- def play
668
- return 'Tape playing...' + sound()
669
- end
670
- end
671
-
672
- CDPlayer = player do
673
- def play
674
- return 'CD playing...' + sound()
675
- end
676
- end
677
-
678
- class BoomBox
679
- include TapePlayer
680
-
681
- def on
682
- play
683
- end
684
- end
685
-
686
- class JukeBox < BoomBox
687
- inject CDPlayer
688
971
  end
689
972
 
690
- BoomBox.new.on.should == 'Tape playing...Lets make some music'
691
- JukeBox.new.on.should == 'CD playing...Lets make some music'
692
-
693
- #...
694
-
695
- jack :speakers
696
-
697
- Bass = speakers do
698
- def sound
699
- super + '...boom boom boom...'
700
- end
701
- end
702
-
703
- JukeBox.inject Bass
704
- JukeBox.new.on.should == 'CD playing...Lets make some music...boom boom boom...'
705
-
706
- end
707
-
708
-
709
- it 'works accross compound injectors' do
710
-
711
- jack :S1
712
-
713
- S1 do
714
- include jack :s2 do
715
- def s2m1
716
- :s2m1
717
- end
718
- include jack :s3 do
719
- def s3m1
720
- :s3m1
721
- end
722
- include jack :s4 do
723
- def s4m1
724
- :s4m1
725
- end
726
- end
727
- end
728
- end
729
- end
730
-
731
- S1().s2.s3.s4 # injector pipeline!
732
-
733
-
734
- # Apply the injectors
735
-
736
- class CompoundContainer
737
- include S1()
738
- end
739
-
740
- CompoundContainer.new.s2m1.should == :s2m1
741
- CompoundContainer.new.s3m1.should == :s3m1
742
- CompoundContainer.new.s4m1.should == :s4m1
743
-
744
-
745
- # Add methods to the VMC of s3
746
-
747
- S1().s2.s3 do
748
- def s3m2
749
- :s3m2
750
- end
751
- end
752
-
753
- CompoundContainer.new.s3m2.should == :s3m2
754
-
755
-
756
- # Create a version Tag
757
-
758
- AccessTag = S1()
759
-
760
- class SecondContainer
761
- include AccessTag
762
- end
763
-
764
- SecondContainer.new.s3m2.should == :s3m2
765
-
766
- end
767
-
768
- it 'works accross the VMC' do
769
-
770
- expect{
771
-
772
- injector :J1
773
- injector :J2
774
- injector :J3
775
-
776
- class AA1
777
- end
778
- J1 do
779
- include J2()
780
- end
781
- J2 do
782
- def mJ2 # virtual cache method
783
- :mJ2
784
- end
785
- end
786
- J1 do
787
- def mJ1 # applied method
788
- :mJ1
789
- end
790
- end
791
- class AA1
792
- include J1()
793
- end
794
-
795
- AA1.new.mJ2.should == :mJ2
796
- AA1.new.mJ1.should == :mJ1
797
-
798
- }.not_to raise_error
799
-
800
- end
801
-
802
- a 'different example' do
803
-
804
- expect{
805
-
806
- injector :K1
807
- injector :K2
808
- injector :K3
809
-
810
- K1 do
811
- include K2() do
812
- def mj2 # applied method
813
- :mj2
814
- end
815
- end
816
- end
817
- class AA2
818
- include K1()
819
- end
820
- AA2.new.mj2.should == :mj2
821
- K2 do
822
- include K3() do
823
- def mj3 # virtual cache method with another indirect
824
- :mj3
825
- end
826
- end
827
- end
828
- AA2.new.mj3.should == :mj3
829
-
830
- }.not_to raise_error
831
-
832
- end
833
-
834
- a 'yet different one' do
835
-
836
- expect{
837
-
838
- injector :M1
839
- injector :M2
840
- injector :M3
841
-
842
- M1 do
843
- include M2() do
844
- def mk2 # applied method
845
- :mk2
846
- end
847
- end
848
- end
849
- class AA3
850
- include M1()
851
- end
852
- AA3.new.mk2.should == :mk2
853
- M2 do
854
- include M3()
855
- end
856
- M3 do
857
- def mk3 # virtual cache method
858
- :mk3
859
- end
860
- end
861
- AA3.new.mk3.should == :mk3
862
-
863
- }.not_to raise_error
864
-
865
- end
866
-
867
- describe 'jit inheriatnce' do
868
-
869
- before do
870
- injector :Tagger
871
-
872
- end
873
-
874
- after do
875
- Tagger(:implode)
876
-
877
- end
878
-
879
-
880
-
881
- it "follows a just-in-time inheritance policy" do
882
-
883
- #
884
- # Our Modular Closure
885
- #
886
- Tag1 = Tagger do
887
- def m1
888
- 1
889
- end
890
-
891
- def m2
892
- :m2
893
- end
894
- end
895
-
896
- expect(Tag1.ancestors).to eql( [Tag1] )
897
- expect(Tagger().ancestors).to eql( [Tagger()] )
898
-
899
-
900
- #
901
- # Normal Injector inheritance
902
- #
903
- Tagger do
904
- def other # No overrides No inheritance
905
- 'other' # -- same ancestors as before
906
- end # -- normal injector inheritance
907
- end
908
-
909
- # test it
910
-
911
- expect(Tag1.ancestors).to eql( [Tag1] )
912
- expect(Tagger().ancestors).to eql( [Tagger()] )
913
-
914
- o = Object.new.extend(Tagger())
915
-
916
- # inherited
917
- o.m1.should == 1
918
- o.m2.should == :m2
919
-
920
- # current
921
- o.other.should == 'other'
922
-
923
-
924
- #
925
- # JIT inheritance
926
- #
927
- Tag2 = Tagger do
928
- def m1 # The :m1 override invokes JIT inheritance
929
- super + 1 # -- Tag1 is added as ancestor
930
- end # -- allows the use of super
931
-
932
- def m3
933
- 'em3'
934
- end
935
- end
936
-
937
- # test it
938
-
939
- expect(Tagger().ancestors).to eql( [Tagger(), Tag1] )
940
- expect(Tag2.ancestors).to eql( [Tag2, Tag1] )
941
-
942
- p = Object.new.extend(Tag2)
943
-
944
- # JIT inherited
945
- p.m1.should == 2
946
-
947
- # regular inheritance
948
- p.m2.should == :m2
949
- p.m3.should == 'em3'
950
- p.other.should == 'other'
951
-
952
-
953
- #
954
- # Under Inclusion
955
- #
956
- class AA6
957
- inject Tag2
958
- end
959
- aa6 = AA6.new
960
-
961
- # test it
962
-
963
- aa6.m1.should == 2
964
- aa6.m2.should == :m2
965
- aa6.m3.should == 'em3'
966
-
967
-
968
- #
969
- # One more level: mixed level inheritance
970
- #
971
- Tag3 = Tagger() do
972
- def m1
973
- super * 2 # second override to #m1
974
- end # -- Tag2 added as ancestor
975
- def m3
976
- super * 2 # first override to #m3
977
- end
978
- end
979
-
980
- # test it
981
-
982
- expect(Tagger().ancestors).to eql( [Tagger(), Tag2, Tag1] )
983
- expect(Tag3.ancestors).to eql( [Tag3, Tag2, Tag1] )
984
- expect(Tag2.ancestors).to eql( [Tag2, Tag1] )
985
-
986
- class AA7
987
- inject Tag3
988
- end
989
- aa7 = AA7.new
990
-
991
- # JIT inheritance
992
- aa7.m1.should == 4
993
- aa7.m3.should == 'em3em3'
994
-
995
- # regular inheritance
996
- aa7.m2.should == :m2
997
- aa7.other.should == 'other'
998
-
999
-
1000
- #
1001
- # Another version: back to basics
1002
- #
1003
- Tagger() do
1004
- def m1 # another override but no call to #super
1005
- :m1 # -- ancestor added
1006
- end
1007
- end
1008
- n = Object.new.extend(Tagger())
1009
-
1010
- # test it
1011
-
1012
- expect(Tagger().ancestors).to eql( [Tagger(), Tag3, Tag2, Tag1] )
1013
- expect(Tag3.ancestors).to eql( [Tag3, Tag2, Tag1] )
1014
- expect(Tag2.ancestors).to eql( [Tag2, Tag1] )
1015
-
1016
-
1017
- n.m1.should == :m1 # new version of #m1
1018
-
1019
- # JIT
1020
- n.m3.should == 'em3em3'
1021
-
1022
- # regular
1023
- n.m2.should == :m2
1024
-
1025
-
1026
- #
1027
- # Test previous versions
1028
- #
1029
- aa6.m1.should == 2
1030
- aa6.m2.should == :m2
1031
- aa6.m3.should == 'em3'
1032
-
1033
- aa66 = AA6.new
1034
-
1035
- aa66.m1.should == 2
1036
- aa66.m2.should == :m2
1037
- aa66.m3.should == 'em3'
1038
-
1039
- aa7.m1.should == 4
1040
- aa7.m2.should == :m2
1041
- aa7.m3.should == 'em3em3'
1042
-
1043
- aa77 = AA7.new
1044
-
1045
- aa77.m1.should == 4
1046
- aa77.m2.should == :m2
1047
- aa77.m3.should == 'em3em3'
1048
-
1049
-
1050
- #
1051
- # other clients
1052
- #
1053
- class AA6B
1054
- inject Tag2
1055
- end
1056
- aa6b = AA6B.new
1057
-
1058
- aa6b.m1.should == 2
1059
- aa6b.m2.should == :m2
1060
- aa6b.m3.should == 'em3'
1061
-
1062
- #
1063
- # VMC (Virtual Method Cache) method
1064
- #
1065
- Tagger() do
1066
- def m4
1067
- :m4
1068
- end
1069
- end
1070
-
1071
- # test it
1072
-
1073
- expect(Tagger().ancestors).to eql([Tagger(), Tag3, Tag2, Tag1])
1074
- expect(Tag3.ancestors).to eql( [Tag3, Tag2, Tag1] )
1075
- expect(Tag2.ancestors).to eql( [Tag2, Tag1] )
1076
-
1077
- aa6b.m1.should == 2
1078
- aa6b.m2.should == :m2
1079
- aa6b.m3.should == 'em3'
1080
- aa6b.m4.should == :m4 # vmc method
1081
-
1082
-
1083
- # Total Tags
1084
-
1085
- Tagger().tags.should == [Tag1, Tag2, Tag3]
1086
-
1087
- end
1088
-
1089
- it "also allows further ancestor injection" do
1090
-
1091
- Tag4 = Tagger do
1092
- def m1
1093
- 1
1094
- end
1095
- def m2
1096
- :m2
1097
- end
1098
- end
1099
-
1100
- module Mod1
1101
- def m1
1102
- 'one'
1103
- end
1104
- end
1105
-
1106
- Tag5 = Tagger(Mod1) do
1107
-
1108
- # include Mod1 # alternatively
1109
-
1110
- def m1
1111
- super * 2 # invoking inheritance for Tag5 !!
1112
- end
1113
- def m3
1114
- :m3
1115
- end
1116
- end
1117
-
1118
- expect(Tagger().ancestors).to eql([Tagger(), Mod1, Tag4])
1119
- expect(Tag4.ancestors).to eql([Tag4])
1120
- expect(Tag5.ancestors).to eql([Tag5, Mod1, Tag4])
1121
-
1122
- # test it
1123
-
1124
- Object.new.extend(Tag5).m1.should == 'oneone'
1125
- Object.new.extend(Tag5).m2.should == :m2
1126
- Object.new.extend(Tag5).m3.should == :m3
1127
-
1128
- # other prolongation
1129
-
1130
- Object.new.extend(Tagger(){
1131
- def m4
1132
- :m4
1133
- end
1134
- }).m4.should == :m4
1135
-
1136
- end
1137
-
1138
- it 'also works like this' do
1139
-
1140
- Tag6 = Tagger do
1141
- def m1
1142
- super() * 2
1143
- end
1144
- def m2
1145
- :m2
1146
- end
1147
- end
1148
-
1149
- module Mod2
1150
- def m1
1151
- 3
1152
- end
1153
- end
1154
-
1155
- Object.new.extend(Tagger(Mod2)).m1.should == 6
1156
- Object.new.extend(Tagger(Mod2)).m2.should == :m2
1157
-
1158
- end
1159
-
1160
- this "also possible" do
1161
-
1162
- Tag7 = Tagger do
1163
- def m1
1164
- 1
1165
- end
1166
- def m2
1167
- :m2
1168
- end
1169
- end
1170
-
1171
- Tag8 = Tagger do
1172
- def m1
1173
- super * 2
1174
- end
1175
- def m3
1176
- :m3
1177
- end
1178
- end
1179
-
1180
- # test it
1181
-
1182
- Object.new.extend(Tag8).m1.should == 2
1183
-
1184
-
1185
- #
1186
- # On the fly overrides
1187
- #
1188
- obj = Object.new.extend(
1189
- Tagger {
1190
- def m1
1191
- super + 3
1192
- end
1193
- def m4
1194
- :m4
1195
- end
1196
- })
1197
- obj.m1.should == 5
1198
- obj.m2.should == :m2
1199
- obj.m3.should == :m3
1200
- obj.m4.should == :m4
1201
-
1202
- end
1203
-
1204
- this "one is a bit tricky" do
1205
-
1206
- Tag9 = Tagger do
1207
- def m1
1208
- 1
1209
- end
1210
- end
1211
-
1212
- module Mod1
1213
- def m1
1214
- 'one'
1215
- end
1216
- end
1217
-
1218
- Tag10 = Tagger() do
1219
-
1220
- include Mod1
1221
-
1222
- def m1
1223
- super * 2
1224
- end
1225
- end
1226
-
1227
- # test it
1228
-
1229
- Object.new.extend(Tag10).m1.should == 'oneone'
1230
- Object.new.extend(Tagger()).m1.should == 'oneone'
1231
-
1232
- Tag10.ancestors.should == [Tag10, Mod1, Tag9]
1233
-
1234
- end
1235
-
1236
- this 'further trick' do
1237
-
1238
- Tag11 = Tagger do
1239
- def m1
1240
- 1
1241
- end
1242
- def m2 # original definition
1243
- 2
1244
- end
1245
- end
1246
- Tag12 = Tagger do
1247
- def m1
1248
- 'm1'
1249
- end # skipped #m2
1250
- end
1251
- Tag13 = Tagger do
1252
- def m1
1253
- super * 2
1254
- end
1255
- def m2
1256
- super * 2 # override # m2 two levels down
1257
- end
1258
- end
1259
- class AA10
1260
- inject Tag13
1261
- end
1262
-
1263
- # test it
1264
-
1265
- AA10.new.m1.should == 'm1m1'
1266
- AA10.new.m2 == 4
1267
-
1268
- Tag13.ancestors.should == [Tag13, Tag12, Tag11]
1269
-
1270
- end
1271
-
1272
- it 'rebases' do
1273
-
1274
- Tag14 = Tagger do
1275
- def m1
1276
- 1
1277
- end
1278
- end
1279
-
1280
- class AA11
1281
- inject Tagger() do
1282
- def m1
1283
- super + 1
1284
- end
1285
- end
1286
- end
1287
-
1288
- # test it
1289
-
1290
- AA11.new.m1.should == 2
1291
-
1292
-
1293
- Tag15 = Tagger do
1294
- def m1
1295
- 5 # rebase m1
1296
- end
1297
- end
1298
-
1299
- class BB11
1300
- inject Tagger() do
1301
- def m1
1302
- super * 2 # new override
1303
- end
1304
- end
1305
- end
1306
-
1307
- # test it
1308
-
1309
- BB11.new.m1.should == 10
1310
-
1311
-
1312
- end
1313
-
1314
- it 'takes Injector Directives' do
1315
-
1316
- Tag16 = Tagger do
1317
- def m1
1318
- 1
1319
- end
1320
- end
1321
-
1322
- class AA12
1323
- inject Tagger() do
1324
- def m1
1325
- super + 1
1326
- end
1327
- end
1328
- end
1329
-
1330
- AA12.new.m1.should == 2
1331
-
1332
-
1333
- Tag17 = Tagger do
1334
- def m1
1335
- 5 # rebase m1
1336
- end
1337
- end
1338
-
1339
- class BB12
1340
- inject Tagger() do
1341
- def m1
1342
- super * 2 # new override
1343
- end
1344
- end
1345
- end
1346
-
1347
- BB12.new.m1.should == 10
1348
-
1349
- # test directives
1350
-
1351
- Tagger(:silence)
1352
-
1353
- AA12.new.m1.should == nil # both bases affected
1354
- BB12.new.m1.should == nil
1355
-
1356
- Tagger(:active)
1357
-
1358
- AA12.new.m1.should == 2 # both bases restored
1359
- BB12.new.m1.should == 10
1360
-
1361
- end
1362
-
1363
973
  end
1364
974
  end
1365
975
 
1366
- # profile = RubyProf.stop
1367
- # RubyProf::FlatPrinter.new(profile).print(STDOUT)
1368
- # RubyProf::GraphHtmlPrinter.new(profile).print(open('profile.html', 'w+'))
1369
- # RubyProf::CallStackPrinter.new(profile).print(open('profile.html', 'w+'))