phenomenal 1.2.2 → 1.2.3
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.
- data/lib/phenomenal.rb +1 -0
- data/lib/phenomenal/context/context.rb +9 -1
- data/lib/phenomenal/context/context_creation.rb +3 -0
- data/lib/phenomenal/manager/conflict_policies.rb +13 -0
- data/lib/phenomenal/manager/manager.rb +0 -1
- data/lib/phenomenal/version.rb +1 -1
- data/lib/phenomenal/viewer/graphical.rb +1 -0
- data/spec/integration/conflict_policy_spec.rb +234 -87
- metadata +2 -2
data/lib/phenomenal.rb
CHANGED
@@ -7,7 +7,7 @@ class Phenomenal::Context
|
|
7
7
|
|
8
8
|
attr_accessor :activation_age, :activation_frequency, :adaptations,
|
9
9
|
:activation_count, :parent, :forgotten
|
10
|
-
attr_reader :manager,:name
|
10
|
+
attr_reader :manager,:name, :priority
|
11
11
|
# Instance methods
|
12
12
|
def initialize(name=nil, manager=nil)
|
13
13
|
@manager = manager || Phenomenal::Manager.instance
|
@@ -18,6 +18,7 @@ class Phenomenal::Context
|
|
18
18
|
@manager.register_context(self)
|
19
19
|
@parent=nil
|
20
20
|
@forgotten=false
|
21
|
+
@priority=nil
|
21
22
|
end
|
22
23
|
|
23
24
|
# Unregister the context from the context manager,
|
@@ -200,6 +201,13 @@ class Phenomenal::Context
|
|
200
201
|
end
|
201
202
|
end
|
202
203
|
|
204
|
+
def priority=(priority)
|
205
|
+
@priority=priority
|
206
|
+
return unless manager.shared_contexts[self]
|
207
|
+
manager.shared_contexts[self].each do |shared_context|
|
208
|
+
shared_context.priority=[priority,shared_context.priority].compact.min
|
209
|
+
end
|
210
|
+
end
|
203
211
|
private
|
204
212
|
def check_validity
|
205
213
|
if forgotten
|
@@ -58,6 +58,9 @@ module Phenomenal::ContextCreation
|
|
58
58
|
else
|
59
59
|
c = self.new(c)
|
60
60
|
end
|
61
|
+
# Inherit from parent priority
|
62
|
+
context.priority=[c.priority,context.priority].compact.min
|
63
|
+
|
61
64
|
instances.push(c)
|
62
65
|
manager.shared_contexts[c]= Array.new if !manager.shared_contexts[c]
|
63
66
|
manager.shared_contexts[c].push(context)
|
@@ -19,6 +19,19 @@ module Phenomenal::ConflictPolicies
|
|
19
19
|
context1.age <=> context2.age
|
20
20
|
end
|
21
21
|
|
22
|
+
# Priority based conflict resolution
|
23
|
+
def priority_conflict_policy(context1, context2)
|
24
|
+
if context1.priority && !context2.priority
|
25
|
+
-1
|
26
|
+
elsif context2.priority && !context1.priority
|
27
|
+
1
|
28
|
+
elsif context1.priority!=context2.priority
|
29
|
+
context1.priority <=> context2.priority
|
30
|
+
else
|
31
|
+
context1.age <=> context2.age
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
22
35
|
# Resolution policy
|
23
36
|
def conflict_policy(context1, context2)
|
24
37
|
age_conflict_policy(context1, context2)
|
data/lib/phenomenal/version.rb
CHANGED
@@ -50,6 +50,7 @@ class Phenomenal::Viewer::Graphical
|
|
50
50
|
self.main_graph = GraphViz::new("")
|
51
51
|
# Default options
|
52
52
|
self.main_graph[:compound] = "true"
|
53
|
+
self.main_graph[:rankdir]="LR"
|
53
54
|
self.main_graph.edge[:lhead] = ""
|
54
55
|
self.main_graph.edge[:ltail] = ""
|
55
56
|
self.main_graph.edge[:fontsize] = 10.0
|
@@ -16,7 +16,7 @@ describe "Conflict policies" do
|
|
16
16
|
adapt :advertise do |a_call|
|
17
17
|
"vibrator"
|
18
18
|
end
|
19
|
-
end
|
19
|
+
end
|
20
20
|
end
|
21
21
|
|
22
22
|
after :each do
|
@@ -25,119 +25,266 @@ describe "Conflict policies" do
|
|
25
25
|
phen_change_conflict_policy { |a,b| age_conflict_policy(a,b) }
|
26
26
|
end
|
27
27
|
|
28
|
-
|
28
|
+
describe "No resolution conflict policy" do
|
29
|
+
it "should not allow two contexts with an adaptation for the same method to be active at the same time" do
|
29
30
|
|
30
|
-
|
31
|
-
|
31
|
+
expect{activate_context(:screening)}.to_not raise_error
|
32
|
+
expect{activate_context(:quiet)}.to raise_error Phenomenal::Error
|
33
|
+
end
|
32
34
|
end
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
+
describe "Age resolution conflict policy" do
|
37
|
+
it "should set the age of the context such that the most recent one has the smaller age" do
|
38
|
+
phen_change_conflict_policy { |a,b| age_conflict_policy(a,b) }
|
36
39
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
+
phen_context_active?(phen_default_feature).should be_true
|
41
|
+
phen_context_active?(:screening).should be_false
|
42
|
+
phen_context_active?(:quiet).should be_false
|
40
43
|
|
41
|
-
|
44
|
+
phen_activate_context(:screening)
|
42
45
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
46
|
+
(phen_context_information(:screening)[:age] <
|
47
|
+
phen_context_information(phen_default_feature)[:age]).should be_true,
|
48
|
+
"screening context has been activated more recently than default"
|
49
|
+
|
50
|
+
phen_activate_context(:quiet)
|
51
|
+
(phen_context_information(:quiet)[:age] <
|
52
|
+
phen_context_information(:screening)[:age]).should be_true
|
53
|
+
"quiet context has been activated more recently than screening"
|
54
|
+
(phen_context_information(:screening)[:age] <
|
55
|
+
phen_context_information(phen_default_feature)[:age]).should be_true,
|
56
|
+
"quiet context has still been activated more recently than default"
|
57
|
+
phen_deactivate_context(:quiet)
|
58
|
+
phen_deactivate_context(:screening)
|
59
|
+
phen_activate_context(:screening)
|
60
|
+
(phen_context_information(:screening)[:age] <
|
61
|
+
phen_context_information(:quiet)[:age]).should be_true,
|
62
|
+
"screening context has now been activated more recently than quiet"
|
63
|
+
end
|
61
64
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
65
|
+
it "should choose the context the most recently activated" do
|
66
|
+
phen_change_conflict_policy { |a,b| age_conflict_policy(a,b) }
|
67
|
+
expect{activate_context(:screening)}.to_not raise_error
|
68
|
+
expect{activate_context(:quiet)}.to_not raise_error
|
69
|
+
end
|
67
70
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
71
|
+
it "should work with interleaved activation of contexts" do
|
72
|
+
phen_change_conflict_policy { |a,b| age_conflict_policy(a,b) }
|
73
|
+
phone = Phone.new
|
74
|
+
call = Call.new("Alice")
|
75
|
+
phone.receive(call)
|
73
76
|
|
74
|
-
|
77
|
+
phone.advertise(call).should=="ringtone"
|
75
78
|
|
76
|
-
|
77
|
-
|
79
|
+
activate_context(:quiet)
|
80
|
+
phone.advertise(call).should=="vibrator"
|
78
81
|
|
79
|
-
|
80
|
-
|
82
|
+
activate_context(:screening)
|
83
|
+
phone.advertise(call).should=="vibrator with screening"
|
81
84
|
|
82
|
-
|
83
|
-
|
85
|
+
deactivate_context(:quiet)
|
86
|
+
phone.advertise(call).should=="ringtone with screening"
|
84
87
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
+
deactivate_context(:screening)
|
89
|
+
phone.advertise(call).should=="ringtone"
|
90
|
+
end
|
88
91
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
92
|
+
it "should nest calls with the age policy" do
|
93
|
+
phen_change_conflict_policy { |a,b| age_conflict_policy(a,b) }
|
94
|
+
phone = Phone.new
|
95
|
+
call = Call.new("Alice")
|
96
|
+
phone.receive(call)
|
94
97
|
|
95
|
-
|
98
|
+
phone.advertise(call).should=="ringtone"
|
96
99
|
|
97
|
-
|
98
|
-
|
100
|
+
activate_context(:quiet)
|
101
|
+
phone.advertise(call).should=="vibrator"
|
99
102
|
|
100
|
-
|
101
|
-
|
103
|
+
activate_context(:screening)
|
104
|
+
phone.advertise(call).should=="vibrator with screening"
|
102
105
|
|
103
|
-
|
104
|
-
|
106
|
+
deactivate_context(:screening)
|
107
|
+
phone.advertise(call).should=="vibrator"
|
105
108
|
|
106
|
-
|
107
|
-
|
109
|
+
deactivate_context(:quiet)
|
110
|
+
phone.advertise(call).should=="ringtone"
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should proceed adaptations in the rigth order" do
|
114
|
+
phen_change_conflict_policy { |a,b| age_conflict_policy(a,b) }
|
115
|
+
context(:level1)
|
116
|
+
phen_add_adaptation(:level1,TestClass,:print) do |arg|
|
117
|
+
phen_proceed(arg) + " 1 -> ARG1: #{arg.to_s}"
|
118
|
+
end
|
119
|
+
|
120
|
+
context(:level2)
|
121
|
+
phen_add_adaptation(:level2,TestClass,:print) do |arg|
|
122
|
+
phen_proceed(arg) + " 2 -> ARG2: #{arg.to_s}"
|
123
|
+
end
|
124
|
+
|
125
|
+
context(:level3)
|
126
|
+
phen_add_adaptation(:level3,TestClass,:print) do |arg|
|
127
|
+
phen_proceed(arg) + " 3 -> ARG3: #{arg.to_s}"
|
128
|
+
end
|
129
|
+
|
130
|
+
context(:level4)
|
131
|
+
phen_add_adaptation(:level4,TestClass,:print) do |arg|
|
132
|
+
phen_proceed(arg) + " 4 -> ARG4: #{arg.to_s}"
|
133
|
+
end
|
134
|
+
t = TestClass.new("Foo")
|
135
|
+
t.print("bar").should=="0 -> ARG: bar"
|
136
|
+
activate_context(:level1)
|
137
|
+
activate_context(:level2)
|
138
|
+
activate_context(:level3)
|
139
|
+
activate_context(:level4)
|
140
|
+
t.print("bar").should=="0 -> ARG: bar 1 -> ARG1: bar 2 -> ARG2: bar 3 -> ARG3: bar 4 -> ARG4: bar"
|
141
|
+
force_forget_context(:level1)
|
142
|
+
force_forget_context(:level2)
|
143
|
+
force_forget_context(:level3)
|
144
|
+
force_forget_context(:level4)
|
145
|
+
end
|
108
146
|
end
|
109
147
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
148
|
+
describe "Priority conflict resolution policy" do
|
149
|
+
it "should behave like age when no priorities defined" do
|
150
|
+
phen_change_conflict_policy { |a,b| priority_conflict_policy(a,b) }
|
151
|
+
phone = Phone.new
|
152
|
+
call = Call.new("Alice")
|
153
|
+
phone.receive(call)
|
154
|
+
|
155
|
+
phone.advertise(call).should=="ringtone"
|
156
|
+
|
157
|
+
activate_context(:quiet)
|
158
|
+
phone.advertise(call).should=="vibrator"
|
159
|
+
|
160
|
+
activate_context(:screening)
|
161
|
+
phone.advertise(call).should=="vibrator with screening"
|
162
|
+
|
163
|
+
deactivate_context(:quiet)
|
164
|
+
phone.advertise(call).should=="ringtone with screening"
|
165
|
+
|
166
|
+
deactivate_context(:screening)
|
167
|
+
phone.advertise(call).should=="ringtone"
|
115
168
|
end
|
169
|
+
|
170
|
+
it "should use priorities when defined" do
|
171
|
+
phen_change_conflict_policy { |a,b| priority_conflict_policy(a,b) }
|
172
|
+
phone = Phone.new
|
173
|
+
call = Call.new("Alice")
|
174
|
+
context(:quiet).priority=1
|
175
|
+
context(:screening).priority=2
|
176
|
+
|
177
|
+
phone.receive(call)
|
178
|
+
|
179
|
+
phone.advertise(call).should=="ringtone"
|
116
180
|
|
117
|
-
|
118
|
-
|
119
|
-
|
181
|
+
activate_context(:quiet)
|
182
|
+
phone.advertise(call).should=="vibrator"
|
183
|
+
|
184
|
+
activate_context(:screening)
|
185
|
+
phone.advertise(call).should=="vibrator"
|
186
|
+
|
187
|
+
deactivate_context(:quiet)
|
188
|
+
phone.advertise(call).should=="ringtone with screening"
|
189
|
+
|
190
|
+
deactivate_context(:screening)
|
191
|
+
phone.advertise(call).should=="ringtone"
|
120
192
|
end
|
193
|
+
it "should behave like age when priorities are equal" do
|
194
|
+
phen_change_conflict_policy { |a,b| priority_conflict_policy(a,b) }
|
195
|
+
phone = Phone.new
|
196
|
+
call = Call.new("Alice")
|
197
|
+
context(:quiet).priority=2
|
198
|
+
context(:screening).priority=2
|
199
|
+
phone.receive(call)
|
200
|
+
|
201
|
+
phone.advertise(call).should=="ringtone"
|
202
|
+
|
203
|
+
activate_context(:quiet)
|
204
|
+
phone.advertise(call).should=="vibrator"
|
205
|
+
|
206
|
+
activate_context(:screening)
|
207
|
+
phone.advertise(call).should=="vibrator with screening"
|
208
|
+
|
209
|
+
deactivate_context(:quiet)
|
210
|
+
phone.advertise(call).should=="ringtone with screening"
|
211
|
+
|
212
|
+
deactivate_context(:screening)
|
213
|
+
phone.advertise(call).should=="ringtone"
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should prefer priority over age" do
|
217
|
+
phen_change_conflict_policy { |a,b| priority_conflict_policy(a,b) }
|
218
|
+
phone = Phone.new
|
219
|
+
call = Call.new("Alice")
|
220
|
+
context(:quiet).priority=1
|
221
|
+
|
222
|
+
phone.receive(call)
|
121
223
|
|
122
|
-
|
123
|
-
|
124
|
-
|
224
|
+
phone.advertise(call).should=="ringtone"
|
225
|
+
|
226
|
+
activate_context(:quiet)
|
227
|
+
phone.advertise(call).should=="vibrator"
|
228
|
+
|
229
|
+
activate_context(:screening)
|
230
|
+
phone.advertise(call).should=="vibrator"
|
231
|
+
|
232
|
+
deactivate_context(:quiet)
|
233
|
+
phone.advertise(call).should=="ringtone with screening"
|
234
|
+
|
235
|
+
deactivate_context(:screening)
|
236
|
+
phone.advertise(call).should=="ringtone"
|
125
237
|
end
|
238
|
+
|
239
|
+
it "should prefer combined context" do
|
240
|
+
phen_change_conflict_policy { |a,b| priority_conflict_policy(a,b) }
|
241
|
+
phone = Phone.new
|
242
|
+
call = Call.new("Alice")
|
243
|
+
combined_context=context :screening, :quiet do
|
244
|
+
adaptations_for Phone
|
245
|
+
adapt :advertise do |a_call|
|
246
|
+
"combined"
|
247
|
+
end
|
248
|
+
end
|
249
|
+
context(:quiet).priority=1
|
250
|
+
context(:screening).priority=2
|
251
|
+
|
252
|
+
|
253
|
+
phone.receive(call)
|
254
|
+
|
255
|
+
phone.advertise(call).should=="ringtone"
|
256
|
+
|
257
|
+
activate_context(:quiet)
|
258
|
+
phone.advertise(call).should=="vibrator"
|
259
|
+
|
260
|
+
activate_context(:screening)
|
261
|
+
phone.advertise(call).should=="combined"
|
262
|
+
|
263
|
+
deactivate_context(:quiet)
|
264
|
+
phone.advertise(call).should=="ringtone with screening"
|
265
|
+
|
266
|
+
deactivate_context(:screening)
|
267
|
+
phone.advertise(call).should=="ringtone"
|
268
|
+
|
269
|
+
# Invert priority
|
270
|
+
context(:quiet).priority=2
|
271
|
+
context(:screening).priority=1
|
272
|
+
|
273
|
+
phone.advertise(call).should=="ringtone"
|
274
|
+
|
275
|
+
activate_context(:quiet)
|
276
|
+
phone.advertise(call).should=="vibrator"
|
277
|
+
|
278
|
+
activate_context(:screening)
|
279
|
+
phone.advertise(call).should=="combined"
|
280
|
+
|
281
|
+
deactivate_context(:quiet)
|
282
|
+
phone.advertise(call).should=="ringtone with screening"
|
126
283
|
|
127
|
-
|
128
|
-
|
129
|
-
|
284
|
+
deactivate_context(:screening)
|
285
|
+
phone.advertise(call).should=="ringtone"
|
286
|
+
|
287
|
+
combined_context.forget
|
130
288
|
end
|
131
|
-
t = TestClass.new("Foo")
|
132
|
-
t.print("bar").should=="0 -> ARG: bar"
|
133
|
-
activate_context(:level1)
|
134
|
-
activate_context(:level2)
|
135
|
-
activate_context(:level3)
|
136
|
-
activate_context(:level4)
|
137
|
-
t.print("bar").should=="0 -> ARG: bar 1 -> ARG1: bar 2 -> ARG2: bar 3 -> ARG3: bar 4 -> ARG4: bar"
|
138
|
-
force_forget_context(:level1)
|
139
|
-
force_forget_context(:level2)
|
140
|
-
force_forget_context(:level3)
|
141
|
-
force_forget_context(:level4)
|
142
289
|
end
|
143
290
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: phenomenal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-06-
|
12
|
+
date: 2012-06-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|