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,345 @@
1
+ require "spec_helper"
2
+ =begin rdoc
3
+
4
+ Name spacing of injectors
5
+ Author: LHA
6
+
7
+
8
+
9
+ Description of the difference between the different namespacing options of injectors:
10
+
11
+ injector :Main
12
+ vs.
13
+ injector :main
14
+
15
+ module X
16
+ injector :Some_Injector
17
+ vs.
18
+ injector :some_injector
19
+ end
20
+
21
+ class Y
22
+ injector :Other_Injector
23
+ vs.
24
+ injector :other_injector
25
+ end
26
+
27
+ =end
28
+
29
+ ###########################
30
+ injector :Major
31
+ injector :minor
32
+ ###########################
33
+
34
+ # upper case vs lower case: semantically equivalent
35
+
36
+ describe 'Major vs minor' do
37
+
38
+
39
+ example :Major do
40
+ Major{
41
+ lets(:bar) {|arg| arg * arg}
42
+ lets(:far) {|arg| arg * arg * arg}
43
+ }
44
+
45
+ class Object
46
+ inject Major()
47
+ end
48
+
49
+ Object.new.bar(3).should == 9
50
+ Object.new.far(2).should == 8
51
+
52
+ Object.eject Major()
53
+ end
54
+
55
+ example :minor do
56
+ minor do
57
+ lets(:bar) {|arg| arg * 3}
58
+ lets(:far) {|arg| arg * arg * 3}
59
+ end
60
+
61
+ class Object
62
+ inject minor
63
+ end
64
+
65
+ Object.new.bar(3).should == 9
66
+ Object.new.far(2).should == 12
67
+
68
+ Object.eject minor
69
+ end
70
+
71
+ end
72
+
73
+
74
+ ###############################
75
+ module X
76
+ injector :Maxi # use sparringly
77
+ injector :mini
78
+ end
79
+ ################################
80
+
81
+ # upper case vs lower case: semantically different
82
+
83
+ describe "X.Maxi vs X.mini" do
84
+
85
+ # scoped globally: no matter where defined or accessed
86
+
87
+ example 'X.Maxi' do
88
+ Maxi{
89
+ def bar
90
+ :bar
91
+ end
92
+ def far
93
+ :far
94
+ end
95
+ }
96
+
97
+ class MaxiTester
98
+ include Maxi()
99
+ end
100
+
101
+ MaxiTester.new.bar.should == :bar
102
+ MaxiTester.new.far.should == :far
103
+ end
104
+
105
+ # scoped to module/class
106
+
107
+ example 'X.mini' do
108
+ expect{
109
+ mini do
110
+ def bar
111
+ :barrr
112
+ end
113
+ def far
114
+ :farrr
115
+ end
116
+ end
117
+ }.to raise_error(NoMethodError) # not in scope
118
+
119
+ X.mini do
120
+ def bar
121
+ :barrr
122
+ end
123
+ def far
124
+ :farrr
125
+ end
126
+ end
127
+
128
+ expect{
129
+ class TesterFor_mini
130
+ include mini
131
+ end
132
+ }.to raise_error(NameError) # not in scope
133
+
134
+ class TesterFor_mini
135
+ include X.mini
136
+ end
137
+
138
+ TesterFor_mini.new.bar.should == :barrr
139
+ TesterFor_mini.new.far.should == :farrr
140
+ end
141
+ end
142
+
143
+ #############################
144
+ # Should follow the same line
145
+ #
146
+ class Y
147
+ injector :Other_Injector
148
+ # vs.
149
+ injector :other_injector
150
+ end
151
+ #
152
+ # No example needed!!
153
+ ##############################
154
+
155
+
156
+
157
+
158
+ # Tied to the idea of Injector Name Spaces is the one of Injector Version Naming/Tagging. In order to make is easier to
159
+ # work with injector versions there is a need to tag/name the different versions for later use.
160
+ describe 'injector Tagging/Naming and its relationship to Injector Versioning' do
161
+
162
+ there 'is way to tag/name a particular version for later reuse' do
163
+
164
+ injector :Bar
165
+
166
+ Tag = Bar do
167
+ def foo_bar
168
+ 'a bar and foo'
169
+ end
170
+ end
171
+
172
+ AnotherTag = Bar do
173
+ def foo_bar
174
+ 'a foo and bar'
175
+ end
176
+ end
177
+
178
+
179
+ class TaggerOne
180
+ inject Tag # first version
181
+ end
182
+ TaggerOne.new.foo_bar.should == 'a bar and foo'
183
+
184
+ class TaggerTwo
185
+ inject AnotherTag # second version
186
+ end
187
+ TaggerTwo.new.foo_bar.should == 'a foo and bar'
188
+
189
+
190
+ class TaggerThree
191
+ inject Tag # first version
192
+ end
193
+ TaggerThree.new.foo_bar.should == 'a bar and foo'
194
+
195
+ class TaggerFour
196
+ inject AnotherTag # second version
197
+ end
198
+ TaggerFour.new.foo_bar.should == 'a foo and bar'
199
+
200
+ end
201
+
202
+ the 'following restriction applies to tags' do
203
+
204
+ # cannot redefine tags
205
+
206
+ SomeTag = Bar do
207
+ def foo
208
+ :foo
209
+ end
210
+ end
211
+
212
+ expect{
213
+ SomeTag do
214
+ def foo
215
+ end
216
+ end
217
+ }.to raise_error(NoMethodError)
218
+ expect{
219
+ SomeTag() {
220
+ def foo
221
+ end
222
+ }
223
+ }.to raise_error(NoMethodError)
224
+
225
+ # This is consistent with the notion of a version:
226
+ # the tag is a snapshot of the Injector at the point of creation
227
+ # . once defined it shouldn't be modified
228
+ # . to make modifications create a new version
229
+
230
+ end
231
+
232
+ it 'does work this way however' do
233
+
234
+ OtherTag = Bar do # New Tag/version!!
235
+ def foo
236
+ :oof
237
+ end
238
+ end # Bar is a true method
239
+
240
+ class TagsTester
241
+ include SomeTag
242
+ end
243
+
244
+ TagsTester.new.foo.should == :foo
245
+
246
+ # update the version a target uses
247
+
248
+ class TagsTester
249
+ update OtherTag
250
+ end
251
+
252
+ TagsTester.new.foo.should == :oof
253
+
254
+ end
255
+ end
256
+
257
+ describe "tag scoping and naming" do
258
+
259
+ it 'passes' do
260
+
261
+ jack :M0
262
+
263
+ TopLevelTag = M0()
264
+
265
+ extend TopLevelTag
266
+
267
+ singleton_class.ancestors.to_s.should match(/TopLevelTag/)
268
+
269
+ end
270
+
271
+ it 'also passes' do
272
+
273
+ module M1
274
+ jack :j1
275
+ end
276
+
277
+ module M2
278
+ Atag = M1.j1
279
+ end
280
+
281
+ class A4
282
+ include M2::Atag
283
+ end
284
+
285
+ A4.ancestors.to_s.should match(/Atag/)
286
+
287
+ end
288
+
289
+ it 'also passes' do
290
+
291
+ module M3
292
+ module M4
293
+ AnotherTag = M1.j1
294
+ end
295
+ end
296
+
297
+ class B4
298
+ include M3::M4::AnotherTag
299
+ end
300
+
301
+ A4.ancestors.to_s.should match(/Atag/)
302
+ B4.ancestors.to_s.should match(/AnotherTag/)
303
+
304
+ end
305
+
306
+ describe "soft tags" do
307
+
308
+ it "is possible to create soft tags" do
309
+
310
+ jack :some_jack
311
+
312
+ some_jack :tag do
313
+ def mith
314
+ 'King Arthur'
315
+ end
316
+ end
317
+
318
+ some_jack :tag do
319
+ def mith
320
+ 'Leprechauns'
321
+ end
322
+ end
323
+
324
+ some_jack :tag do
325
+ def mith
326
+ 'Tooth Fairy'
327
+ end
328
+ end
329
+
330
+ some_jack.tags.size.should == 3
331
+
332
+ $stdout.should_receive(:puts).with("King Arthur")
333
+ $stdout.should_receive(:puts).with("Leprechauns")
334
+ $stdout.should_receive(:puts).with("Tooth Fairy")
335
+
336
+ some_jack.tags.each { |t|
337
+ enrich t
338
+ puts mith
339
+ }
340
+
341
+ end
342
+
343
+ end
344
+ end
345
+
@@ -0,0 +1,847 @@
1
+ require "spec_helper"
2
+ =begin rdoc
3
+
4
+ Injector_spec
5
+ author: Lou Henry
6
+
7
+ Injectors are like modules; they can be extended or included in other modules, but
8
+ exhibit some additional functionality not present in modules.
9
+
10
+ =end
11
+
12
+ include Injectors
13
+
14
+ describe Injectors, :injectors do
15
+
16
+ describe :injector do
17
+ it 'creates the injector function' do
18
+ should respond_to :injector
19
+ class Bar
20
+ end
21
+ Bar.should respond_to :injector
22
+ end
23
+ it 'returns an instance of Injector' do
24
+ injector(:code_injector).class.should == Injector
25
+ end
26
+ end
27
+
28
+ #####
29
+ # Syntax differences
30
+ describe 'syntax differences: ' do
31
+
32
+ describe 'One of the main differences is in how injectors are declared using a method from the injectors
33
+ module and a block. Thsy can later be included or extended into a class or module. They can moreover
34
+ be used to #inject or #enrich into a class or module' do
35
+
36
+ it 'is declared like so...'do
37
+
38
+ expect {
39
+
40
+ injector :my_injector
41
+
42
+ # or...
43
+
44
+ Name = injector :name
45
+
46
+ # or even ...
47
+
48
+ injector :Name # capitalized method
49
+
50
+ }.to_not raise_error
51
+
52
+ end
53
+
54
+ it 'allows the following expressions' do
55
+
56
+ expect{
57
+
58
+ # somewhere in your code
59
+
60
+ injector :my_injector # define the injector
61
+
62
+ # later on...
63
+
64
+ my_injector do
65
+ def foo
66
+ 'a foo'
67
+ end
68
+ def bar
69
+ :a_bar
70
+ end
71
+ end
72
+
73
+ # later on...
74
+
75
+ widget = Object.new
76
+ widget.extend my_injector
77
+ widget.bar
78
+
79
+ # or...
80
+
81
+ Mine = my_injector
82
+
83
+ class Target1
84
+ include Mine # apply the injector
85
+ extend Mine
86
+ end
87
+
88
+ Target1.new.bar
89
+
90
+ module Container
91
+ jack :some_jack # alternate term
92
+
93
+ class Contained
94
+ inject Container.some_jack
95
+ end
96
+ end
97
+
98
+ # etc ...
99
+
100
+ }.to_not raise_error
101
+
102
+ end
103
+
104
+ the 'above generate the following target methods' do
105
+
106
+ Target1.bar.should == :a_bar
107
+ Target1.new.bar.should == :a_bar
108
+
109
+ Target1.foo.should == 'a foo'
110
+ Target1.new.foo.should == 'a foo'
111
+
112
+ Container.some_jack
113
+
114
+ end
115
+
116
+ it 'follows the method lookup algorythm' do
117
+
118
+ injector :some_injector
119
+
120
+ expect{
121
+ class SomeReceiver
122
+ include some_injector
123
+ end
124
+ }.to raise_error(NameError)
125
+
126
+ end
127
+
128
+ it 'allows you to follow the constant lookup algorythmn' do
129
+
130
+ Some_Injector = injector :some_injector
131
+
132
+ expect{
133
+ class Some_Receiver
134
+ inject Some_Injector
135
+ end
136
+ }.to_not raise_error
137
+
138
+ end
139
+
140
+ it 'has alternate syntax and function through the inject/enrich keywords' do
141
+
142
+ # inject
143
+
144
+ injector :alternate do
145
+ def meth arg
146
+ arg < 3
147
+ end
148
+ end
149
+
150
+ class AlternateClass
151
+ # ...
152
+ end
153
+ AlternateClass.inject alternate
154
+
155
+ AlternateClass.new.meth(2).should == true
156
+
157
+ # enrich
158
+
159
+ class Window
160
+
161
+ def draw
162
+ 'window'
163
+ end
164
+
165
+ injector :scroll_bars do
166
+ def draw
167
+ super() + ' with scroll bars'
168
+ end
169
+ end
170
+
171
+ end
172
+
173
+ Window.new.enrich(Window.scroll_bars).draw.should == 'window with scroll bars'
174
+
175
+ end
176
+
177
+ end
178
+
179
+ # This toys with the ideas of modules as closures.'
180
+ describe 'another main difference is that Injectors are defined using a block.' do
181
+ there 'can be subsequent additions and definitions on the block' do
182
+
183
+ # declare the injector
184
+ Stuff = injector :stuff do
185
+ def far
186
+ 'distant'
187
+ end
188
+ end
189
+
190
+ # define containers and include the injector
191
+ class Something
192
+ include Stuff
193
+ end
194
+
195
+ # program works
196
+ some_thing = Something.new
197
+ some_thing.far.should == 'distant'
198
+
199
+ # define more stuff on the injector
200
+ stuff do
201
+ define_method :far do |miles|
202
+ 'My stuff is: ' + miles.to_s + ' miles away'
203
+ end
204
+ end
205
+
206
+ # program stiil works
207
+ some_thing.far(100).should == ('My stuff is: 100 miles away')
208
+
209
+ end
210
+
211
+ it 'can have code dynamically injected into a receiver' do
212
+
213
+ Thing = Object.new
214
+ Thang = Object.new
215
+
216
+ injector :agent
217
+
218
+ Thing.extend agent
219
+ Thang.extend agent
220
+
221
+ agent do # on the fly definitions
222
+ define_method :capability do
223
+ 'do the deed'
224
+ end
225
+ define_method :location do
226
+ 'main building'
227
+ end
228
+ define_method :tester do
229
+ 'some crap happened'
230
+ end
231
+ end
232
+ Thing.should respond_to :capability
233
+ Thing.capability.should == 'do the deed'
234
+ Thang.should respond_to :location
235
+ Thang.location.should == 'main building'
236
+
237
+ end
238
+
239
+ these 'blocks allow on the fly modules which can also include state from the surrounding context' do
240
+
241
+ class ClosureExpose
242
+
243
+ some_value = 'something'
244
+
245
+ injector :capture do
246
+ define_method :val do
247
+ some_value
248
+ end
249
+ end
250
+
251
+ inject capture
252
+ end
253
+
254
+ # the result
255
+ ClosureExpose.new.val.should == 'something'
256
+
257
+ class SecondClass
258
+ include ClosureExpose.capture
259
+ end
260
+
261
+ # the result
262
+ SecondClass.new.val.should == 'something'
263
+
264
+ end
265
+
266
+ these 'new blocks constitute new injector prolongations' do
267
+
268
+ AnotherName = injector :another_injector
269
+
270
+ class Target2
271
+ include AnotherName
272
+ end
273
+
274
+ #_____________________
275
+ # first prolongation
276
+ another_injector do
277
+ def meth arg
278
+ arg
279
+ end
280
+
281
+ def mith *args
282
+ return args
283
+ end
284
+ end
285
+
286
+ expect {
287
+
288
+ Target2.new.mith(1,2,3).should == [1,2,3]
289
+ Target2.new.meth(4).should == 4
290
+
291
+ }.to_not raise_error
292
+
293
+ #____________________
294
+ # another prolongation
295
+ another_injector do
296
+ def moth arg1, arg2
297
+ arg1 + arg2
298
+ end
299
+ end
300
+
301
+ end
302
+
303
+ end
304
+ end
305
+
306
+ describe 'method definition on injectors' do
307
+ the 'methods of the injector closure can be defined using the def keyword' do
308
+
309
+ injector :MethodDefinitions
310
+ MethodDefinitions() do
311
+ def some_crazy_method
312
+ 'I am %#&*@^%_crazy enough'
313
+ end
314
+ end
315
+ o = Object.new.enrich MethodDefinitions()
316
+ o.some_crazy_method.should == 'I am %#&*@^%_crazy enough'
317
+
318
+ end
319
+
320
+ the 'methods can be defined using the define_method method proc style' do
321
+
322
+ injector :MethodDefinitions
323
+ MethodDefinitions do
324
+ define_method :more_crazynex do |x, y|
325
+ x * y * x * y
326
+ end
327
+ end
328
+ enrich MethodDefinitions()
329
+ more_crazynex( 3, 4).should == 144
330
+
331
+ end
332
+
333
+ the 'methods can be defined using the define_method lambda style' do
334
+
335
+ injector :MethodDefinitions
336
+ MethodDefinitions do
337
+ define_method :gone_bonkers, lambda { |x,y,z| (x * y * z).split(':').join('#@')}
338
+ end
339
+ enrich MethodDefinitions()
340
+ gone_bonkers('errrr:rrrr', 2, 3).should == 'errrr#@rrrrerrrr#@rrrrerrrr#@rrrrerrrr#@rrrrerrrr#@rrrrerrrr#@rrrr'
341
+
342
+ end
343
+ end
344
+
345
+ describe 'the types of receivers' do
346
+
347
+ it 'can be a class INSTANCE' do
348
+
349
+ injector :class_instance_injector do
350
+ def new *args
351
+ puts "--done--"
352
+ super(*args)
353
+ end
354
+ end
355
+
356
+ class SomeClassInstance
357
+ # ...
358
+ end
359
+
360
+ SomeClassInstance.enrich class_instance_injector
361
+
362
+ $stdout.should_receive(:puts).with("--done--")
363
+ iu = SomeClassInstance.new
364
+
365
+ end
366
+
367
+ it 'can be an actual class receiver' do
368
+
369
+ Layout = injector( :layout ){
370
+ def expand
371
+ end
372
+ }
373
+ Color = injector( :color ){
374
+ def tint
375
+ end
376
+ }
377
+ class Widget
378
+
379
+ include Layout
380
+ include Color
381
+
382
+ end
383
+ Widget.injectors.sym_list.should == [:layout, :color]
384
+
385
+ expect{Widget.new.expand}.to_not raise_error
386
+ expect{Widget.new.tint}.to_not raise_error
387
+
388
+ end
389
+
390
+ it 'can be an object instance receiver' do
391
+
392
+ injector :for_an_object do
393
+ def to_s
394
+ 'oohooo'
395
+ end
396
+ end
397
+
398
+ o = Object.new
399
+
400
+ o.enrich for_an_object
401
+
402
+ o.to_s.should == 'oohooo'
403
+
404
+ end
405
+
406
+ end
407
+
408
+ describe 'introspection on receivers' do
409
+
410
+ a 'list of injections to an object is available from the objects themselves' do
411
+
412
+ class Coffee
413
+ def cost
414
+ 1.50
415
+ end
416
+ end
417
+ injector :milk
418
+ injector :vanilla
419
+
420
+ cup = Coffee.new.enrich(milk).enrich(vanilla)
421
+ cup.injectors.sym_list.should == [:milk, :vanilla]
422
+
423
+ end
424
+
425
+ the 'list if also available on class injection' do
426
+
427
+ class SomeClass
428
+ inject injector :one
429
+ inject injector :two
430
+ end
431
+ SomeClass.injectors.sym_list.should == [:one, :two]
432
+
433
+ end
434
+
435
+ the 'same is true at the class instance level' do
436
+
437
+ # from above
438
+ SomeClassInstance.injectors.sym_list.should == [:class_instance_injector]
439
+
440
+ end
441
+
442
+ #
443
+ # more on this at the end of file
444
+ #
445
+
446
+ end
447
+
448
+
449
+ describe 'injectors can all be dynamically erased from context. In various ways:' do
450
+ describe 'An injector individually ejected to eliminate its function. All subsequent
451
+ method calls on the injectors methods may raise an error if there is nothing else up
452
+ the lookup chain' do
453
+
454
+ the 'functionality removed from the individual objects.
455
+ Note: applied using the enrich keyword on the object instance' do
456
+
457
+ class Coffee
458
+ def cost
459
+ 1.00
460
+ end
461
+ end
462
+ injector :milk do
463
+ def cost
464
+ super() + 0.50
465
+ end
466
+ end
467
+ # expect{eject :milk}.to raise_error(NoMethodError, /eject/)
468
+
469
+ cup = Coffee.new.enrich(milk)
470
+ friends_cup = Coffee.new.enrich(milk)
471
+
472
+ cup.cost.should == 1.50
473
+ friends_cup.cost.should == 1.50
474
+
475
+ cup.eject :milk
476
+ cup.cost.should == 1.00
477
+ # friends cup didn't change price
478
+ friends_cup.cost.should == 1.50
479
+
480
+ end
481
+
482
+ the 'functionality removed from a class INSTANCE
483
+ Note: when applied via the enrich keywork on the class' do
484
+
485
+ injector :part do
486
+ def connector
487
+ 'connected'
488
+ end
489
+ end
490
+ class Whole
491
+ end
492
+ Whole.extend part
493
+
494
+ Whole.connector.should == 'connected'
495
+ Whole.injectors.sym_list.should == [:part]
496
+
497
+ # eject the part
498
+
499
+ Whole.eject part
500
+
501
+ # result
502
+
503
+ Whole.injectors.should be_empty
504
+ expect{
505
+ Whole.eject part
506
+ }.to raise_error(ArgumentError)
507
+
508
+ end
509
+
510
+ the 'injector functionality removed from a class of objects.
511
+ Note: applied using the inject keyword on the class' do
512
+
513
+ # create the injection
514
+ class Home
515
+ include jack :layout do
516
+ def fractal
517
+ end
518
+ end
519
+ end
520
+ expect{Home.new.fractal}.to_not raise_error
521
+
522
+ # another injector
523
+ class Home
524
+ include jack :materials do
525
+ def plastic
526
+ end
527
+ end
528
+ end
529
+ Home.injectors.sym_list.should == [:layout, :materials ]
530
+
531
+ # build
532
+ my_home = Home.new
533
+ friends = Home.new
534
+
535
+ # eject the code
536
+ class Home
537
+ eject :layout
538
+ end
539
+ Home.injectors.sym_list.should == [:materials]
540
+
541
+ # the result
542
+ expect{my_home.fractal}.to raise_error(NoMethodError)
543
+ expect{friends.fractal}.to raise_error(NoMethodError)
544
+ expect{Home.new.fractal}.to raise_error(NoMethodError)
545
+
546
+ # eject the other injector
547
+ class Home
548
+ eject :materials
549
+ end
550
+ Home.injectors.sym_list.should be_empty
551
+
552
+ # the result
553
+ expect{my_home.plastic}.to raise_error(NoMethodError)
554
+ expect{friends.plastic}.to raise_error(NoMethodError)
555
+ expect{Home.new.plastic}.to raise_error(NoMethodError)
556
+
557
+ end
558
+
559
+ but 'the main injector is still available for re-injection' do
560
+
561
+ # re-inject the class
562
+ class Home
563
+ inject layout
564
+ end
565
+
566
+ # the result
567
+ expect{Home.new.fractal}.to_not raise_error
568
+ expect{Home.new.dup}.to_not raise_error
569
+
570
+ end
571
+
572
+ end
573
+
574
+
575
+ end
576
+
577
+ describe 'orthogonality of injectors with Jackbox' do
578
+
579
+ the 'following interdepent calls do not raise any errors' do
580
+
581
+ expect{
582
+ include Injectors
583
+
584
+ injector :tester1
585
+
586
+ tester1 do
587
+ extend self # extend self
588
+ # Note: you cannot self enrich an injector
589
+ def order weight
590
+ lets label =->(){"label for #{weight}"}
591
+ label[]
592
+ end
593
+ end
594
+ tester1.order(50).should == 'label for 50' # call method extended to self
595
+
596
+
597
+ tester1 do
598
+ decorate :order do |num| # decorate the same method
599
+ "#{self.to_s} " + super(num)
600
+ end
601
+ end
602
+ tester1.order(50).should match( /|tester1| label for 50/ ) # call decorated method extended to self
603
+
604
+
605
+ $stdout.should_receive(:puts).with("|tester1| label for 30")
606
+ with tester1 do # with self(tester1)
607
+ puts order 30 # execute method
608
+ def receive weight # define singleton method
609
+ "received #{weight}"
610
+ end
611
+ end
612
+ tester1.receive(90).should == 'received 90' # call singleton method
613
+
614
+
615
+ tester1 do
616
+ def more_tests arg # define instance method which depends on singleton method
617
+ receive 23 # call singleton method
618
+ "tested more #{arg}"
619
+ end
620
+ end
621
+
622
+ tester1.more_tests('of the api').should == 'tested more of the api'
623
+
624
+ }.to_not raise_error
625
+
626
+ end
627
+
628
+ it 'should also pass' do
629
+
630
+ expect{
631
+
632
+ injector :tester2
633
+ ##################
634
+ tester2 do # enrich == extend
635
+ enrich self ##################
636
+
637
+ def meth arg # define method enriched on self
638
+ arg * arg
639
+ end
640
+ end
641
+ tester2.meth(4).should == 16 # call method enriched on self
642
+
643
+
644
+ tester2 do
645
+ decorate :meth do |arg| # re-define method enriched on self
646
+ super(arg) + 1
647
+ end
648
+ end
649
+ tester2.meth(3).should == 10 # call re-defined method
650
+
651
+ # splat
652
+ with tester2 do # with object self
653
+ meth(5).should == 26
654
+ def math arg1, arg2 # define singleton method on self
655
+ meth(arg1 + arg2)
656
+ end
657
+ end
658
+ tester2.math(3, 2).should == 26 # call singleton method on self
659
+
660
+ }.to_not raise_error
661
+
662
+ tester2 do # define new instance method depending on singleton method
663
+ def moth arg
664
+ math(arg, arg)
665
+ end
666
+ end
667
+
668
+ tester2.moth(4).should == 65
669
+
670
+ end
671
+
672
+ describe 'othogonality: equivalent injector forms' do
673
+
674
+ describe "equivalent inclusion" do
675
+
676
+ before do
677
+ class Injected
678
+ # ...
679
+ end
680
+ end
681
+
682
+ after do
683
+
684
+ end
685
+
686
+ the 'following class injection forms are all equivalent' do
687
+
688
+ injector :First do
689
+ def meth
690
+ :meth
691
+ end
692
+ end
693
+ Injected.inject First()
694
+ Injected.new.meth.should == :meth
695
+
696
+ Injected.eject First()
697
+ end
698
+ the 'following class injection forms are all equivalent' do
699
+
700
+ Injected.inject First() do
701
+ def meth
702
+ :meth
703
+ end
704
+ end
705
+ Injected.new.meth.should == :meth
706
+
707
+ Injected.eject First()
708
+ end
709
+ the 'following class injection forms are all equivalent' do
710
+
711
+ injector( :First ){
712
+ def meth
713
+ :meth
714
+ end
715
+ }
716
+ Injected.inject First()
717
+ Injected.new.meth.should == :meth
718
+
719
+ Injected.eject First()
720
+ end
721
+ the 'following class injection forms are all equivalent' do
722
+
723
+ Injected.inject injector( :First ){
724
+ def meth
725
+ :meth
726
+ end
727
+ }
728
+ Injected.new.meth.should == :meth
729
+
730
+ Injected.eject First()
731
+ end
732
+ end
733
+
734
+ describe 'equivalent enrichment' do
735
+
736
+ the 'following instance enrichment forms are all equvalent' do
737
+
738
+ injector :second do
739
+ def meth
740
+ :meth
741
+ end
742
+ end
743
+ enrich second
744
+ meth.should == :meth
745
+
746
+ eject second
747
+ end
748
+ the 'following instance enrichment forms are all equvalent' do
749
+
750
+ enrich injector :second do
751
+ def meth
752
+ :meth
753
+ end
754
+ end
755
+ meth.should == :meth
756
+
757
+ eject second
758
+ end
759
+ the 'following instance enrichment forms are all equvalent' do
760
+
761
+ injector( :second ){
762
+ def meth
763
+ :meth
764
+ end
765
+ }
766
+ enrich second
767
+ meth.should == :meth
768
+
769
+ eject second
770
+ end
771
+ the 'following instance enrichment forms are all equvalent' do
772
+
773
+ enrich injector( :second ){
774
+ def meth
775
+ :meth
776
+ end
777
+ }
778
+ meth.should == :meth
779
+
780
+ eject second
781
+ end
782
+
783
+ end
784
+
785
+ end
786
+
787
+ describe 'other forms of othogonlity' do
788
+
789
+ before do
790
+ injector :Ortho
791
+ end
792
+
793
+ after do
794
+ Ortho(:implode)
795
+ end
796
+
797
+ it 'uses #with in the following ways' do
798
+
799
+ with Ortho() do
800
+ def foo
801
+ end
802
+ end
803
+
804
+ Ortho().instance_methods.should include(:foo)
805
+
806
+ end
807
+
808
+ it "also works this way" do
809
+
810
+ class OrthoClass
811
+ end
812
+
813
+ with OrthoClass do
814
+ include Ortho()
815
+ extend Ortho(), Ortho()
816
+ end
817
+
818
+ with OrthoClass do
819
+ eject *injectors
820
+ end
821
+
822
+ OrthoClass.injectors.should be_empty
823
+
824
+ end
825
+
826
+ it 'works with #lets in this way' do
827
+
828
+ with Ortho() do
829
+ lets(:make){'Special Make'}
830
+
831
+ def print
832
+ puts make
833
+ end
834
+ end
835
+
836
+ enrich Ortho()
837
+ make.should == 'Special Make'
838
+ #...
839
+
840
+ end
841
+
842
+ end
843
+ end
844
+
845
+ end
846
+
847
+