jackbox 0.9.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +5 -0
  3. data/CHANGES.txt +108 -0
  4. data/LICENSE.lic +0 -0
  5. data/LICENSE.txt +13 -0
  6. data/README.md +1395 -0
  7. data/Rakefile +6 -0
  8. data/bin/jackup +248 -0
  9. data/jackbox.gemspec +27 -0
  10. data/jackbox.jpg +0 -0
  11. data/lib/.document +0 -0
  12. data/lib/jackbox.rb +2 -0
  13. data/lib/jackbox/examples/dir.rb +80 -0
  14. data/lib/jackbox/examples/dx.rb +182 -0
  15. data/lib/jackbox/examples/transformers.rb +101 -0
  16. data/lib/jackbox/injectors.rb +2 -0
  17. data/lib/jackbox/rake.rb +2 -0
  18. data/lib/jackbox/tools/prefs.rb +2 -0
  19. data/lib/jackbox/version.rb +4 -0
  20. data/rgloader/loader.rb +23 -0
  21. data/rgloader/rgloader.darwin.bundle +0 -0
  22. data/rgloader/rgloader.freebsd.so +0 -0
  23. data/rgloader/rgloader.freebsd.x86_64.so +0 -0
  24. data/rgloader/rgloader.linux.so +0 -0
  25. data/rgloader/rgloader.linux.x86_64.so +0 -0
  26. data/rgloader/rgloader.mingw.so +0 -0
  27. data/rgloader/rgloader19.darwin.bundle +0 -0
  28. data/rgloader/rgloader19.freebsd.so +0 -0
  29. data/rgloader/rgloader19.freebsd.x86_64.so +0 -0
  30. data/rgloader/rgloader19.linux.so +0 -0
  31. data/rgloader/rgloader19.linux.x86_64.so +0 -0
  32. data/rgloader/rgloader19.mingw.so +0 -0
  33. data/rgloader/rgloader191.mingw.so +0 -0
  34. data/rgloader/rgloader192.darwin.bundle +0 -0
  35. data/rgloader/rgloader192.freebsd.so +0 -0
  36. data/rgloader/rgloader192.freebsd.x86_64.so +0 -0
  37. data/rgloader/rgloader192.linux.so +0 -0
  38. data/rgloader/rgloader192.linux.x86_64.so +0 -0
  39. data/rgloader/rgloader192.mingw.so +0 -0
  40. data/rgloader/rgloader193.darwin.bundle +0 -0
  41. data/rgloader/rgloader193.freebsd.so +0 -0
  42. data/rgloader/rgloader193.freebsd.x86_64.so +0 -0
  43. data/rgloader/rgloader193.linux.so +0 -0
  44. data/rgloader/rgloader193.linux.x86_64.so +0 -0
  45. data/rgloader/rgloader193.mingw.so +0 -0
  46. data/rgloader/rgloader20.darwin.bundle +0 -0
  47. data/rgloader/rgloader20.freebsd.so +0 -0
  48. data/rgloader/rgloader20.freebsd.x86_64.so +0 -0
  49. data/rgloader/rgloader20.linux.so +0 -0
  50. data/rgloader/rgloader20.linux.x86_64.so +0 -0
  51. data/rgloader/rgloader20.mingw.so +0 -0
  52. data/rgloader/rgloader20.mingw.x64.so +0 -0
  53. data/rgloader/rgloader21.darwin.bundle +0 -0
  54. data/rgloader/rgloader21.freebsd.so +0 -0
  55. data/rgloader/rgloader21.freebsd.x86_64.so +0 -0
  56. data/rgloader/rgloader21.linux.so +0 -0
  57. data/rgloader/rgloader21.linux.x86_64.so +0 -0
  58. data/rgloader/rgloader21.mingw.so +0 -0
  59. data/rgloader/rgloader21.mingw.x64.so +0 -0
  60. data/rgloader/rgloader22.darwin.bundle +0 -0
  61. data/rgloader/rgloader22.freebsd.so +0 -0
  62. data/rgloader/rgloader22.linux.so +0 -0
  63. data/rgloader/rgloader22.linux.x86_64.so +0 -0
  64. data/rgloader/rgloader22.mingw.so +0 -0
  65. data/rgloader/rgloader22.mingw.x64.so +0 -0
  66. data/spec/bin/jackup_cmd_shared.rb +176 -0
  67. data/spec/bin/jackup_cmd_spec.rb +292 -0
  68. data/spec/lib/abtract_spec.rb +56 -0
  69. data/spec/lib/jackbox/examples/dir_spec.rb +112 -0
  70. data/spec/lib/jackbox/examples/dx_spec.rb +346 -0
  71. data/spec/lib/jackbox/examples/result.xml +15 -0
  72. data/spec/lib/jackbox/examples/source1.xml +11 -0
  73. data/spec/lib/jackbox/examples/source2.xml +15 -0
  74. data/spec/lib/jackbox/examples/source3.xml +11 -0
  75. data/spec/lib/jackbox/examples/trasnformers_spec.rb +35 -0
  76. data/spec/lib/jackbox/injector_composition_spec.rb +950 -0
  77. data/spec/lib/jackbox/injector_directives_spec.rb +266 -0
  78. data/spec/lib/jackbox/injector_inheritance_spec.rb +799 -0
  79. data/spec/lib/jackbox/injector_introspection_spec.rb +614 -0
  80. data/spec/lib/jackbox/injector_namespacing_spec.rb +345 -0
  81. data/spec/lib/jackbox/injector_spec.rb +847 -0
  82. data/spec/lib/jackbox/injector_versioning_spec.rb +334 -0
  83. data/spec/lib/jackbox/patterns_spec.rb +410 -0
  84. data/spec/lib/jackbox/prefs_spec.rb +212 -0
  85. data/spec/lib/jackbox/reclassing_spec.rb +394 -0
  86. data/spec/lib/jackbox_spec.rb +595 -0
  87. data/spec/spec_helper.rb +139 -0
  88. metadata +218 -0
