jackbox 0.9.6.3 → 0.9.6.6
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.
- checksums.yaml +5 -13
- data/CHANGES.txt +38 -4
- data/LICENSE.lic +0 -0
- data/README.md +568 -364
- data/lib/jackbox.rb +1 -1
- data/lib/jackbox/injectors.rb +1 -1
- data/lib/jackbox/injectors/coda.rb +2 -0
- data/lib/jackbox/injectors/prelude.rb +2 -0
- data/lib/jackbox/rake.rb +1 -1
- data/lib/jackbox/tools/prefs.rb +1 -1
- data/lib/jackbox/version.rb +1 -1
- data/spec/lib/jackbox/injector_composition_spec.rb +111 -111
- data/spec/lib/jackbox/injector_directives_spec.rb +25 -27
- data/spec/lib/jackbox/injector_inheritance_spec.rb +610 -1004
- data/spec/lib/jackbox/injector_introspection_spec.rb +265 -219
- data/spec/lib/jackbox/injector_namespacing_spec.rb +17 -17
- data/spec/lib/jackbox/injector_spec.rb +26 -0
- data/spec/lib/jackbox/injector_versioning_spec.rb +37 -37
- data/spec/lib/jackbox/jiti_rules_spec.rb +663 -0
- data/spec/lib/jackbox/patterns_spec.rb +224 -122
- data/spec/lib/jackbox/prefs_spec.rb +4 -4
- data/spec/lib/jackbox/reclassing_spec.rb +154 -406
- data/spec/lib/jackbox/vmc_spec.rb +169 -10
- data/spec/lib/jackbox_spec.rb +241 -131
- metadata +26 -26
- data/spec/lib/jackbox/examples/dx_spec.rb +0 -346
@@ -1,34 +1,34 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
=begin rdoc
|
3
3
|
|
4
|
-
Name spacing of
|
4
|
+
Name spacing of traits
|
5
5
|
Author: LHA
|
6
6
|
|
7
7
|
|
8
8
|
|
9
|
-
Description of the difference between the different namespacing options of
|
9
|
+
Description of the difference between the different namespacing options of traits:
|
10
10
|
|
11
|
-
|
11
|
+
trait :Main
|
12
12
|
vs.
|
13
|
-
|
13
|
+
trait :main
|
14
14
|
|
15
15
|
module X
|
16
|
-
|
16
|
+
trait :Some_Injector
|
17
17
|
vs.
|
18
|
-
|
18
|
+
trait :some_trait
|
19
19
|
end
|
20
20
|
|
21
21
|
class Y
|
22
|
-
|
22
|
+
trait :Other_Injector
|
23
23
|
vs.
|
24
|
-
|
24
|
+
trait :other_trait
|
25
25
|
end
|
26
26
|
|
27
27
|
=end
|
28
28
|
|
29
29
|
###########################
|
30
|
-
|
31
|
-
|
30
|
+
trait :Major
|
31
|
+
trait :minor
|
32
32
|
###########################
|
33
33
|
|
34
34
|
# upper case vs lower case: semantically equivalent
|
@@ -73,8 +73,8 @@ end
|
|
73
73
|
|
74
74
|
###############################
|
75
75
|
module X
|
76
|
-
|
77
|
-
|
76
|
+
trait :Maxi # use sparringly
|
77
|
+
trait :mini
|
78
78
|
end
|
79
79
|
################################
|
80
80
|
|
@@ -144,9 +144,9 @@ end
|
|
144
144
|
# Should follow the same line
|
145
145
|
#
|
146
146
|
class Y
|
147
|
-
|
147
|
+
trait :Other_Injector
|
148
148
|
# vs.
|
149
|
-
|
149
|
+
trait :other_trait
|
150
150
|
end
|
151
151
|
#
|
152
152
|
# No example needed!!
|
@@ -156,12 +156,12 @@ end
|
|
156
156
|
|
157
157
|
|
158
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
|
160
|
-
describe '
|
159
|
+
# work with trait versions there is a need to tag/name the different versions for later use.
|
160
|
+
describe 'trait Tagging/Naming and its relationship to Injector Versioning' do
|
161
161
|
|
162
162
|
there 'is way to tag/name a particular version for later reuse' do
|
163
163
|
|
164
|
-
|
164
|
+
trait :Bar
|
165
165
|
|
166
166
|
Tag = Bar do
|
167
167
|
def foo_bar
|
@@ -839,6 +839,32 @@ describe Injectors, :injectors do
|
|
839
839
|
|
840
840
|
end
|
841
841
|
|
842
|
+
it 'ejects inherited tags' do
|
843
|
+
|
844
|
+
EjectionTag1 = jack :ejection_test do
|
845
|
+
def m1
|
846
|
+
2
|
847
|
+
end
|
848
|
+
end
|
849
|
+
|
850
|
+
EjectionTag2 = ejection_test do
|
851
|
+
def m1
|
852
|
+
super + 2 # override --jit inheritance
|
853
|
+
end
|
854
|
+
end
|
855
|
+
|
856
|
+
o = Object.new.enrich EjectionTag2
|
857
|
+
o.m1.should == 4
|
858
|
+
# o.metaclass.ancestors.to_s.should match(/EjectionTag2.*EjectionTag1/)
|
859
|
+
|
860
|
+
o.eject EjectionTag2
|
861
|
+
expect{o.m1}.to raise_error(NoMethodError)
|
862
|
+
o.metaclass.ancestors.to_s.should_not match(/EjectionTag2/)
|
863
|
+
o.metaclass.ancestors.to_s.should_not match(/EjectionTag2.*EjectionTag1/)
|
864
|
+
o.metaclass.ancestors.to_s.should_not match(/EjectionTag1/)
|
865
|
+
|
866
|
+
end
|
867
|
+
|
842
868
|
end
|
843
869
|
end
|
844
870
|
|
@@ -2,29 +2,29 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
include Injectors
|
4
4
|
|
5
|
-
describe 'Injector versioning:', :
|
6
|
-
# subsequent redefinitions of methods constitute another version of the
|
5
|
+
describe 'Injector versioning:', :traits do
|
6
|
+
# subsequent redefinitions of methods constitute another version of the trait. Injector
|
7
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
|
9
|
-
# gets applied to an object. From, that point on the object contains only that version of methods from that
|
10
|
-
# any subsequent overrides to those methods are only members of the "prolongation" of the
|
8
|
+
# certain set of methods and their associated outputs and represents a snapshot of that trait 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 trait, and
|
10
|
+
# any subsequent overrides to those methods are only members of the "prolongation" of the trait and do not become part
|
11
11
|
# of the object of injection unless some form of reinjection occurs. Newer versions of methods only become part of newer
|
12
12
|
# objects or newer injections into existing targets'
|
13
13
|
|
14
|
-
describe '
|
14
|
+
describe 'trait versioning and its relationship to object instances' do
|
15
15
|
|
16
|
-
the '
|
17
|
-
# using only that version of methods as the object of injection. AA4ny overrides to methods in any subsequent
|
18
|
-
# do not take effect in this target. AA4ny new methods added to the
|
16
|
+
the 'trait versioning uses a snapshot of the trait`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 trait prolongations
|
18
|
+
# do not take effect in this target. AA4ny new methods added to the trait do become available to the target, although
|
19
19
|
# may contain internal references to newer versions of the target methods. This ensures to keep everyting working correctly.'
|
20
20
|
|
21
21
|
#___________________
|
22
|
-
#
|
23
|
-
|
22
|
+
# trait declaration
|
23
|
+
trait :My_trait
|
24
24
|
|
25
25
|
#___________________
|
26
|
-
#
|
27
|
-
|
26
|
+
# trait first prolongation
|
27
|
+
My_trait do
|
28
28
|
def bar
|
29
29
|
:a_bar # version bar.1
|
30
30
|
end
|
@@ -34,12 +34,12 @@ describe 'Injector versioning:', :injectors do
|
|
34
34
|
end
|
35
35
|
|
36
36
|
object1 = Object.new
|
37
|
-
object1.enrich
|
37
|
+
object1.enrich My_trait() # apply the trait --first snapshot
|
38
38
|
object1.bar.should == :a_bar # pass the test
|
39
39
|
|
40
40
|
#__________________
|
41
|
-
#
|
42
|
-
|
41
|
+
# trait second prolongation
|
42
|
+
My_trait do
|
43
43
|
def bar
|
44
44
|
:some_larger_bar # version bar.2 ... re-defines bar
|
45
45
|
end
|
@@ -49,7 +49,7 @@ describe 'Injector versioning:', :injectors do
|
|
49
49
|
end
|
50
50
|
|
51
51
|
object2 = Object.new
|
52
|
-
object2.enrich
|
52
|
+
object2.enrich My_trait() # apply the trait --second snapshot
|
53
53
|
object2.bar.should == :some_larger_bar
|
54
54
|
|
55
55
|
# result
|
@@ -66,7 +66,7 @@ describe 'Injector versioning:', :injectors do
|
|
66
66
|
|
67
67
|
#_________________
|
68
68
|
# re-injection
|
69
|
-
enrich
|
69
|
+
enrich My_trait() # re-injection on any object instance
|
70
70
|
bar.should == :some_larger_bar # bar.2 now available
|
71
71
|
|
72
72
|
expect{some_other_function}.to_not raise_error # some_other_function.1 is present
|
@@ -77,7 +77,7 @@ describe 'Injector versioning:', :injectors do
|
|
77
77
|
|
78
78
|
o = Object.new
|
79
79
|
|
80
|
-
|
80
|
+
trait :some_methods do
|
81
81
|
def meth arg
|
82
82
|
arg
|
83
83
|
end
|
@@ -103,19 +103,19 @@ describe 'Injector versioning:', :injectors do
|
|
103
103
|
|
104
104
|
end
|
105
105
|
|
106
|
-
describe "
|
107
|
-
# similar to object level versioning in that it uses a snapshot of the
|
106
|
+
describe "trait versioning and its relationship to classes" do
|
107
|
+
# similar to object level versioning in that it uses a snapshot of the trait`s existing methods up to the point of injection, using only
|
108
108
|
# that version of methods as the object of injection. But, unlike object level versioning, because class injection is static, reinjection
|
109
109
|
# does not change the class unless we use the Strategy Pattern which completely changes the class's strategy of methods"
|
110
110
|
|
111
|
-
the "class
|
111
|
+
the "class trait versioning is similar to object trait versioning" do
|
112
112
|
|
113
113
|
#___________________
|
114
|
-
#
|
115
|
-
|
114
|
+
# trait declaration:
|
115
|
+
trait :Versions
|
116
116
|
|
117
117
|
#___________________
|
118
|
-
#
|
118
|
+
# trait first prolongation
|
119
119
|
Version1 = Versions do
|
120
120
|
def meth arg # version meth.1
|
121
121
|
arg ** arg
|
@@ -127,7 +127,7 @@ describe 'Injector versioning:', :injectors do
|
|
127
127
|
end
|
128
128
|
|
129
129
|
#_________________
|
130
|
-
#
|
130
|
+
# trait second prolongation
|
131
131
|
Version2 = Versions do
|
132
132
|
def meth arg1, arg2 # version meth.2 ... redefines meth.1
|
133
133
|
arg1 * arg2
|
@@ -142,7 +142,7 @@ describe 'Injector versioning:', :injectors do
|
|
142
142
|
# result
|
143
143
|
#############################
|
144
144
|
Two.new.meth(2,4).should == 8 # meth.2
|
145
|
-
# two different
|
145
|
+
# two different trait versions
|
146
146
|
One.new.meth(3).should == 27 # meth.1
|
147
147
|
#############################
|
148
148
|
#
|
@@ -162,7 +162,7 @@ describe 'Injector versioning:', :injectors do
|
|
162
162
|
|
163
163
|
end
|
164
164
|
|
165
|
-
the 'way to class level
|
165
|
+
the 'way to class level trait updates is through the Strategy Pattern' do
|
166
166
|
|
167
167
|
# DO NOT want to necessarily update older clients of the class
|
168
168
|
# but possible if needed
|
@@ -170,7 +170,7 @@ describe 'Injector versioning:', :injectors do
|
|
170
170
|
class One
|
171
171
|
eject Version1 # eject version 1
|
172
172
|
|
173
|
-
inject Version2 # re-inject with prolonged
|
173
|
+
inject Version2 # re-inject with prolonged trait -- can be any version
|
174
174
|
end
|
175
175
|
One.new.meth(4,5).should == 20 # meth.2 now available!!
|
176
176
|
|
@@ -205,7 +205,7 @@ describe 'Injector versioning:', :injectors do
|
|
205
205
|
|
206
206
|
class Freak
|
207
207
|
|
208
|
-
|
208
|
+
trait :freaky
|
209
209
|
freaky do
|
210
210
|
def twitch
|
211
211
|
'_-=-_-=-_-=-_-=-_'
|
@@ -255,11 +255,11 @@ describe 'Injector versioning:', :injectors do
|
|
255
255
|
end
|
256
256
|
end
|
257
257
|
|
258
|
-
describe "utility of
|
258
|
+
describe "utility of trait versioning: " do
|
259
259
|
|
260
260
|
it 'allows to easily override methods without affecting other parts of your program' do
|
261
261
|
|
262
|
-
J1 =
|
262
|
+
J1 = trait :j do
|
263
263
|
def meth(arg)
|
264
264
|
arg
|
265
265
|
end
|
@@ -285,11 +285,11 @@ describe 'Injector versioning:', :injectors do
|
|
285
285
|
|
286
286
|
end
|
287
287
|
|
288
|
-
the "local binding of
|
288
|
+
the "local binding of traits" do
|
289
289
|
|
290
290
|
#_____________________
|
291
|
-
#
|
292
|
-
VersionOne =
|
291
|
+
# trait declaration
|
292
|
+
VersionOne = trait :functionality do
|
293
293
|
def basic arg # version basic.1
|
294
294
|
arg * 2
|
295
295
|
end
|
@@ -300,7 +300,7 @@ describe 'Injector versioning:', :injectors do
|
|
300
300
|
|
301
301
|
|
302
302
|
#_____________________
|
303
|
-
#
|
303
|
+
# trait prolongation
|
304
304
|
VersionTwo = functionality do
|
305
305
|
def basic arg # basic.2 ... basic.1 redefined
|
306
306
|
arg * 3
|
@@ -321,7 +321,7 @@ describe 'Injector versioning:', :injectors do
|
|
321
321
|
|
322
322
|
o.basic(1).should == 2 # basic.1
|
323
323
|
# debugger
|
324
|
-
o.compound.should == 11 # compound.1 --local
|
324
|
+
o.compound.should == 11 # compound.1 --local trait binding
|
325
325
|
|
326
326
|
###################################
|
327
327
|
# This ensures #compound.1 keeps bound
|
@@ -0,0 +1,663 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe 'jit inheriatnce' do
|
4
|
+
|
5
|
+
before do
|
6
|
+
|
7
|
+
suppress_warnings do
|
8
|
+
|
9
|
+
#
|
10
|
+
# Trait
|
11
|
+
#
|
12
|
+
trait :Functionality
|
13
|
+
|
14
|
+
#
|
15
|
+
# Works like class inheritance
|
16
|
+
#
|
17
|
+
Tag1 = Functionality do
|
18
|
+
def m1
|
19
|
+
1
|
20
|
+
end
|
21
|
+
|
22
|
+
def m2
|
23
|
+
:m2
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
Functionality do
|
28
|
+
def other # No overrides No inheritance
|
29
|
+
'other' # -- same ancestors as before
|
30
|
+
end # -- normal trait inheritance
|
31
|
+
end
|
32
|
+
|
33
|
+
Tag2 = Functionality do
|
34
|
+
def m1 # The :m1 override invokes JIT inheritance
|
35
|
+
super + 1 # -- Tag1 is added as ancestor
|
36
|
+
end # -- allows the use of super
|
37
|
+
|
38
|
+
def m3
|
39
|
+
'em3'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class AA6
|
44
|
+
inject Tag2
|
45
|
+
end
|
46
|
+
|
47
|
+
Tag3 = Functionality() do
|
48
|
+
def m1
|
49
|
+
super * 2 # second override to #m1
|
50
|
+
end # -- Tag2 added as ancestor
|
51
|
+
def m3
|
52
|
+
super * 2 # first override to #m3
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class AA7
|
57
|
+
inject Tag3
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
after do
|
64
|
+
|
65
|
+
suppress_warnings do
|
66
|
+
|
67
|
+
Tag1 = nil
|
68
|
+
Tag2 = nil
|
69
|
+
Tag3 = nil
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
Functionality(:implode)
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'works under boejct extension' do
|
78
|
+
|
79
|
+
o = Object.new.extend Tag3
|
80
|
+
o.m1.should == 4
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'also works under class inclusion' do
|
85
|
+
|
86
|
+
#
|
87
|
+
# Under Inclusion
|
88
|
+
#
|
89
|
+
class AA6
|
90
|
+
inject Tag2
|
91
|
+
end
|
92
|
+
aa6 = AA6.new
|
93
|
+
|
94
|
+
# JIT inherited
|
95
|
+
aa6.m1.should == 2
|
96
|
+
aa6.m3.should == 'em3'
|
97
|
+
|
98
|
+
# Version inherited
|
99
|
+
aa6.m2.should == :m2
|
100
|
+
aa6.other.should == 'other'
|
101
|
+
|
102
|
+
Functionality().tags.should == [Tag1, Tag2, Tag3]
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'goes on down the levels' do
|
107
|
+
|
108
|
+
#
|
109
|
+
# Different client/Diferent Tag
|
110
|
+
#
|
111
|
+
class AA7
|
112
|
+
inject Tag3
|
113
|
+
end
|
114
|
+
aa7 = AA7.new
|
115
|
+
|
116
|
+
# JIT inherited
|
117
|
+
aa7.m1.should == 4
|
118
|
+
aa7.m3.should == 'em3em3'
|
119
|
+
|
120
|
+
# regular inheritance
|
121
|
+
aa7.m2.should == :m2
|
122
|
+
aa7.other.should == 'other'
|
123
|
+
|
124
|
+
Functionality().tags.should == [Tag1, Tag2, Tag3]
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'keeps the main trait in sync with the last tag' do
|
129
|
+
|
130
|
+
o = Object.new.extend Tag3
|
131
|
+
p = Object.new.extend Functionality()
|
132
|
+
|
133
|
+
# test it
|
134
|
+
|
135
|
+
o.m1.should == 4
|
136
|
+
p.m1.should == 4
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'allows rebasing individual methods' do
|
141
|
+
|
142
|
+
#
|
143
|
+
# Another prolongation: back to basics
|
144
|
+
#
|
145
|
+
Tag4 = Functionality() do
|
146
|
+
def m1 # another override but no call to #super
|
147
|
+
:m1 # -- just simple override
|
148
|
+
end # -- could be tagged if needed
|
149
|
+
end
|
150
|
+
|
151
|
+
# test it
|
152
|
+
|
153
|
+
o = Object.new.extend( Tag4 )
|
154
|
+
|
155
|
+
# new version of #m1 !!
|
156
|
+
o.m1.should == :m1
|
157
|
+
|
158
|
+
# JIT inherited
|
159
|
+
o.m3.should == 'em3em3' # old jiti version of m3
|
160
|
+
|
161
|
+
# Version inherited
|
162
|
+
o.m2.should == :m2 # old version of m2
|
163
|
+
o.other.should == 'other'
|
164
|
+
|
165
|
+
# Total Tags
|
166
|
+
|
167
|
+
Functionality().tags.should == [Tag1, Tag2, Tag3, Tag4]
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'still holds on to earlier tag definitions' do
|
172
|
+
|
173
|
+
#
|
174
|
+
# Test previous Tags are unaffected !!
|
175
|
+
#
|
176
|
+
AA6.new.m1.should == 2 # includes Tag2
|
177
|
+
AA6.new.m2.should == :m2
|
178
|
+
AA6.new.m3.should == 'em3'
|
179
|
+
|
180
|
+
AA7.new.m1.should == 4 # includes Tag3
|
181
|
+
AA7.new.m2.should == :m2
|
182
|
+
AA7.new.m3.should == 'em3em3'
|
183
|
+
|
184
|
+
#
|
185
|
+
# other clients
|
186
|
+
#
|
187
|
+
class AA6B
|
188
|
+
inject Tag2
|
189
|
+
end
|
190
|
+
aa6b = AA6B.new
|
191
|
+
|
192
|
+
aa6b.m1.should == 2
|
193
|
+
aa6b.m2.should == :m2
|
194
|
+
aa6b.m3.should == 'em3'
|
195
|
+
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'keeps the VMC in proper working order' do
|
199
|
+
|
200
|
+
#
|
201
|
+
# VMC (Virtual Method Cache) method
|
202
|
+
#
|
203
|
+
Functionality() do
|
204
|
+
def m4
|
205
|
+
:m4
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
class AA6B
|
210
|
+
inject Tag2
|
211
|
+
end
|
212
|
+
aa6b = AA6B.new
|
213
|
+
|
214
|
+
# jit inherited
|
215
|
+
aa6b.m1.should == 2
|
216
|
+
aa6b.m3.should == 'em3'
|
217
|
+
|
218
|
+
# version inherited
|
219
|
+
aa6b.m2.should == :m2
|
220
|
+
aa6b.other.should == 'other'
|
221
|
+
|
222
|
+
aa6b.m4.should == :m4 # vmc method
|
223
|
+
|
224
|
+
# other clients of the VMC
|
225
|
+
AA6.new.m4.should == :m4
|
226
|
+
AA7.new.m4.should == :m4
|
227
|
+
|
228
|
+
end
|
229
|
+
|
230
|
+
it "allows further ancestor injection" do
|
231
|
+
|
232
|
+
module Mod1
|
233
|
+
def m4
|
234
|
+
:m4
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
Tag5 = Functionality(Mod1) do
|
239
|
+
|
240
|
+
include Mod1 # alternatively
|
241
|
+
|
242
|
+
def m1
|
243
|
+
super * 2
|
244
|
+
end
|
245
|
+
def m3
|
246
|
+
:m3 # m3 is rebased
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
# test it
|
251
|
+
|
252
|
+
# jit inherited
|
253
|
+
Object.new.extend(Tag5).m1.should == 8 # from Tag3
|
254
|
+
|
255
|
+
# version inherited
|
256
|
+
Object.new.extend(Tag5).m2.should == :m2 # from Tag1
|
257
|
+
|
258
|
+
# rebased
|
259
|
+
Object.new.extend(Tag5).m3.should == :m3 # from Tag5
|
260
|
+
|
261
|
+
# ancestor injection
|
262
|
+
Object.new.extend(Tag5).m4.should == :m4 # from Mod1
|
263
|
+
|
264
|
+
end
|
265
|
+
|
266
|
+
it "also allows on the fly overrides" do
|
267
|
+
|
268
|
+
#
|
269
|
+
# On the fly overrides
|
270
|
+
#
|
271
|
+
obj = Object.new.extend(
|
272
|
+
Functionality {
|
273
|
+
def m1
|
274
|
+
super + 3 # on top of Tag1, Tag2, Tag3
|
275
|
+
end
|
276
|
+
def m4
|
277
|
+
:m4
|
278
|
+
end
|
279
|
+
})
|
280
|
+
|
281
|
+
# new jiti override
|
282
|
+
obj.m1.should == 7
|
283
|
+
|
284
|
+
# version inherited
|
285
|
+
obj.m2.should == :m2
|
286
|
+
obj.m3.should == 'em3em3'
|
287
|
+
obj.m4.should == :m4
|
288
|
+
|
289
|
+
# other prolongation
|
290
|
+
|
291
|
+
Object.new.extend(Functionality(){
|
292
|
+
def m3
|
293
|
+
super * 2
|
294
|
+
end
|
295
|
+
}).m3.should == 'em3em3em3em3'
|
296
|
+
|
297
|
+
end
|
298
|
+
|
299
|
+
it "blocks external ancestor intrusion enforcing internal trait consistency" do
|
300
|
+
|
301
|
+
#########################################
|
302
|
+
# Masks Ancestor intrussion
|
303
|
+
#
|
304
|
+
|
305
|
+
Tag6 = Functionality do
|
306
|
+
def m1 # Injector has internal base
|
307
|
+
1
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
module Mod1
|
312
|
+
def m1
|
313
|
+
'one'
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
Tag7 = Functionality(Mod1) do # Mod1 attempts to intrude on base
|
318
|
+
|
319
|
+
include Mod1
|
320
|
+
|
321
|
+
def m1
|
322
|
+
super * 2
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
# test it
|
327
|
+
|
328
|
+
o = Object.new.extend(Tag7)
|
329
|
+
# jit inherited
|
330
|
+
o.m1.should == 2 # no such luck!!
|
331
|
+
|
332
|
+
p = Object.new.extend(Functionality())
|
333
|
+
# jit inherited
|
334
|
+
p.m1.should == 2 # no such luck!!
|
335
|
+
|
336
|
+
# version inherited
|
337
|
+
o.m2.should == :m2 # from Tag1
|
338
|
+
p.m2.should == :m2
|
339
|
+
|
340
|
+
end
|
341
|
+
|
342
|
+
it 'allows overriding methods further down the tree' do
|
343
|
+
|
344
|
+
Tag8 = Functionality do
|
345
|
+
def m1
|
346
|
+
1
|
347
|
+
end
|
348
|
+
def m2 # original definition
|
349
|
+
2
|
350
|
+
end
|
351
|
+
end
|
352
|
+
Tag9 = Functionality do
|
353
|
+
def m1
|
354
|
+
'm1'
|
355
|
+
end # skipped #m2
|
356
|
+
end
|
357
|
+
Tag10 = Functionality do
|
358
|
+
def m1
|
359
|
+
super * 2
|
360
|
+
end
|
361
|
+
def m2
|
362
|
+
super * 2 # override # m2 two levels down
|
363
|
+
end
|
364
|
+
end
|
365
|
+
class AA10
|
366
|
+
inject Tag10
|
367
|
+
end
|
368
|
+
|
369
|
+
# test it
|
370
|
+
|
371
|
+
AA10.new.m1.should == 'm1m1'
|
372
|
+
AA10.new.m2 == 4
|
373
|
+
|
374
|
+
end
|
375
|
+
|
376
|
+
it 'allows rebasing (start fresh) methods at any level' do
|
377
|
+
|
378
|
+
Tag11 = Functionality do
|
379
|
+
def m1
|
380
|
+
1 # rebase Tag3
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
class AA11
|
385
|
+
inject Functionality() do
|
386
|
+
def m1
|
387
|
+
super + 1 # override
|
388
|
+
end
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
# test it
|
393
|
+
|
394
|
+
AA11.new.m1.should == 2
|
395
|
+
|
396
|
+
|
397
|
+
Tag12 = Functionality do
|
398
|
+
def m1
|
399
|
+
5 # rebase m1 again
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
class BB11
|
404
|
+
inject Functionality() do
|
405
|
+
def m1
|
406
|
+
super * 2 # new override
|
407
|
+
end
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
# test it
|
412
|
+
|
413
|
+
BB11.new.m1.should == 10
|
414
|
+
|
415
|
+
|
416
|
+
end
|
417
|
+
|
418
|
+
it 'slloed Injector Directives likr sll traits' do
|
419
|
+
|
420
|
+
Tag13 = Functionality do
|
421
|
+
def m1
|
422
|
+
1
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
class AA12
|
427
|
+
inject Functionality() do
|
428
|
+
def m1
|
429
|
+
super + 1
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
AA12.new.m1.should == 2
|
435
|
+
|
436
|
+
|
437
|
+
Tag14 = Functionality do
|
438
|
+
def m1
|
439
|
+
5 # rebase m1
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
class BB12
|
444
|
+
inject Functionality() do
|
445
|
+
def m1
|
446
|
+
super * 2 # new override
|
447
|
+
end
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
BB12.new.m1.should == 10
|
452
|
+
|
453
|
+
# test directives
|
454
|
+
|
455
|
+
Functionality(:silence)
|
456
|
+
|
457
|
+
AA12.new.m1.should == nil # both bases affected
|
458
|
+
BB12.new.m1.should == nil
|
459
|
+
|
460
|
+
Functionality(:active)
|
461
|
+
|
462
|
+
AA12.new.m1.should == 2 # both bases restored
|
463
|
+
BB12.new.m1.should == 10
|
464
|
+
|
465
|
+
end
|
466
|
+
|
467
|
+
end
|
468
|
+
|
469
|
+
describe 'jiti external basing' do
|
470
|
+
|
471
|
+
before do
|
472
|
+
|
473
|
+
#
|
474
|
+
# Injector
|
475
|
+
#
|
476
|
+
trait :Functionality
|
477
|
+
|
478
|
+
suppress_warnings do
|
479
|
+
|
480
|
+
module Base1 # EXTERNAL BASEs!!
|
481
|
+
def m1
|
482
|
+
2
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
module Base2
|
487
|
+
def m1
|
488
|
+
3
|
489
|
+
end
|
490
|
+
end
|
491
|
+
|
492
|
+
#
|
493
|
+
# Similar to Above
|
494
|
+
#
|
495
|
+
Tag1 = Functionality(Base1) do
|
496
|
+
|
497
|
+
# include Base1 # alternatively
|
498
|
+
|
499
|
+
def m2
|
500
|
+
:m2
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
Tag2 = Functionality do
|
505
|
+
def m1 # The :m1 override invokes JIT inheritance
|
506
|
+
super + 1 # -- Tag1 is added as ancestor
|
507
|
+
end # -- allows the use of super
|
508
|
+
|
509
|
+
def m3
|
510
|
+
'em3'
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
Tag3 = Functionality() do
|
515
|
+
def m1
|
516
|
+
super * 2 # second override to #m1
|
517
|
+
end # -- Tag2 added as ancestor
|
518
|
+
def m3
|
519
|
+
super * 2 # first override to #m3
|
520
|
+
end
|
521
|
+
end
|
522
|
+
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
526
|
+
after do
|
527
|
+
|
528
|
+
suppress_warnings do
|
529
|
+
|
530
|
+
Tag1 = nil
|
531
|
+
Tag2 = nil
|
532
|
+
Tag3 = nil
|
533
|
+
|
534
|
+
end
|
535
|
+
|
536
|
+
Functionality(:implode)
|
537
|
+
|
538
|
+
end
|
539
|
+
|
540
|
+
it 'works with initial external basing' do
|
541
|
+
|
542
|
+
o = Object.new.extend(Tag3)
|
543
|
+
o.m1.should == 6 # from Base1 thru Tag3
|
544
|
+
|
545
|
+
end
|
546
|
+
|
547
|
+
it 'also keeps the main trait in sync with the last tag' do
|
548
|
+
|
549
|
+
o = Object.new.extend(Tag3)
|
550
|
+
o.m1.should == 6
|
551
|
+
|
552
|
+
p = Object.new.extend(Functionality())
|
553
|
+
p.m1.should == 6
|
554
|
+
|
555
|
+
end
|
556
|
+
|
557
|
+
it 'follows the other normal rules' do
|
558
|
+
|
559
|
+
Tag15 = Functionality do
|
560
|
+
def m1
|
561
|
+
super() * 2 # on top of Tag3
|
562
|
+
end
|
563
|
+
def m2
|
564
|
+
:m2
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
p = Object.new.extend(Tag15)
|
569
|
+
p.m1.should == 12
|
570
|
+
|
571
|
+
end
|
572
|
+
|
573
|
+
it 'allows external base substitution --keeps the Trait Injector shell/casing' do
|
574
|
+
|
575
|
+
q = Object.new.extend(Functionality(Base2)) # on top or Tag3 thru Tag2....
|
576
|
+
q.m1.should == 8
|
577
|
+
|
578
|
+
end
|
579
|
+
|
580
|
+
it 'also allows other external base function' do
|
581
|
+
|
582
|
+
module Base2
|
583
|
+
def m4
|
584
|
+
'new'
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
Tag16 = Functionality(Base2) do
|
589
|
+
def m1
|
590
|
+
super / 2
|
591
|
+
end
|
592
|
+
def m2
|
593
|
+
super
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
597
|
+
p = Object.new.extend(Tag16)
|
598
|
+
|
599
|
+
p.m1.should == 4 # external rebase and thru Tag16, Tag3 and Tag2
|
600
|
+
p.m2.should == :m2
|
601
|
+
p.m4.should == 'new' # new function
|
602
|
+
|
603
|
+
end
|
604
|
+
|
605
|
+
it 'enforces internal basing once applied --blocks further external intrusion (like above)' do
|
606
|
+
|
607
|
+
Tag17 = Functionality(Base2) do
|
608
|
+
def m2
|
609
|
+
6 # rebase #m2
|
610
|
+
end
|
611
|
+
end
|
612
|
+
|
613
|
+
o = Object.new.extend(Functionality())
|
614
|
+
o.m1.should == 8 # Base2 thru Tag3 casing
|
615
|
+
o.m2.should == 6 # new #m2
|
616
|
+
|
617
|
+
Functionality() do
|
618
|
+
def m1
|
619
|
+
super + 1 # on top of Tag17
|
620
|
+
end
|
621
|
+
end
|
622
|
+
|
623
|
+
p = Object.new.extend Functionality()
|
624
|
+
p.m1.should == 9
|
625
|
+
|
626
|
+
module Base3
|
627
|
+
def m1
|
628
|
+
0 # new base
|
629
|
+
end
|
630
|
+
def m3
|
631
|
+
:m3 # muted by internal basing
|
632
|
+
end
|
633
|
+
end
|
634
|
+
|
635
|
+
p = Object.new.extend(Functionality(Base3))
|
636
|
+
p.m1.should == 3
|
637
|
+
p.m2.should == 6
|
638
|
+
p.m3.should == 'em3em3'
|
639
|
+
|
640
|
+
q = Object.new.extend(
|
641
|
+
Functionality() do
|
642
|
+
def m1
|
643
|
+
2 # internal rebase
|
644
|
+
end
|
645
|
+
end)
|
646
|
+
q.m1.should == 2
|
647
|
+
q.m2.should == 6
|
648
|
+
|
649
|
+
Tag18 = Functionality()
|
650
|
+
|
651
|
+
module Base4
|
652
|
+
def m1
|
653
|
+
'em1' # muted by internal rebasing
|
654
|
+
end
|
655
|
+
end
|
656
|
+
|
657
|
+
r = Object.new.extend(Functionality(Base4))
|
658
|
+
r.m1.should == 2
|
659
|
+
r.m2.should == 6
|
660
|
+
|
661
|
+
end
|
662
|
+
|
663
|
+
end
|