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,334 @@
1
+ require "spec_helper"
2
+
3
+ include Injectors
4
+
5
+ describe 'Injector versioning:', :injectors do
6
+ # subsequent redefinitions of methods constitute another version of the injector. Injector
7
+ # versioning is the term used to identify a feature in the code that produces an artifact of injection which contains a
8
+ # certain set of methods and their associated outputs and represents a snapshot of that injector up until the point it
9
+ # gets applied to an object. From, that point on the object contains only that version of methods from that injector, and
10
+ # any subsequent overrides to those methods are only members of the "prolongation" of the injector and do not become part
11
+ # of the object of injection unless some form of reinjection occurs. Newer versions of methods only become part of newer
12
+ # objects or newer injections into existing targets'
13
+
14
+ describe 'injector versioning and its relationship to object instances' do
15
+
16
+ the 'injector versioning uses a snapshot of the injector`s existing methods up to the point of injection' do
17
+ # using only that version of methods as the object of injection. AA4ny overrides to methods in any subsequent injector prolongations
18
+ # do not take effect in this target. AA4ny new methods added to the injector do become available to the target, although
19
+ # may contain internal references to newer versions of the target methods. This ensures to keep everyting working correctly.'
20
+
21
+ #___________________
22
+ # injector declaration
23
+ injector :My_injector
24
+
25
+ #___________________
26
+ # injector first prolongation
27
+ My_injector do
28
+ def bar
29
+ :a_bar # version bar.1
30
+ end
31
+ def foo
32
+ # ...
33
+ end
34
+ end
35
+
36
+ object1 = Object.new
37
+ object1.enrich My_injector() # apply the injector --first snapshot
38
+ object1.bar.should == :a_bar # pass the test
39
+
40
+ #__________________
41
+ # injector second prolongation
42
+ My_injector do
43
+ def bar
44
+ :some_larger_bar # version bar.2 ... re-defines bar
45
+ end
46
+ def some_other_function
47
+ # ...
48
+ end
49
+ end
50
+
51
+ object2 = Object.new
52
+ object2.enrich My_injector() # apply the injector --second snapshot
53
+ object2.bar.should == :some_larger_bar
54
+
55
+ # result
56
+ ###########
57
+
58
+ object1.bar.should == :a_bar # bar.1 is still the one
59
+
60
+ ###########################################
61
+ # The object has kept its preferred version
62
+
63
+ end
64
+
65
+ the 're-injection changes ("updates if you will") versions of methods in use' do
66
+
67
+ #_________________
68
+ # re-injection
69
+ enrich My_injector() # re-injection on any object instance
70
+ bar.should == :some_larger_bar # bar.2 now available
71
+
72
+ expect{some_other_function}.to_not raise_error # some_other_function.1 is present
73
+
74
+ end
75
+
76
+ a 'different example with an explicit self' do
77
+
78
+ o = Object.new
79
+
80
+ injector :some_methods do
81
+ def meth arg
82
+ arg
83
+ end
84
+ end
85
+
86
+ o.enrich some_methods
87
+ o.meth('cha cha').should == 'cha cha'
88
+
89
+ some_methods do
90
+ def meth arg
91
+ arg * 2
92
+ end
93
+ end
94
+
95
+ o.meth('cha cha').should == 'cha cha'
96
+
97
+ oo = Object.new.enrich(some_methods)
98
+ oo.meth('cha cha').should == 'cha cha'+'cha cha'
99
+
100
+ o.meth('cha cha').should == 'cha cha'
101
+
102
+ end
103
+
104
+ end
105
+
106
+ describe "injector versioning and its relationship to classes" do
107
+ # similar to object level versioning in that it uses a snapshot of the injector`s existing methods up to the point of injection, using only
108
+ # that version of methods as the object of injection. But, unlike object level versioning, because class injection is static, reinjection
109
+ # does not change the class unless we use the Strategy Pattern which completely changes the class's strategy of methods"
110
+
111
+ the "class injector versioning is similar to object injector versioning" do
112
+
113
+ #___________________
114
+ # injector declaration:
115
+ injector :Versions
116
+
117
+ #___________________
118
+ # injector first prolongation
119
+ Version1 = Versions do
120
+ def meth arg # version meth.1
121
+ arg ** arg
122
+ end
123
+ end
124
+
125
+ class One
126
+ inject Version1 # apply --first snapshot
127
+ end
128
+
129
+ #_________________
130
+ # injector second prolongation
131
+ Version2 = Versions do
132
+ def meth arg1, arg2 # version meth.2 ... redefines meth.1
133
+ arg1 * arg2
134
+ end
135
+ end
136
+
137
+ class Two
138
+ inject Version2 # apply --second snapshot
139
+ end
140
+
141
+
142
+ # result
143
+ #############################
144
+ Two.new.meth(2,4).should == 8 # meth.2
145
+ # two different injector versions
146
+ One.new.meth(3).should == 27 # meth.1
147
+ #############################
148
+ #
149
+
150
+ end
151
+
152
+ # we can update individual object instances but not classes directly
153
+ # this is unavailable because class injection is pervasive
154
+ the 'simple re-injection is different for classes: it fails ' do
155
+
156
+ # re-injection can happen on individual object instances
157
+ One.new.enrich(Version2).meth(4,5).should == 20 # meth.2 works!!
158
+
159
+ # re-injection applying version 2 to class One has no effect
160
+ One.inject Version2
161
+ expect{ One.new.meth(4,5) }.to raise_error(ArgumentError) # meth.2: fails!!
162
+
163
+ end
164
+
165
+ the 'way to class level injector updates is through the Strategy Pattern' do
166
+
167
+ # DO NOT want to necessarily update older clients of the class
168
+ # but possible if needed
169
+
170
+ class One
171
+ eject Version1 # eject version 1
172
+
173
+ inject Version2 # re-inject with prolonged injector -- can be any version
174
+ end
175
+ One.new.meth(4,5).should == 20 # meth.2 now available!!
176
+
177
+ ################################################
178
+ # We feel this is the correct approach but has #
179
+ # a sllight syntactical handicap/ambiguity #
180
+ ################################################
181
+
182
+ end
183
+
184
+ a 'preferred way as of late: private updates --could change' do
185
+
186
+ Versions do
187
+ def meth(*args)
188
+ args.inject(&:+)
189
+ end
190
+ end
191
+
192
+ class One
193
+ update Versions() # changes strategy for you
194
+ # by design a private method as sign of its delicate nature
195
+ end
196
+
197
+ # or ....
198
+
199
+ One.send :update, Versions()
200
+ One.new.meth( 3,4,5,6 ).should == 18 # new version now available!
201
+
202
+ end
203
+
204
+ a 'different use case' do
205
+
206
+ class Freak
207
+
208
+ injector :freaky
209
+ freaky do
210
+ def twitch
211
+ '_-=-_-=-_-=-_-=-_'
212
+ end
213
+ end
214
+ inject freaky
215
+
216
+ end
217
+ Freak.new.twitch.should == '_-=-_-=-_-=-_-=-_'
218
+
219
+ class Freak
220
+
221
+ freaky do
222
+ def twitch
223
+ '/\/\/\/\/\/\/\/\/\/'
224
+ end
225
+ end
226
+ update freaky
227
+
228
+ end
229
+ Freak.new.twitch.should == '/\/\/\/\/\/\/\/\/\/'
230
+
231
+ end
232
+
233
+ there 'is a different way todo global updates on Injectors: use define_method' do
234
+
235
+ SomeJack = jack :some_jack do
236
+ def foo_bar
237
+ 'a foo and a bar'
238
+ end
239
+ end
240
+
241
+ class Client
242
+ inject SomeJack
243
+ end
244
+
245
+ Client.new.foo_bar.should == 'a foo and a bar' # expected
246
+
247
+ some_jack do
248
+ define_method :foo_bar do
249
+ 'fooooo and barrrrr'
250
+ end
251
+ end
252
+
253
+ Client.new.foo_bar.should == 'fooooo and barrrrr' # different
254
+
255
+ end
256
+ end
257
+
258
+ describe "utility of injector versioning: " do
259
+
260
+ it 'allows to easily override methods without affecting other parts of your program' do
261
+
262
+ J1 = injector :j do
263
+ def meth(arg)
264
+ arg
265
+ end
266
+ end
267
+
268
+ class AA4
269
+ inject J1
270
+ end
271
+ AA4.new.meth(3).should == 3
272
+
273
+ J2 = j do
274
+ def meth(arg)
275
+ arg *arg
276
+ end
277
+ end
278
+
279
+ class BBB
280
+ inject J2
281
+ end
282
+ BBB.new.meth(3).should == 9
283
+
284
+ AA4.new.meth(3).should == 3
285
+
286
+ end
287
+
288
+ the "local binding of injectors" do
289
+
290
+ #_____________________
291
+ # injector declaration
292
+ VersionOne = injector :functionality do
293
+ def basic arg # version basic.1
294
+ arg * 2
295
+ end
296
+ end
297
+
298
+ o = Object.new.enrich VersionOne # apply --first snapshot
299
+ o.basic(1).should == 2 # basic.1
300
+
301
+
302
+ #_____________________
303
+ # injector prolongation
304
+ VersionTwo = functionality do
305
+ def basic arg # basic.2 ... basic.1 redefined
306
+ arg * 3
307
+ end
308
+
309
+ def compound # compound.1 --bound locally to basic.2
310
+ basic(3) + 2
311
+ end
312
+ end
313
+
314
+ p = Object.new.enrich VersionTwo # apply --second snapshot (like above)
315
+ p.basic(1).should == 3 # basic.2
316
+ p.compound.should == 11 # compound.1
317
+
318
+
319
+ # result
320
+ ###################################
321
+
322
+ o.basic(1).should == 2 # basic.1
323
+ o.compound.should == 11 # compound.1 --local injector binding
324
+
325
+ ###################################
326
+ # This ensures #compound.1 keeps bound
327
+ # to the right version #basic.2
328
+
329
+ end
330
+
331
+ end
332
+ end
333
+
334
+
@@ -0,0 +1,410 @@
1
+ require "spec_helper"
2
+ =begin rdoc
3
+ This file contains the specs for the GOF Decorator Pattern and
4
+ Strategy Pattern use cases for injectors.
5
+ =end
6
+
7
+ include Injectors
8
+
9
+ describe 'some use cases', :injectors do
10
+
11
+ describe 'GOF Decortors is one use of this codebase. Traditionally this is only partially solved in Ruby through PORO
12
+ decorators or the use of modules with the problems of loss of class identity for the former
13
+ or the limitations on the times it can be re-applied for the latter. We solve that!!' do
14
+
15
+ the 'GOF class decorator' do
16
+
17
+ class Coffee
18
+ def cost
19
+ 1.50
20
+ end
21
+ end
22
+
23
+ injector :milk do
24
+ def cost
25
+ super() + 0.30
26
+ end
27
+ end
28
+ injector :vanilla do
29
+ def cost
30
+ super() + 0.15
31
+ end
32
+ end
33
+
34
+ cup = Coffee.new.enrich(milk).enrich(vanilla)
35
+ cup.should be_instance_of(Coffee)
36
+ cup.cost.should == 1.95
37
+
38
+ end
39
+
40
+ this 'can then be applied multiple times to the same receiver:' do
41
+
42
+ class Coffee
43
+ def cost
44
+ 1.50
45
+ end
46
+ end
47
+
48
+ jack :milk do
49
+ def cost
50
+ super() + 0.30
51
+ end
52
+ end
53
+ jack :vanilla do
54
+ def cost
55
+ super() + 0.15
56
+ end
57
+ end
58
+
59
+ cup = Coffee.new.enrich(milk).enrich(vanilla).enrich(vanilla)
60
+ cup.injectors.sym_list.should == [:milk, :vanilla, :vanilla]
61
+ cup.cost.should == 2.10
62
+ cup.should be_instance_of(Coffee)
63
+
64
+ end
65
+
66
+ the 'a further workflow' do
67
+
68
+ class Coffee
69
+ def cost
70
+ 1.50
71
+ end
72
+ end
73
+
74
+ jack :milk do
75
+ def cost
76
+ super() + 0.30
77
+ end
78
+ end
79
+ jack :vanilla do
80
+ def cost
81
+ super() + 0.15
82
+ end
83
+ end
84
+
85
+ cup = Coffee.new.enrich(milk).enrich(vanilla)
86
+ cup.should be_instance_of(Coffee)
87
+ cup.cost.should == 1.95
88
+
89
+ user_input = 'extra red vanilla'
90
+ vanilla do
91
+ define_method :appearance do
92
+ user_input
93
+ end
94
+ end
95
+
96
+ cup.enrich(vanilla)
97
+ cup.injectors.sym_list.should == [:milk, :vanilla, :vanilla]
98
+ cup.cost.should == 2.10
99
+ cup.appearance.should == 'extra red vanilla'
100
+
101
+ end
102
+
103
+ a 'bigger example' do
104
+
105
+ # some data
106
+
107
+ def database_content
108
+ %{car truck airplane boat}
109
+ end
110
+
111
+ # rendering helper controls
112
+
113
+ class MyWidgetClass
114
+ def initialize(content)
115
+ @content = content
116
+ end
117
+
118
+ def render
119
+ "<div id='MyWidget'>#{@content}</div>"
120
+ end
121
+ end
122
+
123
+ injector :WidgetDecorator do
124
+ attr_reader :width, :height
125
+
126
+ def dim(width, heigth)
127
+ @width, @heigth = width, heigth
128
+ end
129
+ end
130
+
131
+ DesktopDecorator = WidgetDecorator do
132
+ def render
133
+ dim '600px', '200px'
134
+ %{
135
+ <style>
136
+ #MyWidget{
137
+ font: 14px, helvetica;
138
+ width:#{@width};
139
+ height: #{@heigth}
140
+ }
141
+ </style>
142
+ #{super()}
143
+ }
144
+ end
145
+ end
146
+
147
+ MobileDecorator = WidgetDecorator do
148
+ def render content
149
+ dim '200px', '600px'
150
+ %{
151
+ <style>
152
+ #MyWidget{
153
+ font: 10px, arial
154
+ width:#{@width}
155
+ height: #{@heigth}
156
+ }
157
+ </style>
158
+ #{super()}
159
+ }
160
+ end
161
+ end
162
+
163
+
164
+ # somewhere in a view
165
+
166
+ browser = 'Safari'
167
+ @content = database_content
168
+
169
+ my_widget = case browser
170
+ when match(/Safari|Firefox|IE/)
171
+ MyWidgetClass.new(@content).enrich(DesktopDecorator)
172
+ else
173
+ MyWidgetClass.new(@content).enrich(MobileDecorator)
174
+ end
175
+ expect(
176
+
177
+ my_widget.render.split.join).to eq( # split.join used for comparison
178
+ %{
179
+ <style>
180
+ #MyWidget {
181
+ font: 14px, helvetica;
182
+ width:600px;
183
+ height:200px
184
+ }
185
+ </style>
186
+ <div id='MyWidget'>car truck airplane boat</div>
187
+ }.split.join
188
+ )
189
+
190
+ end
191
+
192
+ end
193
+
194
+ describe 'strategy pattern.' do
195
+
196
+ this 'is a pattern with changes the guts of an object as opposed to just changing its face. Traditional
197
+ examples of this pattern use PORO component injection within constructors. Here is an alternate
198
+ implementation' do
199
+
200
+ class Coffee
201
+
202
+ attr_reader :strategy
203
+ def initialize
204
+ @strategy = nil
205
+ end
206
+ def cost
207
+ 1.50
208
+ end
209
+ def brew
210
+ @strategy = 'normal-'
211
+ end
212
+ end
213
+
214
+ injector :Sweedish do
215
+ def brew
216
+ @strategy = 'sweedish-'
217
+ end
218
+ end
219
+ injector :French do
220
+ def brew
221
+ @strategy ='french-'
222
+ end
223
+ end
224
+
225
+ cup = Coffee.new
226
+ cup.brew
227
+ cup.strategy.should == 'normal-'
228
+
229
+ cup = Coffee.new.enrich(Sweedish()) # clobbers original strategy for this instance only
230
+ cup.brew
231
+ cup.strategy.should == ('sweedish-')
232
+
233
+ cup.enrich(French())
234
+ cup.brew
235
+ cup.strategy.should == ('french-')
236
+ end
237
+
238
+ this 'can be further enhanced by mixing it with the above decorator pattern' do
239
+
240
+ injector :Russian do
241
+ def brew
242
+ @strategy = super.to_s + 'vodka-'
243
+ end
244
+ end
245
+ injector :Scotish do
246
+ def brew
247
+ @strategy = super.to_s + 'wiskey-'
248
+ end
249
+ end
250
+
251
+ cup = Coffee.new
252
+ cup.enrich(Russian()).enrich(Scotish()).enrich(Russian())
253
+ cup.brew
254
+ cup.strategy.should == 'normal-vodka-wiskey-vodka-'
255
+
256
+ end
257
+
258
+ it 'is even better or possible to have yet another implementation. This time we completely
259
+ replace the current strategy by actually ejecting it out of the class and then injecting
260
+ a new one' do
261
+
262
+ class Tea < Coffee # Tea is a type of coffee ;~Q)
263
+ injector :SpecialStrategy do
264
+ def brew
265
+ @strategy = 'special'
266
+ end
267
+ end
268
+ inject SpecialStrategy()
269
+ end
270
+
271
+ cup = Tea.new
272
+ cup.brew
273
+ cup.strategy.should == 'special'
274
+ friends_cup = Tea.new
275
+ friends_cup.strategy == 'special'
276
+
277
+ Tea.eject :SpecialStrategy
278
+
279
+ Tea.inject Sweedish()
280
+ cup.brew
281
+ friends_cup.brew
282
+ cup.strategy.should == 'sweedish-'
283
+ friends_cup.strategy.should == 'sweedish-'
284
+
285
+ Tea.eject Sweedish()
286
+
287
+ Tea.inject French()
288
+ cup.brew
289
+ friends_cup.brew
290
+ cup.strategy == 'french-'
291
+ friends_cup.strategy.should == 'french-'
292
+
293
+ end
294
+
295
+ end
296
+
297
+ describe "further Jackbox Injector workflows" do
298
+
299
+ it "allows adding decorators with function to be defined at later statge" do
300
+
301
+ class Widget
302
+ def cost
303
+ 1
304
+ end
305
+ end
306
+ w = Widget.new
307
+
308
+ injector :decorator
309
+ w.enrich decorator, decorator, decorator, decorator
310
+
311
+ # user input
312
+ bid = 3.5
313
+
314
+ # define function
315
+ decorator do
316
+ # Global define
317
+ define_method :cost do
318
+ super() + bid
319
+ end
320
+ end
321
+
322
+ w.cost.should == 15
323
+
324
+ end
325
+
326
+ it "allows for the following workflow using super" do
327
+
328
+ jack :Superb
329
+
330
+ Superb do
331
+ def process string, additives, index
332
+ str = string.gsub('o', additives.slice!(index))
333
+ super(string, additives, index) + str rescue str
334
+ end
335
+ extend Superb(), Superb(), Superb()
336
+ end
337
+
338
+ Superb().process( 'food ', 'aeiu', 0 ).should == 'fuud fiid feed faad '
339
+ Superb(:implode)
340
+
341
+ end
342
+
343
+ it 'allows for the following strategy workflow using soft tags' do
344
+
345
+ ###########################################################################
346
+ # For a specific example of what can be accomplished using this workflow #
347
+ # please refer to the examples directory under transformers spec #
348
+ # #
349
+ # #########################################################################
350
+
351
+ jack :Solution
352
+
353
+ Solution( :tag ) do
354
+ def solution
355
+ 1
356
+ end
357
+ end
358
+ Solution( :tag ) do
359
+ def solution
360
+ 2
361
+ end
362
+ end
363
+ Solution( :tag ) do
364
+ def solution
365
+ 3
366
+ end
367
+ end
368
+
369
+
370
+ class Client
371
+ inject Solution()
372
+
373
+ def self.solve
374
+ Solution().tags.each { |e|
375
+ update e
376
+ puts new.solution rescue nil
377
+ }
378
+
379
+ # or...
380
+
381
+ solutions = Solution().tags.each
382
+ begin
383
+ update solutions.next
384
+ puts solved = new().solution()
385
+ end until solved
386
+ solved
387
+ end
388
+
389
+ end
390
+
391
+ $stdout.should_receive(:puts).with(1)
392
+ $stdout.should_receive(:puts).with(2)
393
+ $stdout.should_receive(:puts).with(3)
394
+ $stdout.should_receive(:puts).with(1)
395
+
396
+ Client.solve
397
+
398
+ end
399
+
400
+ end
401
+
402
+ # describe 'use in rails' do
403
+ #
404
+ # it 'allows replacing draper'
405
+ # it 'allows decorating anything not just models'
406
+ #
407
+ # end
408
+
409
+ end
410
+