@@ -0,0 +1,266 @@
1
+ require "spec_helper"
2
+
3
+ include Injectors
4
+
5
+ describe 'Injector Directives: ' do
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
9
+
10
+ an 'example of complete injector implosion' do
11
+
12
+ class Model
13
+ def feature
14
+ 'a standard feature'
15
+ end
16
+ end
17
+
18
+ injector :extras do
19
+ def feature
20
+ super() + ' plus some extras'
21
+ end
22
+ end
23
+
24
+ car = Model.new.enrich(extras)
25
+ car.feature.should == 'a standard feature plus some extras'
26
+
27
+ extras :implode
28
+
29
+ # total implosion
30
+ expect{extras}.to raise_error(NameError, /extras/)
31
+ car.feature.should == 'a standard feature'
32
+
33
+ expect{
34
+ new_car = Model.new.enrich(extras)
35
+ }.to raise_error(NameError, /extras/)
36
+
37
+ expect{
38
+ extras do
39
+ def foo
40
+ end
41
+ end
42
+ }.to raise_error(NameError, /extras/)
43
+
44
+ end
45
+
46
+ describe 'difference between injector ejection/implosion' do
47
+
48
+ the 'Injector reconstitution after ejection is possible through reinjection
49
+ but reconstitution after injector implosion is NOT AVAILABLE' do
50
+
51
+ # code defined
52
+ class Job
53
+ injector :agent do
54
+ def call
55
+ end
56
+ end
57
+ inject agent
58
+ end
59
+ Job.injectors.sym_list.should == [:agent]
60
+
61
+ # normal use
62
+ expect{Job.new.call}.to_not raise_error
63
+
64
+ # code ejection
65
+ Job.eject :agent
66
+
67
+ # code extended and re-injected
68
+ class Job
69
+ inject agent
70
+ agent do
71
+ def sms
72
+ end
73
+ end
74
+ end
75
+
76
+ #normal use
77
+ expect{Job.new.call}.to_not raise_error
78
+ expect{Job.new.sms}.to_not raise_error
79
+
80
+ # code imlossion
81
+ Job.agent :implode
82
+
83
+ # Unavailable !!!
84
+ expect{
85
+ class Job
86
+ inject :agent
87
+ end
88
+ }.to raise_error(TypeError)
89
+
90
+ # Unavailable !!!
91
+ expect{
92
+ class Job
93
+ agent do
94
+ def something
95
+ end
96
+ end
97
+ end }.to raise_error(NoMethodError)
98
+
99
+ # Unavailable!!!
100
+ expect{Job.new.call}.to raise_error(NoMethodError)
101
+ expect{Job.new.sms}.to raise_error(NoMethodError)
102
+
103
+ end
104
+ end
105
+
106
+ end
107
+ end
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
111
+
112
+ the 'case with objects' do
113
+
114
+ injector :copiable do
115
+ def object_copy
116
+ 'a dubious copy'
117
+ end
118
+ end
119
+
120
+ o1 = Object.new.enrich(copiable)
121
+ o2 = Object.new.enrich(copiable)
122
+
123
+ o1.object_copy.should == 'a dubious copy'
124
+ o2.object_copy.should == 'a dubious copy'
125
+
126
+ copiable :silence
127
+
128
+ o1.object_copy.should == nil
129
+ o2.object_copy.should == nil
130
+
131
+ end
132
+
133
+ the 'case with classes' do
134
+
135
+ class SomeClass
136
+ injector :code do
137
+ def tester
138
+ 'boo'
139
+ end
140
+ end
141
+
142
+ inject code
143
+ end
144
+
145
+ # collapse
146
+ SomeClass.code :collapse
147
+
148
+ # build
149
+ a = SomeClass.new
150
+ b = SomeClass.new
151
+
152
+ a.tester.should == nil
153
+ b.tester.should == nil
154
+
155
+ # further
156
+ SomeClass.eject :code
157
+ expect{ a.tester }.to raise_error(NoMethodError)
158
+ expect{ b.tester }.to raise_error(NoMethodError)
159
+
160
+ end
161
+
162
+ the 'class members are not affected by the collapse' do
163
+
164
+ # define container
165
+ class BumperCar
166
+ def fun
167
+ 'this is fun'
168
+ end
169
+ end
170
+
171
+ injector :somecode do # share member name with container
172
+ def fun
173
+ super + ' and more fun'
174
+ end
175
+ end
176
+
177
+ bc = BumperCar.new.enrich(somecode).enrich(somecode) # decorator pattern
178
+ bc.fun.should == 'this is fun and more fun and more fun'
179
+
180
+ somecode :collapse # collapse the injector
181
+
182
+ bc.fun.should == 'this is fun' # class memeber foo intact
183
+
184
+ # eject all injectors
185
+ bc.injectors.sym_list.each { |ij| bc.eject ij } # same as before
186
+ bc.fun.should == 'this is fun'
187
+
188
+ end
189
+ end
190
+
191
+ describe '<injector> :rebuild. Quieted injectors restored without having
192
+ to re-inject them into every object they modify' do
193
+
194
+ the 'case with objects' do
195
+
196
+ injector :reenforcer do
197
+ def thick_walls
198
+ '===== ====='
199
+ end
200
+ end
201
+
202
+ o1 = Object.new.enrich(reenforcer)
203
+ o2 = Object.new.enrich(reenforcer)
204
+
205
+ reenforcer :collapse
206
+
207
+ o1.thick_walls.should == nil
208
+ o2.thick_walls.should == nil
209
+
210
+ reenforcer :rebuild
211
+
212
+ o1.thick_walls.should == '===== ====='
213
+ o2.thick_walls.should == '===== ====='
214
+
215
+ end
216
+
217
+ the 'case with classes' do
218
+
219
+ class SomeBloatedObject
220
+ injector :ThinFunction do
221
+ def perform
222
+ 'do the deed'
223
+ end
224
+ end
225
+ inject ThinFunction()
226
+ end
227
+ ThinFunction :silence
228
+
229
+ tester = SomeBloatedObject.new
230
+ tester.perform.should == nil
231
+
232
+ ThinFunction :active
233
+ tester.perform.should == 'do the deed'
234
+
235
+ end
236
+
237
+ the 'rebuild reconstructs the entire injector and all applications' do
238
+
239
+ class BumperCar
240
+ def fun
241
+ 'this is fun'
242
+ end
243
+ end
244
+ injector :othercode do # share memeber name with container
245
+ def fun
246
+ super + ' and more fun'
247
+ end
248
+ end
249
+
250
+ bc = BumperCar.new.enrich(othercode).enrich(othercode) # decorator pattern
251
+ bc.fun.should == 'this is fun and more fun and more fun'
252
+
253
+ othercode :silence # declare injector silence
254
+
255
+ bc.fun.should == 'this is fun' # class member un-affected
256
+
257
+ othercode :active
258
+ bc.fun.should == 'this is fun and more fun and more fun' # restores all decorations !!!
259
+
260
+ # restore the original
261
+ bc.injectors.sym_list.each { |ij| bc.eject ij } # same as before
262
+ bc.fun.should == 'this is fun'
263
+
264
+ end
265
+
266
+ end
@@ -0,0 +1,799 @@
1
+ require "spec_helper"
2
+ =begin rdoc
3
+
4
+ Specifies the behavior of Injectors under inheritance
5
+
6
+ . First we se how ancestors are treated
7
+ . Next we treat Injectors under a class hierarchy
8
+ . Then we see a few special cases in the realm of multiple inheritance
9
+
10
+ lha
11
+
12
+ =end
13
+
14
+ include Injectors
15
+
16
+ describe "ancestor chains" do
17
+
18
+ it 'updates the ancestor chains accordingly based on: injections and ejections' do
19
+
20
+ injector :Parent # capitalized method
21
+ class Child
22
+ include Parent()
23
+ end
24
+ Child.ancestors.to_s.should match( /Child, \(.*\|Parent\|\), Object.*BasicObject/ )
25
+
26
+ c = Child.new.enrich Parent()
27
+ # Parent is ancestor of the class and of the metaclass
28
+ c.singleton_class.ancestors.to_s.should match( /\(.*\|Parent\|\), Child, \(.*\|Parent\|\), Object.*BasicObject/ )
29
+
30
+ c.eject Parent()
31
+ # Parent is ejected from the object metaclass and ancestor chain reverts back
32
+ c.singleton_class.ancestors.to_s.should match( /Child, \(.*\|Parent\|\), Object.*BasicObject/ )
33
+
34
+ Child.eject Parent()
35
+ # Parent is ejected from the class and ancestors chain is empty
36
+ Child.ancestors.to_s.should match( /Child, Object.*BasicObject/ )
37
+ # cannot update empty injector
38
+ expect{ Child.send :update, Child.parent }.to raise_error(NoMethodError)
39
+
40
+ c.enrich Parent()
41
+ c.enrich Parent()
42
+ # object metaclass is extended with Parent twice like in the case of multiple decorators
43
+ c.singleton_class.ancestors.to_s.should match( /\(.*\|Parent\|\), \(.*\|Parent\|\), Child, Object.*BasicObject/ )
44
+
45
+ c.eject Parent()
46
+ c.eject Parent()
47
+ # object is reverted back to no Injectors
48
+ c.singleton_class.ancestors.to_s.should match( /Child, Object.*BasicObject/ )
49
+
50
+ Child.inject Parent()
51
+ # class is re-injected with Parent and ancestors is updated
52
+ Child.ancestors.to_s.should match( /Child, \(.*\|Parent\|\), Object.*BasicObject/ )
53
+ c.singleton_class.ancestors.to_s.should match( /Child, \(.*\|Parent\|\), Object.*BasicObject/ )
54
+
55
+ c.eject Parent()
56
+ # class level Injector ejected from single object and ancestor for the object updated but not for class
57
+ c.singleton_class.ancestors.to_s.should match( /Child, Object.*BasicObject/ )
58
+ Child.ancestors.to_s.should match( /Child, \(.*\|Parent\|\), Object.*BasicObject/ )
59
+
60
+ Child.send :update, Parent()
61
+ # class level Injector update re-introduces it to objects that have ejected it locally and ancestors is updated
62
+ c.singleton_class.ancestors.to_s.should match( /Child, \(.*\|Parent\|\), Object.*BasicObject/ )
63
+
64
+ end
65
+ end
66
+
67
+ describe "the inheritance behavior of injectors" do
68
+
69
+ example "works accross class hierarchies" do
70
+
71
+
72
+ ###########################################
73
+ # injection
74
+ ###########################################
75
+ injector :j
76
+
77
+ class C
78
+ end
79
+ C.inject j { # #foo pre-defined at time of injection
80
+ def foo
81
+ 'foo'
82
+ end
83
+ }
84
+ C.injectors.sym_list.should == [:j]
85
+ C.new.injectors.sym_list.should == [:j]
86
+
87
+ injector :k
88
+
89
+ C.inject k { # #faa pre-defined at injection
90
+ def faa
91
+ 'faa'
92
+ end
93
+ }
94
+ C.injectors.sym_list.should == [:j, :k]
95
+ C.new.injectors.sym_list.should == [:j, :k]
96
+
97
+ C.new.foo.should == 'foo'
98
+ C.new.faa.should == 'faa'
99
+ c = C.new
100
+
101
+
102
+ # D inherits from C
103
+
104
+ class D < C # methods are inherited from j and k
105
+ end
106
+ C.injectors.sym_list.should == [:j, :k]
107
+ C.new.injectors.sym_list.should == [:j, :k]
108
+ D.injectors.sym_list.should == []
109
+ D.new.injectors.sym_list.should == []
110
+
111
+ # New Objects
112
+ C.new.foo.should == 'foo'
113
+ C.new.faa.should == 'faa'
114
+ D.new.foo.should == 'foo'
115
+ D.new.faa.should == 'faa'
116
+ # Existing Objects
117
+ d = D.new
118
+ c.foo.should == 'foo'
119
+ c.faa.should == 'faa'
120
+
121
+
122
+ # inject D and override C
123
+
124
+ D.inject j { # new version of j pre-defined at injection
125
+ def foo
126
+ 'foooo'
127
+ end
128
+ }
129
+ C.injectors.sym_list.should == [:j, :k]
130
+ C.new.injectors.sym_list.should == [:j, :k]
131
+ D.injectors.sym_list.should == [:j]
132
+ D.new.injectors.sym_list.should == [:j]
133
+
134
+ # New Objects
135
+ D.new.foo.should == 'foooo' # new version of #foo
136
+ # still the same
137
+ D.new.faa.should == 'faa'
138
+ C.new.foo.should == 'foo'
139
+ C.new.faa.should == 'faa'
140
+ # Existing Objects
141
+ c.foo.should == 'foo'
142
+ c.faa.should == 'faa'
143
+ d.foo.should == 'foooo'
144
+ d.faa.should == 'faa'
145
+
146
+
147
+ # D class overrides j
148
+
149
+ class D < C
150
+ def foo # overrides foo from j
151
+ 'fuu'
152
+ end
153
+ end
154
+ C.injectors.sym_list.should == [:j, :k]
155
+ C.new.injectors.sym_list.should == [:j, :k]
156
+ D.injectors.sym_list.should == [:j]
157
+ D.new.injectors.sym_list.should == [:j]
158
+
159
+ # New Objects
160
+ D.new.foo.should == 'fuu' # overrided last version from j
161
+ # still the same
162
+ D.new.faa.should == 'faa'
163
+ C.new.foo.should == 'foo'
164
+ C.new.faa.should == 'faa'
165
+ # Existing Objects
166
+ c.foo.should == 'foo'
167
+ c.faa.should == 'faa'
168
+ d.foo.should == 'fuu' # overrided
169
+ d.faa.should == 'faa'
170
+
171
+
172
+ # update C and inherit into D
173
+
174
+ C.send :update, k { # new version of k pre-defined at update
175
+ def faa # -- no other version of k in hierarchy
176
+ 'faaxx'
177
+ end
178
+ }
179
+ C.injectors.sym_list.should == [:j, :k]
180
+ C.new.injectors.sym_list.should == [:j, :k]
181
+ D.injectors.sym_list.should == [:j]
182
+ D.new.injectors.sym_list.should == [:j]
183
+
184
+ # New Objects
185
+ C.new.faa.should == 'faaxx' # new version of #faa
186
+ D.new.faa.should == 'faaxx'
187
+ # still the same
188
+ C.new.foo.should == 'foo'
189
+ D.new.foo.should == 'fuu'
190
+ # Existing Objects
191
+ c.foo.should == 'foo'
192
+ c.faa.should == 'faaxx'
193
+ d.foo.should == 'fuu'
194
+ d.faa.should == 'faaxx'
195
+
196
+
197
+ # E inherits from D
198
+
199
+ class E < D # methods are inherited from j at C, D and k update at C
200
+ end
201
+ C.injectors.sym_list.should == [:j, :k]
202
+ C.new.injectors.sym_list.should == [:j, :k]
203
+ D.injectors.sym_list.should == [:j]
204
+ D.new.injectors.sym_list.should == [:j]
205
+ E.injectors.sym_list.should == []
206
+ E.new.injectors.sym_list.should == []
207
+
208
+ # New Objects
209
+ C.new.foo.should == 'foo'
210
+ C.new.faa.should == 'faaxx'
211
+ D.new.foo.should == 'fuu'
212
+ D.new.faa.should == 'faaxx' # new objects pass
213
+ E.new.foo.should == 'fuu'
214
+ E.new.faa.should == 'faaxx'
215
+ # Existing Objects
216
+ e = E.new
217
+ c.foo.should == 'foo'
218
+ c.faa.should == 'faaxx' # existing objects pass
219
+ d.foo.should == 'fuu'
220
+ d.faa.should == 'faaxx'
221
+
222
+
223
+ # E overrides D
224
+
225
+ class E < D
226
+ def foo # overrides #foo from j at C, D
227
+ 'fuuuu'
228
+ end
229
+ end
230
+ C.injectors.sym_list.should == [:j, :k]
231
+ C.new.injectors.sym_list.should == [:j, :k]
232
+ D.injectors.sym_list.should == [:j]
233
+ D.new.injectors.sym_list.should == [:j]
234
+ E.injectors.sym_list.should == []
235
+ E.new.injectors.sym_list.should == []
236
+
237
+ # New Objects
238
+ C.new.foo.should == 'foo'
239
+ C.new.faa.should == 'faaxx'
240
+ D.new.foo.should == 'fuu'
241
+ D.new.faa.should == 'faaxx'
242
+ E.new.foo.should == 'fuuuu'
243
+ E.new.faa.should == 'faaxx'
244
+ # Existing Objects
245
+ c.foo.should == 'foo'
246
+ c.faa.should == 'faaxx'
247
+ d.foo.should == 'fuu'
248
+ d.faa.should == 'faaxx'
249
+ e.foo.should == 'fuuuu'
250
+ e.faa.should == 'faaxx'
251
+
252
+
253
+ #######################################
254
+ # ejection
255
+ #######################################
256
+ C.eject :j # eject j from C
257
+
258
+ C.new.injectors.sym_list.should == [:k]
259
+ C.injectors.sym_list.should == [:k]
260
+ D.new.injectors.sym_list.should == [:j]
261
+ D.injectors.sym_list.should == [:j]
262
+ E.new.injectors.sym_list.should == []
263
+ E.injectors.sym_list.should == []
264
+
265
+ # New Objects
266
+ expect{ C.new.foo.should == 'foo'}.to raise_error(NoMethodError) # #foo errors out on C
267
+ C.new.faa.should == 'faaxx'
268
+ D.new.foo.should == 'fuu'
269
+ D.new.faa.should == 'faaxx' # all else is the same...
270
+ E.new.foo.should == 'fuuuu'
271
+ E.new.faa.should == 'faaxx'
272
+ # Existing Objects
273
+ expect{c.foo.should == 'foo'}.to raise_error(NoMethodError)
274
+ c.faa.should == 'faaxx'
275
+ d.foo.should == 'fuu'
276
+ d.faa.should == 'faaxx'
277
+ e.foo.should == 'fuuuu'
278
+ e.faa.should == 'faaxx'
279
+
280
+
281
+ C.eject :k # eject the only k
282
+
283
+ C.new.injectors.sym_list.should == []
284
+ C.injectors.sym_list.should == []
285
+ D.new.injectors.sym_list.should == [:j]
286
+ D.injectors.sym_list.should == [:j]
287
+ E.new.injectors.sym_list.should == []
288
+ E.injectors.sym_list.should == []
289
+
290
+ # New Objects
291
+ expect{ C.new.foo.should == 'foo'}.to raise_error(NoMethodError)
292
+ expect{ C.new.faa.should == 'faaxx'}.to raise_error(NoMethodError) # # faa errors out
293
+ D.new.foo.should == 'fuu'
294
+ expect{ D.new.faa.should == 'faaxx'}.to raise_error(NoMethodError) #faa errors out
295
+ E.new.foo.should == 'fuuuu'
296
+ expect{ E.new.faa.should == 'faaxx'}.to raise_error(NoMethodError) #faa was only available thru k at C
297
+ # Existing Objects
298
+ expect{c.foo.should == 'foo'}.to raise_error(NoMethodError)
299
+ expect{c.faa.should == 'faaxx'}.to raise_error(NoMethodError)
300
+ d.foo.should == 'fuu' # same thing for pre-existing objects
301
+ expect{d.faa.should == 'faaxx'}.to raise_error(NoMethodError)
302
+ e.foo.should == 'fuuuu'
303
+ expect{e.faa.should == 'faaxx'}.to raise_error(NoMethodError)
304
+
305
+
306
+ D.eject :j # eject j from D: the only one remaining
307
+ # -- everything should revert back to class level
308
+ C.injectors.sym_list.should == []
309
+ C.new.injectors.sym_list.should == []
310
+ D.injectors.sym_list.should == []
311
+ D.new.injectors.sym_list.should == []
312
+ E.injectors.sym_list.should == []
313
+ E.new.injectors.sym_list.should == []
314
+ # New Objects
315
+ expect{ C.new.foo.should == 'foo'}.to raise_error(NoMethodError) # no actual #foo on class
316
+ expect{ C.new.faa.should == 'faaxx'}.to raise_error(NoMethodError) # ''
317
+ D.new.foo.should == 'fuu' # retains overrides from D
318
+ expect{ D.new.faa.should == 'faaxx'}.to raise_error(NoMethodError)
319
+ E.new.foo.should == 'fuuuu' # retains overrides from E
320
+ expect{ E.new.faa.should == 'faaxx'}.to raise_error(NoMethodError)
321
+ # Existing Objects
322
+ expect{c.foo.should == 'foo'}.to raise_error(NoMethodError)
323
+ expect{c.faa.should == 'faaxx'}.to raise_error(NoMethodError)
324
+ d.foo.should == 'fuu' # same for pre-existing objects
325
+ expect{d.faa.should == 'faaxx'}.to raise_error(NoMethodError)
326
+ e.foo.should == 'fuuuu'
327
+ expect{e.faa.should == 'faaxx'}.to raise_error(NoMethodError)
328
+
329
+ end
330
+
331
+ end
332
+
333
+ describe "some special cases and circumstances" do
334
+
335
+ it 'passes on this case when we apply a <blank> Injector and then define the methods on it' do
336
+
337
+ class C1
338
+ end
339
+
340
+ # Define a Blank Injector
341
+
342
+ injector :multi_levelA
343
+
344
+ C1.inject multi_levelA # apply blank injector
345
+
346
+
347
+ # Define function after the application
348
+
349
+ multi_levelA do
350
+ def m1
351
+ 'm1'
352
+ end
353
+ end
354
+
355
+
356
+ # C1 calls
357
+
358
+ C1.new.m1.should == 'm1' # call
359
+
360
+
361
+ # D1 inherits from C1
362
+
363
+ class D1 < C1
364
+ end
365
+ D1.new.m1.should == 'm1' # inherited call
366
+
367
+
368
+ # E1 inherits from D1
369
+
370
+ class E1 < D1
371
+ end
372
+ E1.new.m1.should == 'm1' # inherited call
373
+
374
+
375
+ # Re-define Method Cache
376
+ # -- previously un-applied methods
377
+
378
+ multi_levelA do
379
+ def m1
380
+ 'm1xx'
381
+ end
382
+ end
383
+
384
+
385
+ # Calls are also re-defined
386
+
387
+ C1.new.m1.should == 'm1xx' # call is redefined
388
+ D1.new.m1.should == 'm1xx' # ''
389
+ E1.new.m1.should == 'm1xx' # ''
390
+
391
+
392
+ # Apply the <full> Injector onto E1
393
+
394
+ E1.inject multi_levelA # Attaches this version only onto E1
395
+
396
+ # calls
397
+
398
+ C1.new.m1.should == 'm1xx' # => from cache
399
+ D1.new.m1.should == 'm1xx' # ''
400
+
401
+ E1.new.m1.should == 'm1xx' # => from applied version
402
+
403
+
404
+ # Re-define cached injector methods
405
+
406
+ multi_levelA do
407
+ def m1
408
+ '-----'
409
+ end
410
+ end
411
+
412
+
413
+ # calls
414
+
415
+ C1.new.m1.should == '-----' # re-defined!!
416
+ D1.new.m1.should == '-----' # ''
417
+
418
+ E1.new.m1.should == 'm1xx' # NOT REDEFINED!!
419
+ # -- attached with version
420
+
421
+ end
422
+
423
+ it 'also passes on this case' do
424
+
425
+ class C2
426
+ end
427
+
428
+ # Define a blanck Injector
429
+
430
+ injector :multi_levelB
431
+
432
+
433
+ # Fill-in function as you apply
434
+
435
+ C2.inject multi_levelB do # apply definitions
436
+ def m1
437
+ 'm1'
438
+ end
439
+ end
440
+ C2.new.m1.should == 'm1' # call on Injector
441
+
442
+
443
+ # DD inherits from CC
444
+
445
+ class D2 < C2
446
+ end # call on Injector
447
+ D2.new.m1.should == 'm1'
448
+
449
+
450
+ # EE inherits from DD
451
+
452
+ class E2 < D2
453
+ end # call on Injector
454
+ E2.new.m1.should == 'm1'
455
+
456
+
457
+ # Re-define methods
458
+
459
+ multi_levelB do # NEW VERSION! because previous had an application
460
+ def m1 # -- was applied to C2 in the hierarchy
461
+ 'm1xx'
462
+ end
463
+ end
464
+
465
+ # Calls un-affected !! # have existing version
466
+
467
+ C2.new.m1.should == 'm1'
468
+ D2.new.m1.should == 'm1'
469
+ E2.new.m1.should == 'm1'
470
+
471
+ E2.inject multi_levelB # apply to hierarchy on E
472
+
473
+ C2.new.m1.should == 'm1' # same
474
+ D2.new.m1.should == 'm1' # same
475
+ E2.new.m1.should == 'm1xx' # changed
476
+
477
+ end
478
+
479
+ it 'also passes on this case' do
480
+
481
+ class C3
482
+ end
483
+
484
+ # Define a blank Injector
485
+
486
+ injector :multi_levelC
487
+
488
+
489
+ # Apply <full> Injector definition to an ancestor
490
+
491
+ Object.inject multi_levelC do
492
+ def m1
493
+ 'm1xx'
494
+ end
495
+ end
496
+
497
+
498
+ # Call on the Injector
499
+
500
+ C3.new.m1.should == 'm1xx' # call Injector
501
+
502
+
503
+ # Re-define a new Injector version
504
+
505
+ multi_levelC do
506
+ def m1
507
+ 'm1'
508
+ end
509
+ end
510
+
511
+ # Calls un-afffected
512
+
513
+ C3.new.m1.should == 'm1xx' # still using the previous version --no changes
514
+
515
+
516
+ # Inherit
517
+
518
+ class D3 < C3
519
+ end
520
+ D3.new.m1.should == 'm1xx' # using previous version
521
+
522
+
523
+ # Inherit
524
+
525
+ class E3 < D3
526
+ end
527
+ E3.new.m1.should == 'm1xx' # using previous version
528
+
529
+
530
+ # Finally apply new version
531
+
532
+ C3.inject multi_levelC
533
+
534
+
535
+ # Calls changed from C on up
536
+
537
+ C3.new.m1.should == 'm1'
538
+ D3.new.m1.should == 'm1'
539
+ E3.new.m1.should == 'm1' # new version of #m1
540
+
541
+
542
+ # Call on ancestor the same
543
+
544
+ Object.new.m1.should == 'm1xx' # previous version
545
+
546
+ end
547
+
548
+ it 'carries current methods onto sub-versions' do
549
+
550
+ # Define injector
551
+
552
+ jack :bounce
553
+
554
+ bounce do
555
+ def sound
556
+ 'splat splat'
557
+ end
558
+ end
559
+
560
+
561
+ # Define Tag with new methods
562
+
563
+ TagOne = bounce do
564
+ def bounce
565
+ 'boing boing'
566
+ end
567
+ end
568
+
569
+
570
+ # Apply Tag
571
+
572
+ class Ball
573
+ inject TagOne
574
+ end
575
+ Ball.new.bounce.should == 'boing boing'
576
+
577
+
578
+ class Spring
579
+ inject TagOne
580
+ end
581
+ Spring.new.bounce.should == 'boing boing'
582
+
583
+
584
+ # Inherited methods from :bounce
585
+
586
+ Ball.new.sound.should == 'splat splat'
587
+ Spring.new.sound.should == 'splat splat'
588
+
589
+ end
590
+
591
+ a "more complex example: effectively working Ruby's multiple inheritance" do
592
+
593
+ jack :player do
594
+ def sound
595
+ 'Lets make some music'
596
+ end
597
+ end
598
+
599
+ TapePlayer = player do
600
+ def play
601
+ return 'Tape playing...' + sound()
602
+ end
603
+ end
604
+
605
+ CDPlayer = player do
606
+ def play
607
+ return 'CD playing...' + sound()
608
+ end
609
+ end
610
+
611
+ class BoomBox
612
+ include TapePlayer
613
+
614
+ def on
615
+ play
616
+ end
617
+ end
618
+
619
+ class JukeBox < BoomBox
620
+ inject CDPlayer
621
+ end
622
+
623
+ BoomBox.new.on.should == 'Tape playing...Lets make some music'
624
+ JukeBox.new.on.should == 'CD playing...Lets make some music'
625
+
626
+
627
+ jack :speakers
628
+
629
+ Bass = speakers do
630
+ def sound
631
+ super + '...boom boom boom...'
632
+ end
633
+ end
634
+ JukeBox.inject Bass
635
+
636
+ #...
637
+
638
+ JukeBox.new.on.should == 'CD playing...Lets make some music...boom boom boom...'
639
+
640
+ end
641
+
642
+ it 'works accross compound injectors' do
643
+
644
+ jack :S1
645
+
646
+ S1 do
647
+ include jack :s2 do
648
+ def s2m1
649
+ end
650
+ include jack :s3 do
651
+ def s3m1
652
+ end
653
+ include jack :s4 do
654
+ def s4m1
655
+ end
656
+ end
657
+ end
658
+ end
659
+ end
660
+ S1().s2.s3.s4 # injector pipeline!
661
+
662
+
663
+ # Apply the injectors
664
+
665
+ class CompoundContainer
666
+ include S1()
667
+ end
668
+
669
+
670
+ # Call on the Injectors
671
+
672
+ CompoundContainer.new.s2m1
673
+ CompoundContainer.new.s3m1
674
+ CompoundContainer.new.s4m1
675
+
676
+
677
+ # Add methods to the method cache of s3
678
+
679
+ S1().s2.s3 do
680
+ def s3m2
681
+ end
682
+ end
683
+ CompoundContainer.new.s3m2
684
+
685
+
686
+ # Create a version Tag
687
+
688
+ AccessTag = S1()
689
+
690
+
691
+ # Apply the Tag
692
+
693
+ class SecondContainer
694
+ include AccessTag
695
+ end
696
+
697
+
698
+ # Call on tag methods
699
+
700
+ SecondContainer.new.s3m2
701
+
702
+
703
+ # Add methdos to the s2 method cache
704
+
705
+ S1().s2 do
706
+ def s2m2
707
+ end
708
+ end
709
+
710
+
711
+ # The current cache is available to all containers
712
+
713
+ CompoundContainer.new.s2m2
714
+ SecondContainer.new.s2m2
715
+
716
+ end
717
+
718
+ it 'pases' do
719
+
720
+ injector :M1
721
+ injector :M2
722
+ injector :M3
723
+
724
+ class AA1
725
+ end
726
+ M1 do
727
+ include M2()
728
+ end
729
+ M2 do
730
+ def mM2
731
+ end
732
+ end
733
+ M1 do
734
+ def mM1
735
+ end
736
+ end
737
+ class AA1
738
+ include M1()
739
+ end
740
+ AA1.new.mM2
741
+
742
+ end
743
+
744
+ it 'passes' do
745
+
746
+ injector :J1
747
+ injector :J2
748
+ injector :J3
749
+
750
+ J1 do
751
+ include J2() do
752
+ def mj2
753
+ end
754
+ end
755
+ end
756
+ class AA2
757
+ include J1()
758
+ end
759
+ AA2.new.mj2
760
+ J2 do
761
+ include J3() do
762
+ def mj3
763
+ end
764
+ end
765
+ end
766
+ AA2.new.mj3
767
+
768
+ end
769
+
770
+ it 'also passes' do
771
+
772
+ injector :K1
773
+ injector :K2
774
+ injector :K3
775
+
776
+ K1 do
777
+ include K2() do
778
+ def mk2
779
+ end
780
+ end
781
+ end
782
+ class AA3
783
+ include K1()
784
+ end
785
+ AA3.new.mk2
786
+ K2 do
787
+ include K3()
788
+ end
789
+ K3 do
790
+ def mk3
791
+ end
792
+ end
793
+
794
+ AA3.new.mk3
795
+
796
+ end
797
+
798
+ end
799
+