jackbox 0.9.6.2

Sign up to get free protection for your applications and to get access to all the features.
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
+