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.
Files changed (50) hide show
  1. data/LICENSE +1 -1
  2. data/README +4 -3
  3. data/Rakefile +0 -3
  4. data/demo.rb +24 -0
  5. data/demo_age.rb +89 -0
  6. data/demo_dsl.rb +28 -0
  7. data/lib/phenomenal.rb +2 -15
  8. data/lib/phenomenal/adaptation.rb +12 -22
  9. data/lib/phenomenal/context.rb +134 -127
  10. data/lib/phenomenal/dsl.rb +14 -41
  11. data/lib/phenomenal/logger.rb +1 -0
  12. data/lib/phenomenal/manager.rb +35 -117
  13. data/phenomenal.gemspec +15 -0
  14. data/{spec → test}/test_classes.rb +0 -3
  15. data/test/test_cop_adaptation.rb +168 -0
  16. data/test/test_cop_composition.rb +84 -0
  17. data/test/test_cop_conflictpolicy.rb +177 -0
  18. data/test/test_cop_infrastructure.rb +129 -0
  19. data/test_declaration.rb +18 -0
  20. metadata +29 -70
  21. data/lib/phenomenal/feature.rb +0 -8
  22. data/lib/phenomenal/relationships/context_relationships.rb +0 -22
  23. data/lib/phenomenal/relationships/dsl.rb +0 -18
  24. data/lib/phenomenal/relationships/feature_relationships.rb +0 -42
  25. data/lib/phenomenal/relationships/implication.rb +0 -35
  26. data/lib/phenomenal/relationships/relationship.rb +0 -42
  27. data/lib/phenomenal/relationships/relationships_manager.rb +0 -63
  28. data/lib/phenomenal/relationships/relationships_store.rb +0 -73
  29. data/lib/phenomenal/relationships/requirement.rb +0 -26
  30. data/lib/phenomenal/relationships/suggestion.rb +0 -41
  31. data/lib/phenomenal/version.rb +0 -3
  32. data/spec/adaptation_spec.rb +0 -64
  33. data/spec/behavior/adaptation_spec.rb +0 -5
  34. data/spec/behavior/combined_contexts_spec.rb +0 -5
  35. data/spec/behavior/composition_spec.rb +0 -5
  36. data/spec/behavior/conflict_policy_spec.rb +0 -5
  37. data/spec/behavior/open_context.rb +0 -5
  38. data/spec/behavior/relationships_spec.rb +0 -249
  39. data/spec/context_spec.rb +0 -268
  40. data/spec/dsl_spec.rb +0 -181
  41. data/spec/feature_spec.rb +0 -5
  42. data/spec/manager_spec.rb +0 -84
  43. data/spec/proc_spec.rb +0 -20
  44. data/spec/relationships/context_relationships_spec.rb +0 -13
  45. data/spec/relationships/dsl_spec.rb +0 -13
  46. data/spec/relationships/feature_relationships_spec.rb +0 -13
  47. data/spec/relationships/relationship_spec.rb +0 -31
  48. data/spec/relationships/relationships_manager_spec.rb +0 -15
  49. data/spec/relationships/relationships_store_spec.rb +0 -19
  50. data/spec/spec_helper.rb +0 -18
@@ -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(context,*contexts,&block)
12
- Phenomenal::Context.create(context,*contexts,false,nil,&block)
11
+ def phen_context(*args,&block)
12
+ Phenomenal::Context.create(*args,&block)
13
13
  end
14
- Phenomenal::DSL.phen_alias(:context,klass)
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(context,*contexts,&block)
18
- Phenomenal::Feature.create(context,*contexts,false,nil,&block)
18
+ def phen_feature(*args,&block)
19
+ Phenomenal::Context.create_feature(*args,&block)
19
20
  end
20
- Phenomenal::DSL.phen_alias(:feature,klass)
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,true, &implementation
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,true
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
- Phenomenal::DSL.phen_alias(:activate_context,klass)
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
- Phenomenal::DSL.phen_alias(:deactivate_context,klass)
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 phen_context_information(context)
73
- Phenomenal::Manager.instance.find_context(context).information
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
- Phenomenal::DSL.phen_alias(:proceed,klass)
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
 
@@ -20,6 +20,7 @@ class Phenomenal::Logger
20
20
  end
21
21
 
22
22
  def error(msg)
23
+ logger.error(msg)
23
24
  raise(Phenomenal::Error, msg)
24
25
  end
25
26
 
@@ -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, :contexts,
8
- :default_context, :combined_contexts, :shared_contexts, :rmanager
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,adaptation.instance_adaptation?)
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,adaptation.instance_adaptation?)
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
- #Relationships managment
93
- rmanager.deactivate_relationships(context)
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
- # IMPROVE Problems will appears if proceed called in a file where
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
- # IMPROVE Problems will also appears if two adaptations are defined on the same
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,calling_adaptation.instance_adaptation?)
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, *contexts)
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 !context.kind_of?(Phenomenal::Context)
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
- def find_combined_context(contexts)
177
- list=Array.new
178
- contexts.each do |c|
179
- # Use the object instance if already available
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
- Phenomenal::Logger.instance.error(
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,adaptation.instance_adaptation?)
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,adaptation.instance_adaptation?)
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,instance)
226
- to_deploy = resolve_conflict(klass,method_name,instance)
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,adaptation.instance_adaptation?)
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,instance)
247
- if instance
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,instance,method)
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,instance)
285
- sorted_adaptations_for(klass,method_name,instance).first
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,instance)
211
+ def sorted_adaptations_for(klass,method_name)
291
212
  relevant_adaptations =
292
- active_adaptations.find_all { |i| i.concern?(klass, method_name,instance) }
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::Feature.new(nil,self)
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
@@ -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
@@ -1,7 +1,4 @@
1
1
  # Define the test classes
2
- class TestString < String
3
- end
4
-
5
2
  class TestClass < String
6
3
  @klass_inst_var = 2
7
4
  @@klass_var = 1
@@ -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
+