phenomenal 0.9.0 → 0.11.11.24.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/LICENSE +1 -1
- data/README +4 -3
- data/Rakefile +0 -3
- data/demo.rb +24 -0
- data/demo_age.rb +89 -0
- data/demo_dsl.rb +28 -0
- data/lib/phenomenal.rb +2 -15
- data/lib/phenomenal/adaptation.rb +12 -22
- data/lib/phenomenal/context.rb +134 -127
- data/lib/phenomenal/dsl.rb +14 -41
- data/lib/phenomenal/logger.rb +1 -0
- data/lib/phenomenal/manager.rb +35 -117
- data/phenomenal.gemspec +15 -0
- data/{spec → test}/test_classes.rb +0 -3
- data/test/test_cop_adaptation.rb +168 -0
- data/test/test_cop_composition.rb +84 -0
- data/test/test_cop_conflictpolicy.rb +177 -0
- data/test/test_cop_infrastructure.rb +129 -0
- data/test_declaration.rb +18 -0
- metadata +29 -70
- data/lib/phenomenal/feature.rb +0 -8
- data/lib/phenomenal/relationships/context_relationships.rb +0 -22
- data/lib/phenomenal/relationships/dsl.rb +0 -18
- data/lib/phenomenal/relationships/feature_relationships.rb +0 -42
- data/lib/phenomenal/relationships/implication.rb +0 -35
- data/lib/phenomenal/relationships/relationship.rb +0 -42
- data/lib/phenomenal/relationships/relationships_manager.rb +0 -63
- data/lib/phenomenal/relationships/relationships_store.rb +0 -73
- data/lib/phenomenal/relationships/requirement.rb +0 -26
- data/lib/phenomenal/relationships/suggestion.rb +0 -41
- data/lib/phenomenal/version.rb +0 -3
- data/spec/adaptation_spec.rb +0 -64
- data/spec/behavior/adaptation_spec.rb +0 -5
- data/spec/behavior/combined_contexts_spec.rb +0 -5
- data/spec/behavior/composition_spec.rb +0 -5
- data/spec/behavior/conflict_policy_spec.rb +0 -5
- data/spec/behavior/open_context.rb +0 -5
- data/spec/behavior/relationships_spec.rb +0 -249
- data/spec/context_spec.rb +0 -268
- data/spec/dsl_spec.rb +0 -181
- data/spec/feature_spec.rb +0 -5
- data/spec/manager_spec.rb +0 -84
- data/spec/proc_spec.rb +0 -20
- data/spec/relationships/context_relationships_spec.rb +0 -13
- data/spec/relationships/dsl_spec.rb +0 -13
- data/spec/relationships/feature_relationships_spec.rb +0 -13
- data/spec/relationships/relationship_spec.rb +0 -31
- data/spec/relationships/relationships_manager_spec.rb +0 -15
- data/spec/relationships/relationships_store_spec.rb +0 -19
- data/spec/spec_helper.rb +0 -18
data/lib/phenomenal/dsl.rb
CHANGED
@@ -8,16 +8,17 @@ module Phenomenal::DSL
|
|
8
8
|
Phenomenal::Context.new(name,priority)
|
9
9
|
end
|
10
10
|
# Define context with adaptations
|
11
|
-
def phen_context(
|
12
|
-
Phenomenal::Context.create(
|
11
|
+
def phen_context(*args,&block)
|
12
|
+
Phenomenal::Context.create(*args,&block)
|
13
13
|
end
|
14
|
-
|
14
|
+
#TODO check kernel repond to method
|
15
|
+
alias_method :context, :phen_context
|
15
16
|
|
16
17
|
# Define context with adaptations
|
17
|
-
def phen_feature(
|
18
|
-
Phenomenal::
|
18
|
+
def phen_feature(*args,&block)
|
19
|
+
Phenomenal::Context.create_feature(*args,&block)
|
19
20
|
end
|
20
|
-
|
21
|
+
alias_method :feature, :phen_feature
|
21
22
|
|
22
23
|
|
23
24
|
# Forget Context
|
@@ -28,26 +29,14 @@ module Phenomenal::DSL
|
|
28
29
|
# Add adaptation
|
29
30
|
def phen_add_adaptation(context,klass, method_name, &implementation)
|
30
31
|
Phenomenal::Manager.instance.find_context(context).add_adaptation(
|
31
|
-
klass, method_name,
|
32
|
-
)
|
33
|
-
end
|
34
|
-
|
35
|
-
def phen_add_class_adaptation(context,klass, method_name, &implementation)
|
36
|
-
Phenomenal::Manager.instance.find_context(context).add_adaptation(
|
37
|
-
klass, method_name,false, &implementation
|
32
|
+
klass, method_name, &implementation
|
38
33
|
)
|
39
34
|
end
|
40
35
|
|
41
36
|
# Remove Adaptation
|
42
37
|
def phen_remove_adaptation(context,klass,method_name)
|
43
38
|
Phenomenal::Manager.instance.find_context(context).remove_adaptation(
|
44
|
-
klass,method_name
|
45
|
-
)
|
46
|
-
end
|
47
|
-
|
48
|
-
def phen_remove_class_adaptation(context,klass,method_name)
|
49
|
-
Phenomenal::Manager.instance.find_context(context).remove_adaptation(
|
50
|
-
klass,method_name,false
|
39
|
+
klass,method_name
|
51
40
|
)
|
52
41
|
end
|
53
42
|
|
@@ -55,13 +44,13 @@ module Phenomenal::DSL
|
|
55
44
|
def phen_activate_context(context)
|
56
45
|
Phenomenal::Manager.instance.find_context(context).activate
|
57
46
|
end
|
58
|
-
|
47
|
+
alias_method :activate_context, :phen_activate_context
|
59
48
|
|
60
49
|
# Deactivate Context
|
61
50
|
def phen_deactivate_context(context)
|
62
51
|
Phenomenal::Manager.instance.find_context(context).deactivate
|
63
52
|
end
|
64
|
-
|
53
|
+
alias_method :deactivate_context, :phen_deactivate_context
|
65
54
|
|
66
55
|
# Context is active?
|
67
56
|
def phen_context_active?(context)
|
@@ -69,8 +58,8 @@ module Phenomenal::DSL
|
|
69
58
|
end
|
70
59
|
|
71
60
|
# Context informations
|
72
|
-
def
|
73
|
-
Phenomenal::Manager.instance.find_context(context).
|
61
|
+
def phen_context_informations(context)
|
62
|
+
Phenomenal::Manager.instance.find_context(context).informations
|
74
63
|
end
|
75
64
|
|
76
65
|
# Default Context
|
@@ -87,29 +76,13 @@ module Phenomenal::DSL
|
|
87
76
|
def phen_proceed(*args,&block)
|
88
77
|
Phenomenal::Manager.instance.proceed(caller,self,*args,&block)
|
89
78
|
end
|
90
|
-
|
79
|
+
alias_method :proceed, :phen_proceed
|
91
80
|
|
92
81
|
# Change conflict resolution policy (for the proceed call)
|
93
82
|
def phen_change_conflict_policy(&block)
|
94
83
|
Phenomenal::Manager.instance.change_conflict_policy(&block)
|
95
84
|
end
|
96
85
|
end
|
97
|
-
# Add relationships specific DSL
|
98
|
-
define_relationships(klass)
|
99
|
-
end
|
100
|
-
|
101
|
-
private
|
102
|
-
def self.phen_alias(method,klass)
|
103
|
-
if Kernel.respond_to? method
|
104
|
-
Phenomenal::Logger.instance.warn(
|
105
|
-
"The Phenomenal DSL keyword #{method} wasn't defined, use"+
|
106
|
-
" phen_#{method} instead"
|
107
|
-
)
|
108
|
-
else
|
109
|
-
klass.class_eval do
|
110
|
-
alias_method method, "phen_#{method}"
|
111
|
-
end
|
112
|
-
end
|
113
86
|
end
|
114
87
|
end
|
115
88
|
|
data/lib/phenomenal/logger.rb
CHANGED
data/lib/phenomenal/manager.rb
CHANGED
@@ -4,8 +4,8 @@ class Phenomenal::Manager
|
|
4
4
|
include Singleton
|
5
5
|
include Phenomenal::ConflictPolicies
|
6
6
|
|
7
|
-
attr_accessor :active_adaptations, :deployed_adaptations,
|
8
|
-
:
|
7
|
+
attr_accessor :active_adaptations, :deployed_adaptations,
|
8
|
+
:contexts, :default_context
|
9
9
|
|
10
10
|
# Register a new context
|
11
11
|
def register_context(context)
|
@@ -20,7 +20,7 @@ class Phenomenal::Manager
|
|
20
20
|
" If you want to have named context it has to be a globally unique name"
|
21
21
|
)
|
22
22
|
end
|
23
|
-
contexts[context]=context
|
23
|
+
contexts[context.__id__]=context
|
24
24
|
end
|
25
25
|
|
26
26
|
# Unregister a context (forget)
|
@@ -30,17 +30,7 @@ class Phenomenal::Manager
|
|
30
30
|
"Default context can only be forgotten when alone"
|
31
31
|
)
|
32
32
|
else
|
33
|
-
contexts.delete(context)
|
34
|
-
|
35
|
-
# Forgot combined contexts
|
36
|
-
combined_contexts.delete(context)
|
37
|
-
if shared_contexts[context]
|
38
|
-
shared_contexts[context].each do |c|
|
39
|
-
c.forget
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
# Restore default context
|
33
|
+
contexts.delete(context.__id__)
|
44
34
|
init_default() if context==default_context
|
45
35
|
end
|
46
36
|
end
|
@@ -48,10 +38,10 @@ class Phenomenal::Manager
|
|
48
38
|
# Register a new adaptation for a registered context
|
49
39
|
def register_adaptation(adaptation)
|
50
40
|
default_adaptation = default_context.adaptations.find do|i|
|
51
|
-
i.concern?(adaptation.klass,adaptation.method_name
|
41
|
+
i.concern?(adaptation.klass,adaptation.method_name)
|
52
42
|
end
|
53
43
|
if adaptation.context!=default_context && !default_adaptation
|
54
|
-
save_default_adaptation(adaptation.klass, adaptation.method_name
|
44
|
+
save_default_adaptation(adaptation.klass, adaptation.method_name)
|
55
45
|
end
|
56
46
|
activate_adaptation(adaptation) if adaptation.context.active?
|
57
47
|
end
|
@@ -64,23 +54,7 @@ class Phenomenal::Manager
|
|
64
54
|
# Activate the context 'context' and deploy the related adaptation
|
65
55
|
def activate_context(context)
|
66
56
|
begin
|
67
|
-
# Relationships managment
|
68
|
-
rmanager.activate_relationships(context) if context.just_activated?
|
69
|
-
|
70
|
-
# Activation of adaptations
|
71
57
|
context.adaptations.each{ |i| activate_adaptation(i) }
|
72
|
-
#puts "activation of #{context}"
|
73
|
-
if shared_contexts[context]
|
74
|
-
#puts "trigger activation of #{shared_contexts[context].first.information}"
|
75
|
-
shared_contexts[context].each do |combined_context|
|
76
|
-
need_activation=true
|
77
|
-
combined_contexts[combined_context].each do |shared_context|
|
78
|
-
need_activation=false if !shared_context.active?
|
79
|
-
end
|
80
|
-
combined_context.activate if need_activation
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
58
|
rescue Phenomenal::Error
|
85
59
|
context.deactivate # rollback the deployed adaptations
|
86
60
|
raise # throw up the exception
|
@@ -89,30 +63,19 @@ class Phenomenal::Manager
|
|
89
63
|
|
90
64
|
# Deactivate the adaptations (undeploy if needed)
|
91
65
|
def deactivate_context(context)
|
92
|
-
|
93
|
-
|
94
|
-
#Adaptations deactivation
|
95
|
-
context.adaptations.each do |i|
|
96
|
-
deactivate_adaptation(i)
|
97
|
-
end
|
98
|
-
if shared_contexts[context]
|
99
|
-
shared_contexts[context].each do |combined_context|
|
100
|
-
while combined_context.active? do
|
101
|
-
combined_context.deactivate
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
66
|
+
context.adaptations.each{ |i|
|
67
|
+
deactivate_adaptation(i) }
|
105
68
|
end
|
106
69
|
|
107
70
|
# Call the old implementation of the method 'caller.caller_method'
|
108
71
|
def proceed(calling_stack,instance,*args,&block)
|
109
72
|
calling_adaptation = find_adapatation(calling_stack)
|
110
|
-
#
|
73
|
+
#TODO Problems will appears if proceed called in a file where
|
111
74
|
# adaptations are defined but not in one of them=> how to check?
|
112
|
-
#
|
75
|
+
#TODO Problems will also appears if two adaptations are defined on the same
|
113
76
|
# line using the ';' some check needed at add_adaptation ?
|
114
77
|
adaptations_stack = sorted_adaptations_for(calling_adaptation.klass,
|
115
|
-
calling_adaptation.method_name
|
78
|
+
calling_adaptation.method_name)
|
116
79
|
calling_adaptation_index = adaptations_stack.find_index(calling_adaptation)
|
117
80
|
|
118
81
|
next_adaptation = adaptations_stack[calling_adaptation_index+1]
|
@@ -131,38 +94,15 @@ class Phenomenal::Manager
|
|
131
94
|
# currently registered.
|
132
95
|
# The 'context' parameter can be either a reference to a context instance or
|
133
96
|
# a Symbol with the name of a named (not anonymous) context.
|
134
|
-
def find_context(context
|
135
|
-
if contexts.length==0
|
136
|
-
find_simple_context(context)
|
137
|
-
else #Combined contexts
|
138
|
-
contexts.insert(0,context)
|
139
|
-
find_combined_context(contexts)
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
# Check wether context 'context' exist in the context manager
|
144
|
-
# Context can be either the context name or the context instance itself
|
145
|
-
# Return the context if found, or nil otherwise
|
146
|
-
def context_defined?(context, *contexts)
|
147
|
-
c=nil
|
148
|
-
begin
|
149
|
-
c = find_context(context,*contexts)
|
150
|
-
rescue Phenomenal::Error
|
151
|
-
return nil
|
152
|
-
end
|
153
|
-
return c
|
154
|
-
end
|
155
|
-
# ==== Private methods ==== #
|
156
|
-
private
|
157
|
-
def find_simple_context(context)
|
97
|
+
def find_context(context)
|
158
98
|
find=nil
|
159
|
-
if
|
99
|
+
if context.class!=Phenomenal::Context
|
160
100
|
a = contexts.find{|k,v| v.name==context}
|
161
101
|
if a
|
162
102
|
find = a[1]
|
163
103
|
end
|
164
104
|
else
|
165
|
-
find = context if contexts.has_key?(context)
|
105
|
+
find = context if contexts.has_key?(context.__id__)
|
166
106
|
end
|
167
107
|
if find
|
168
108
|
find
|
@@ -172,43 +112,24 @@ class Phenomenal::Manager
|
|
172
112
|
)
|
173
113
|
end
|
174
114
|
end
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
# otherwise use the symbol name
|
181
|
-
c = find_simple_context(c) if context_defined?(c)
|
182
|
-
if shared_contexts[c]==nil
|
183
|
-
list.clear
|
184
|
-
break
|
185
|
-
elsif list.length==0
|
186
|
-
# clone otherwise list.clear empty shared_contexts[c]
|
187
|
-
list=shared_contexts[c].clone
|
188
|
-
else
|
189
|
-
list=shared_contexts[c].find_all{|i| list.include?(i) }
|
190
|
-
end
|
191
|
-
end
|
192
|
-
if list.length==0
|
193
|
-
Phenomenal::Logger.instance.error(
|
194
|
-
"Unknown combined context #{contexts}"
|
195
|
-
)
|
196
|
-
elsif list.length==1
|
197
|
-
return list.first
|
115
|
+
# Check wether context 'context' exist in the context manager
|
116
|
+
# Context can be either the context name or the context instance itself
|
117
|
+
def context_defined?(context)
|
118
|
+
if context.class==Phenomenal::Context
|
119
|
+
contexts.has_key?(context.__id__)
|
198
120
|
else
|
199
|
-
|
200
|
-
"Multiple definition of combined context #{contexts}"
|
201
|
-
)
|
121
|
+
contexts.find{|k,v| v.name==context}!=nil
|
202
122
|
end
|
203
123
|
end
|
204
|
-
|
124
|
+
# ==== Private methods ==== #
|
125
|
+
private
|
205
126
|
# Activate the adaptation and redeploy the adaptations to take the new one
|
206
127
|
# one in account
|
207
128
|
def activate_adaptation(adaptation)
|
208
129
|
if !active_adaptations.include?(adaptation)
|
209
130
|
active_adaptations.push(adaptation)
|
210
131
|
end
|
211
|
-
redeploy_adaptation(adaptation.klass,adaptation.method_name
|
132
|
+
redeploy_adaptation(adaptation.klass,adaptation.method_name)
|
212
133
|
end
|
213
134
|
|
214
135
|
# Deactivate the adaptation and redeploy the adaptations if necessary
|
@@ -216,14 +137,14 @@ class Phenomenal::Manager
|
|
216
137
|
active_adaptations.delete(adaptation)
|
217
138
|
if deployed_adaptations.include?(adaptation)
|
218
139
|
deployed_adaptations.delete(adaptation)
|
219
|
-
redeploy_adaptation(adaptation.klass,adaptation.method_name
|
140
|
+
redeploy_adaptation(adaptation.klass,adaptation.method_name)
|
220
141
|
end
|
221
142
|
end
|
222
143
|
|
223
144
|
# Redeploy the adaptations concerning klass.method_name according to the
|
224
145
|
# conflict policy
|
225
|
-
def redeploy_adaptation(klass, method_name
|
226
|
-
to_deploy = resolve_conflict(klass,method_name
|
146
|
+
def redeploy_adaptation(klass, method_name)
|
147
|
+
to_deploy = resolve_conflict(klass,method_name)
|
227
148
|
# Do nothing when to_deploy==nil to break at default context deactivation
|
228
149
|
if !deployed_adaptations.include?(to_deploy) && to_deploy!=nil
|
229
150
|
deploy_adaptation(to_deploy)
|
@@ -233,7 +154,7 @@ class Phenomenal::Manager
|
|
233
154
|
# Deploy the adaptation
|
234
155
|
def deploy_adaptation(adaptation)
|
235
156
|
to_undeploy = deployed_adaptations.find do |i|
|
236
|
-
i.concern?(adaptation.klass,adaptation.method_name
|
157
|
+
i.concern?(adaptation.klass,adaptation.method_name)
|
237
158
|
end
|
238
159
|
if to_undeploy!=adaptation # if new adaptation
|
239
160
|
deployed_adaptations.delete(to_undeploy)
|
@@ -243,13 +164,13 @@ class Phenomenal::Manager
|
|
243
164
|
end
|
244
165
|
|
245
166
|
# Save the default adaptation of a method, ie: the initial method
|
246
|
-
def save_default_adaptation(klass, method_name
|
247
|
-
if
|
167
|
+
def save_default_adaptation(klass, method_name)
|
168
|
+
if klass.instance_methods.include?(method_name)
|
248
169
|
method = klass.instance_method(method_name)
|
249
170
|
else
|
250
171
|
method = klass.method(method_name)
|
251
172
|
end
|
252
|
-
adaptation = default_context.add_adaptation(klass,method_name,
|
173
|
+
adaptation = default_context.add_adaptation(klass,method_name,method)
|
253
174
|
end
|
254
175
|
|
255
176
|
# Return the adaptation that math the calling_stack, on the basis of the
|
@@ -281,15 +202,15 @@ class Phenomenal::Manager
|
|
281
202
|
end
|
282
203
|
|
283
204
|
# Return the best adaptation according to the resolution policy
|
284
|
-
def resolve_conflict(klass,method_name
|
285
|
-
sorted_adaptations_for(klass,method_name
|
205
|
+
def resolve_conflict(klass,method_name)
|
206
|
+
sorted_adaptations_for(klass,method_name).first
|
286
207
|
end
|
287
208
|
|
288
209
|
# Return the adaptations for a particular method sorted with the
|
289
210
|
# conflict policy
|
290
|
-
def sorted_adaptations_for(klass,method_name
|
211
|
+
def sorted_adaptations_for(klass,method_name)
|
291
212
|
relevant_adaptations =
|
292
|
-
active_adaptations.find_all { |i| i.concern?(klass, method_name
|
213
|
+
active_adaptations.find_all { |i| i.concern?(klass, method_name) }
|
293
214
|
relevant_adaptations.sort!{|a,b| conflict_policy(a,b)}
|
294
215
|
end
|
295
216
|
|
@@ -300,7 +221,7 @@ class Phenomenal::Manager
|
|
300
221
|
|
301
222
|
# Set the default context
|
302
223
|
def init_default
|
303
|
-
self.default_context= Phenomenal::
|
224
|
+
self.default_context= Phenomenal::Context.new(nil,nil,true,self)
|
304
225
|
self.default_context.activate
|
305
226
|
end
|
306
227
|
|
@@ -309,9 +230,6 @@ class Phenomenal::Manager
|
|
309
230
|
@contexts = Hash.new
|
310
231
|
@deployed_adaptations = Array.new
|
311
232
|
@active_adaptations = Array.new
|
312
|
-
@combined_contexts = Hash.new
|
313
|
-
@shared_contexts = Hash.new
|
314
|
-
@rmanager = Phenomenal::RelationshipsManager.instance
|
315
233
|
init_default()
|
316
234
|
end
|
317
235
|
end
|
data/phenomenal.gemspec
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "phenomenal"
|
3
|
+
s.summary = "A context oriented programing framework for ruby"
|
4
|
+
s.description = File.read(File.join(File.dirname(__FILE__),'README'))
|
5
|
+
s.version = "0.11.11.24.3"
|
6
|
+
s.authors = "Loic Vigneron - Thibault Poncelet"
|
7
|
+
s.email = "thibault.poncelet@student.uclouvain.be - loic.vigneron@student.uclouvain.be"
|
8
|
+
s.date = "2011-10-07"
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.required_ruby_version = '>=1.9.2'
|
11
|
+
s.files = Dir['**/**']
|
12
|
+
s.has_rdoc = false
|
13
|
+
s.test_files = Dir['test/*.rb']
|
14
|
+
s.homepage = "http://www.phenomenal-gem.com"
|
15
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
require_relative "../lib/phenomenal.rb"
|
2
|
+
require_relative "./test_classes.rb"
|
3
|
+
require "test/unit"
|
4
|
+
|
5
|
+
class TestCopAdaptation < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
phen_define_context(:quiet)
|
8
|
+
phen_define_context(:offHook)
|
9
|
+
phen_add_adaptation(:quiet,Phone,:advertise){|a_call| "vibrator" }
|
10
|
+
phen_add_adaptation(:offHook,Phone,:advertise) do |a_call|
|
11
|
+
"call waiting signal"
|
12
|
+
end
|
13
|
+
phen_define_context(:test)
|
14
|
+
phen_add_adaptation(:test,TestClass,:to_s) do
|
15
|
+
@value + " @access " + value + " attr_accessor_access"
|
16
|
+
end
|
17
|
+
|
18
|
+
phen_define_context(:test_2)
|
19
|
+
phen_add_adaptation(:test_2,TestClass,:klass_var_access) do
|
20
|
+
@@klass_var+1
|
21
|
+
end
|
22
|
+
|
23
|
+
phen_define_context(:test_3)
|
24
|
+
phen_add_adaptation(:test_3,TestClass,:klass_inst_var_access) do
|
25
|
+
@klass_inst_var+1
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def teardown
|
30
|
+
while phen_context_active?(:quiet) do
|
31
|
+
phen_deactivate_context(:quiet)
|
32
|
+
end
|
33
|
+
phen_forget_context(:quiet)
|
34
|
+
|
35
|
+
while phen_context_active?(:offHook) do
|
36
|
+
phen_deactivate_context(:offHook)
|
37
|
+
end
|
38
|
+
phen_forget_context(:offHook)
|
39
|
+
|
40
|
+
while phen_context_active?(:test) do
|
41
|
+
phen_deactivate_context(:test)
|
42
|
+
end
|
43
|
+
phen_forget_context(:test)
|
44
|
+
|
45
|
+
while phen_context_active?(:test_2) do
|
46
|
+
phen_deactivate_context(:test_2)
|
47
|
+
end
|
48
|
+
phen_forget_context(:test_2)
|
49
|
+
|
50
|
+
while phen_context_active?(:test_3) do
|
51
|
+
phen_deactivate_context(:test_3)
|
52
|
+
end
|
53
|
+
phen_forget_context(:test_3)
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_overriding_adaptation
|
57
|
+
phone = Phone.new
|
58
|
+
call = Call.new("Bob")
|
59
|
+
phone.receive(call)
|
60
|
+
assert((phone.advertise(call))=="ringtone",
|
61
|
+
"Default behaviour should be expressed")
|
62
|
+
phen_activate_context(:quiet)
|
63
|
+
assert((phone.advertise(call))=="vibrator",
|
64
|
+
"Behavior adapted to quiet environments should be expressed")
|
65
|
+
phen_deactivate_context(:quiet)
|
66
|
+
assert((phone.advertise(call))=="ringtone",
|
67
|
+
"Default behaviour should be expressed")
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_conflicting_adaptation
|
71
|
+
assert_raise(Phenomenal::Error,
|
72
|
+
"A context cannot have two different adaptations for the same method.")do
|
73
|
+
phen_add_adaptation(:quiet,Phone,:advertise) do |a_call|
|
74
|
+
"call waiting signal"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_invalid_adaptation
|
80
|
+
phen_define_context(:temp)
|
81
|
+
assert_raise(Phenomenal::Error,
|
82
|
+
"Adaptation of inexistent methods should be forbidden.") do
|
83
|
+
phen_add_adaptation(:temp,Phone,:phonyAdvertise){|a_call| "vibrator"}
|
84
|
+
phen_activate_context(:temp)
|
85
|
+
end
|
86
|
+
phen_forget_context(:temp)
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_conflicting_activation
|
90
|
+
assert(!phen_context_active?(:quiet))
|
91
|
+
assert_nothing_raised(Phenomenal::Error,
|
92
|
+
"Shoud be OK to activate the quiet context") do
|
93
|
+
phen_activate_context(:quiet)
|
94
|
+
end
|
95
|
+
assert(phen_context_active?(:quiet))
|
96
|
+
assert(!phen_context_active?(:offHook))
|
97
|
+
assert_raise(Phenomenal::Error,
|
98
|
+
"Should conflict with currently active quiet context") do
|
99
|
+
phen_activate_context(:offHook)
|
100
|
+
end
|
101
|
+
assert(!phen_context_active?(:offHook),
|
102
|
+
"Should not be mistakenly activated after error")
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_runtime_adding_removing_adaptation
|
106
|
+
phone = Phone.new
|
107
|
+
call = Call.new("Bob")
|
108
|
+
phone.receive(call)
|
109
|
+
phen_activate_context(:quiet)
|
110
|
+
assert(phen_context_active?(:quiet))
|
111
|
+
assert_nothing_raised("Should be ok to remove an active adaptation") do
|
112
|
+
phen_remove_adaptation(:quiet,Phone,:advertise)
|
113
|
+
end
|
114
|
+
assert((phone.advertise(call))=="ringtone",
|
115
|
+
"Default behaviour should be expressed")
|
116
|
+
assert_nothing_raised("Should be ok to add an active adaptation") do
|
117
|
+
phen_add_adaptation(:quiet,Phone,:advertise){|a_call| "vibrator" }
|
118
|
+
end
|
119
|
+
assert((phone.advertise(call))=="vibrator",
|
120
|
+
"Adapted behaviour should be expressed")
|
121
|
+
assert_nothing_raised("Should be ok to deactivate the context") do
|
122
|
+
phen_deactivate_context(:quiet)
|
123
|
+
end
|
124
|
+
assert((phone.advertise(call))=="ringtone",
|
125
|
+
"Default behaviour should be expressed")
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_instance_variable_access
|
129
|
+
t = TestClass.new("VAR")
|
130
|
+
assert("VAR"==t.to_s, %(Default to_s should acess var and return
|
131
|
+
string value))
|
132
|
+
phen_activate_context(:test)
|
133
|
+
assert("VAR @access VAR attr_accessor_access"==t.to_s, %(Adapted to_s should
|
134
|
+
acess both instance var and accessor meth and return string value))
|
135
|
+
phen_deactivate_context(:test)
|
136
|
+
assert("VAR"==t.to_s, %(Default to_s should acess var and return
|
137
|
+
string value))
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_class_variable_access
|
141
|
+
assert(1==TestClass.klass_var_access, %(Default meth should acess var and
|
142
|
+
return val))
|
143
|
+
phen_activate_context(:test_2)
|
144
|
+
|
145
|
+
# Doesn't work: Adaptations doesn't have access to class variables
|
146
|
+
# Seems to be a Ruby bug
|
147
|
+
#TODO
|
148
|
+
|
149
|
+
#assert(2==TestClass.klass_var_access, %(Adapted meth should
|
150
|
+
# acess klass variable and return its value +1))
|
151
|
+
phen_deactivate_context(:test_2)
|
152
|
+
assert(1==TestClass.klass_var_access, %(Default meth should acess var and
|
153
|
+
return val))
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_class_instance_variable_access
|
157
|
+
assert(2==TestClass.klass_inst_var_access, %(Default meth should acess var
|
158
|
+
and return val))
|
159
|
+
phen_activate_context(:test_3)
|
160
|
+
|
161
|
+
assert(3==TestClass.klass_inst_var_access, %(Adapted meth should
|
162
|
+
acess klass variable and return its value +1))
|
163
|
+
phen_deactivate_context(:test_3)
|
164
|
+
assert(2==TestClass.klass_inst_var_access, %(Default meth should acess var
|
165
|
+
and return string value))
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|