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,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
+