phenomenal 0.11.11.24.4 → 0.99.0

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 (51) hide show
  1. data/LICENSE +1 -1
  2. data/README +3 -4
  3. data/Rakefile +3 -0
  4. data/lib/phenomenal.rb +15 -2
  5. data/lib/phenomenal/adaptation.rb +22 -12
  6. data/lib/phenomenal/context.rb +127 -134
  7. data/lib/phenomenal/dsl.rb +41 -14
  8. data/lib/phenomenal/feature.rb +8 -0
  9. data/lib/phenomenal/logger.rb +0 -1
  10. data/lib/phenomenal/manager.rb +117 -35
  11. data/lib/phenomenal/relationships/context_relationships.rb +22 -0
  12. data/lib/phenomenal/relationships/dsl.rb +18 -0
  13. data/lib/phenomenal/relationships/feature_relationships.rb +42 -0
  14. data/lib/phenomenal/relationships/implication.rb +35 -0
  15. data/lib/phenomenal/relationships/relationship.rb +42 -0
  16. data/lib/phenomenal/relationships/relationships_manager.rb +63 -0
  17. data/lib/phenomenal/relationships/relationships_store.rb +73 -0
  18. data/lib/phenomenal/relationships/requirement.rb +26 -0
  19. data/lib/phenomenal/relationships/suggestion.rb +41 -0
  20. data/lib/phenomenal/version.rb +3 -0
  21. data/spec/adaptation_spec.rb +64 -0
  22. data/spec/behavior/adaptation_spec.rb +5 -0
  23. data/spec/behavior/combined_contexts_spec.rb +5 -0
  24. data/spec/behavior/composition_spec.rb +5 -0
  25. data/spec/behavior/conflict_policy_spec.rb +5 -0
  26. data/spec/behavior/open_context.rb +5 -0
  27. data/spec/behavior/relationships_spec.rb +249 -0
  28. data/spec/context_spec.rb +268 -0
  29. data/spec/dsl_spec.rb +181 -0
  30. data/spec/feature_spec.rb +5 -0
  31. data/spec/manager_spec.rb +84 -0
  32. data/spec/proc_spec.rb +20 -0
  33. data/spec/relationships/context_relationships_spec.rb +13 -0
  34. data/spec/relationships/dsl_spec.rb +13 -0
  35. data/spec/relationships/feature_relationships_spec.rb +13 -0
  36. data/spec/relationships/relationship_spec.rb +31 -0
  37. data/spec/relationships/relationships_manager_spec.rb +15 -0
  38. data/spec/relationships/relationships_store_spec.rb +19 -0
  39. data/spec/spec_helper.rb +18 -0
  40. data/{test → spec}/test_classes.rb +3 -0
  41. metadata +69 -24
  42. data/demo.rb +0 -24
  43. data/demo_age.rb +0 -89
  44. data/demo_dsl.rb +0 -28
  45. data/phenomenal-0.11.11.24.3.gem +0 -0
  46. data/phenomenal.gemspec +0 -15
  47. data/test/test_cop_adaptation.rb +0 -168
  48. data/test/test_cop_composition.rb +0 -84
  49. data/test/test_cop_conflictpolicy.rb +0 -177
  50. data/test/test_cop_infrastructure.rb +0 -129
  51. data/test_declaration.rb +0 -18
@@ -8,17 +8,16 @@ module Phenomenal::DSL
8
8
  Phenomenal::Context.new(name,priority)
9
9
  end
10
10
  # Define context with adaptations
11
- def phen_context(*args,&block)
12
- Phenomenal::Context.create(*args,&block)
11
+ def phen_context(context,*contexts,&block)
12
+ Phenomenal::Context.create(context,*contexts,false,nil,&block)
13
13
  end
14
- #TODO check kernel repond to method
15
- alias_method :context, :phen_context
14
+ Phenomenal::DSL.phen_alias(:context,klass)
16
15
 
17
16
  # Define context with adaptations
18
- def phen_feature(*args,&block)
19
- Phenomenal::Context.create_feature(*args,&block)
17
+ def phen_feature(context,*contexts,&block)
18
+ Phenomenal::Feature.create(context,*contexts,false,nil,&block)
20
19
  end
21
- alias_method :feature, :phen_feature
20
+ Phenomenal::DSL.phen_alias(:feature,klass)
22
21
 
23
22
 
24
23
  # Forget Context
@@ -29,14 +28,26 @@ module Phenomenal::DSL
29
28
  # Add adaptation
30
29
  def phen_add_adaptation(context,klass, method_name, &implementation)
31
30
  Phenomenal::Manager.instance.find_context(context).add_adaptation(
32
- klass, method_name, &implementation
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
33
38
  )
34
39
  end
35
40
 
36
41
  # Remove Adaptation
37
42
  def phen_remove_adaptation(context,klass,method_name)
38
43
  Phenomenal::Manager.instance.find_context(context).remove_adaptation(
39
- klass,method_name
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
40
51
  )
41
52
  end
42
53
 
@@ -44,13 +55,13 @@ module Phenomenal::DSL
44
55
  def phen_activate_context(context)
45
56
  Phenomenal::Manager.instance.find_context(context).activate
46
57
  end
47
- alias_method :activate_context, :phen_activate_context
58
+ Phenomenal::DSL.phen_alias(:activate_context,klass)
48
59
 
49
60
  # Deactivate Context
50
61
  def phen_deactivate_context(context)
51
62
  Phenomenal::Manager.instance.find_context(context).deactivate
52
63
  end
53
- alias_method :deactivate_context, :phen_deactivate_context
64
+ Phenomenal::DSL.phen_alias(:deactivate_context,klass)
54
65
 
55
66
  # Context is active?
56
67
  def phen_context_active?(context)
@@ -58,8 +69,8 @@ module Phenomenal::DSL
58
69
  end
59
70
 
60
71
  # Context informations
61
- def phen_context_informations(context)
62
- Phenomenal::Manager.instance.find_context(context).informations
72
+ def phen_context_information(context)
73
+ Phenomenal::Manager.instance.find_context(context).information
63
74
  end
64
75
 
65
76
  # Default Context
@@ -76,13 +87,29 @@ module Phenomenal::DSL
76
87
  def phen_proceed(*args,&block)
77
88
  Phenomenal::Manager.instance.proceed(caller,self,*args,&block)
78
89
  end
79
- alias_method :proceed, :phen_proceed
90
+ Phenomenal::DSL.phen_alias(:proceed,klass)
80
91
 
81
92
  # Change conflict resolution policy (for the proceed call)
82
93
  def phen_change_conflict_policy(&block)
83
94
  Phenomenal::Manager.instance.change_conflict_policy(&block)
84
95
  end
85
96
  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
86
113
  end
87
114
  end
88
115
 
@@ -0,0 +1,8 @@
1
+ class Phenomenal::Feature < Phenomenal::Context
2
+ include Phenomenal::FeatureRelationships
3
+
4
+ def initialize(name=nil,manager=nil)
5
+ super(name,manager)
6
+ initialize_relationships
7
+ end
8
+ end
@@ -20,7 +20,6 @@ class Phenomenal::Logger
20
20
  end
21
21
 
22
22
  def error(msg)
23
- logger.error(msg)
24
23
  raise(Phenomenal::Error, msg)
25
24
  end
26
25
 
@@ -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
- :contexts, :default_context
7
+ attr_accessor :active_adaptations, :deployed_adaptations, :contexts,
8
+ :default_context, :combined_contexts, :shared_contexts, :rmanager
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.__id__]=context
23
+ contexts[context]=context
24
24
  end
25
25
 
26
26
  # Unregister a context (forget)
@@ -30,7 +30,17 @@ class Phenomenal::Manager
30
30
  "Default context can only be forgotten when alone"
31
31
  )
32
32
  else
33
- contexts.delete(context.__id__)
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
34
44
  init_default() if context==default_context
35
45
  end
36
46
  end
@@ -38,10 +48,10 @@ class Phenomenal::Manager
38
48
  # Register a new adaptation for a registered context
39
49
  def register_adaptation(adaptation)
40
50
  default_adaptation = default_context.adaptations.find do|i|
41
- i.concern?(adaptation.klass,adaptation.method_name)
51
+ i.concern?(adaptation.klass,adaptation.method_name,adaptation.instance_adaptation?)
42
52
  end
43
53
  if adaptation.context!=default_context && !default_adaptation
44
- save_default_adaptation(adaptation.klass, adaptation.method_name)
54
+ save_default_adaptation(adaptation.klass, adaptation.method_name,adaptation.instance_adaptation?)
45
55
  end
46
56
  activate_adaptation(adaptation) if adaptation.context.active?
47
57
  end
@@ -54,7 +64,23 @@ class Phenomenal::Manager
54
64
  # Activate the context 'context' and deploy the related adaptation
55
65
  def activate_context(context)
56
66
  begin
67
+ # Relationships managment
68
+ rmanager.activate_relationships(context) if context.just_activated?
69
+
70
+ # Activation of adaptations
57
71
  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
+
58
84
  rescue Phenomenal::Error
59
85
  context.deactivate # rollback the deployed adaptations
60
86
  raise # throw up the exception
@@ -63,19 +89,30 @@ class Phenomenal::Manager
63
89
 
64
90
  # Deactivate the adaptations (undeploy if needed)
65
91
  def deactivate_context(context)
66
- context.adaptations.each{ |i|
67
- deactivate_adaptation(i) }
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
68
105
  end
69
106
 
70
107
  # Call the old implementation of the method 'caller.caller_method'
71
108
  def proceed(calling_stack,instance,*args,&block)
72
109
  calling_adaptation = find_adapatation(calling_stack)
73
- #TODO Problems will appears if proceed called in a file where
110
+ # IMPROVE Problems will appears if proceed called in a file where
74
111
  # adaptations are defined but not in one of them=> how to check?
75
- #TODO Problems will also appears if two adaptations are defined on the same
112
+ # IMPROVE Problems will also appears if two adaptations are defined on the same
76
113
  # line using the ';' some check needed at add_adaptation ?
77
114
  adaptations_stack = sorted_adaptations_for(calling_adaptation.klass,
78
- calling_adaptation.method_name)
115
+ calling_adaptation.method_name,calling_adaptation.instance_adaptation?)
79
116
  calling_adaptation_index = adaptations_stack.find_index(calling_adaptation)
80
117
 
81
118
  next_adaptation = adaptations_stack[calling_adaptation_index+1]
@@ -94,15 +131,38 @@ class Phenomenal::Manager
94
131
  # currently registered.
95
132
  # The 'context' parameter can be either a reference to a context instance or
96
133
  # a Symbol with the name of a named (not anonymous) context.
97
- def find_context(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)
98
158
  find=nil
99
- if context.class!=Phenomenal::Context
159
+ if !context.kind_of?(Phenomenal::Context)
100
160
  a = contexts.find{|k,v| v.name==context}
101
161
  if a
102
162
  find = a[1]
103
163
  end
104
164
  else
105
- find = context if contexts.has_key?(context.__id__)
165
+ find = context if contexts.has_key?(context)
106
166
  end
107
167
  if find
108
168
  find
@@ -112,24 +172,43 @@ class Phenomenal::Manager
112
172
  )
113
173
  end
114
174
  end
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__)
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
120
198
  else
121
- contexts.find{|k,v| v.name==context}!=nil
199
+ Phenomenal::Logger.instance.error(
200
+ "Multiple definition of combined context #{contexts}"
201
+ )
122
202
  end
123
203
  end
124
- # ==== Private methods ==== #
125
- private
204
+
126
205
  # Activate the adaptation and redeploy the adaptations to take the new one
127
206
  # one in account
128
207
  def activate_adaptation(adaptation)
129
208
  if !active_adaptations.include?(adaptation)
130
209
  active_adaptations.push(adaptation)
131
210
  end
132
- redeploy_adaptation(adaptation.klass,adaptation.method_name)
211
+ redeploy_adaptation(adaptation.klass,adaptation.method_name,adaptation.instance_adaptation?)
133
212
  end
134
213
 
135
214
  # Deactivate the adaptation and redeploy the adaptations if necessary
@@ -137,14 +216,14 @@ class Phenomenal::Manager
137
216
  active_adaptations.delete(adaptation)
138
217
  if deployed_adaptations.include?(adaptation)
139
218
  deployed_adaptations.delete(adaptation)
140
- redeploy_adaptation(adaptation.klass,adaptation.method_name)
219
+ redeploy_adaptation(adaptation.klass,adaptation.method_name,adaptation.instance_adaptation?)
141
220
  end
142
221
  end
143
222
 
144
223
  # Redeploy the adaptations concerning klass.method_name according to the
145
224
  # conflict policy
146
- def redeploy_adaptation(klass, method_name)
147
- to_deploy = resolve_conflict(klass,method_name)
225
+ def redeploy_adaptation(klass, method_name,instance)
226
+ to_deploy = resolve_conflict(klass,method_name,instance)
148
227
  # Do nothing when to_deploy==nil to break at default context deactivation
149
228
  if !deployed_adaptations.include?(to_deploy) && to_deploy!=nil
150
229
  deploy_adaptation(to_deploy)
@@ -154,7 +233,7 @@ class Phenomenal::Manager
154
233
  # Deploy the adaptation
155
234
  def deploy_adaptation(adaptation)
156
235
  to_undeploy = deployed_adaptations.find do |i|
157
- i.concern?(adaptation.klass,adaptation.method_name)
236
+ i.concern?(adaptation.klass,adaptation.method_name,adaptation.instance_adaptation?)
158
237
  end
159
238
  if to_undeploy!=adaptation # if new adaptation
160
239
  deployed_adaptations.delete(to_undeploy)
@@ -164,13 +243,13 @@ class Phenomenal::Manager
164
243
  end
165
244
 
166
245
  # Save the default adaptation of a method, ie: the initial method
167
- def save_default_adaptation(klass, method_name)
168
- if klass.instance_methods.include?(method_name)
246
+ def save_default_adaptation(klass, method_name,instance)
247
+ if instance
169
248
  method = klass.instance_method(method_name)
170
249
  else
171
250
  method = klass.method(method_name)
172
251
  end
173
- adaptation = default_context.add_adaptation(klass,method_name,method)
252
+ adaptation = default_context.add_adaptation(klass,method_name,instance,method)
174
253
  end
175
254
 
176
255
  # Return the adaptation that math the calling_stack, on the basis of the
@@ -202,15 +281,15 @@ class Phenomenal::Manager
202
281
  end
203
282
 
204
283
  # Return the best adaptation according to the resolution policy
205
- def resolve_conflict(klass,method_name)
206
- sorted_adaptations_for(klass,method_name).first
284
+ def resolve_conflict(klass,method_name,instance)
285
+ sorted_adaptations_for(klass,method_name,instance).first
207
286
  end
208
287
 
209
288
  # Return the adaptations for a particular method sorted with the
210
289
  # conflict policy
211
- def sorted_adaptations_for(klass,method_name)
290
+ def sorted_adaptations_for(klass,method_name,instance)
212
291
  relevant_adaptations =
213
- active_adaptations.find_all { |i| i.concern?(klass, method_name) }
292
+ active_adaptations.find_all { |i| i.concern?(klass, method_name,instance) }
214
293
  relevant_adaptations.sort!{|a,b| conflict_policy(a,b)}
215
294
  end
216
295
 
@@ -221,7 +300,7 @@ class Phenomenal::Manager
221
300
 
222
301
  # Set the default context
223
302
  def init_default
224
- self.default_context= Phenomenal::Context.new(nil,nil,true,self)
303
+ self.default_context= Phenomenal::Feature.new(nil,self)
225
304
  self.default_context.activate
226
305
  end
227
306
 
@@ -230,6 +309,9 @@ class Phenomenal::Manager
230
309
  @contexts = Hash.new
231
310
  @deployed_adaptations = Array.new
232
311
  @active_adaptations = Array.new
312
+ @combined_contexts = Hash.new
313
+ @shared_contexts = Hash.new
314
+ @rmanager = Phenomenal::RelationshipsManager.instance
233
315
  init_default()
234
316
  end
235
317
  end
@@ -0,0 +1,22 @@
1
+ module Phenomenal::ContextRelationships
2
+ def requires(context,*contexts)
3
+ contexts = contexts.push(context)
4
+ contexts.each do |target|
5
+ self.parent_feature.requirements_for(self,{:on=>target})
6
+ end
7
+ end
8
+
9
+ def implies(context,*contexts)
10
+ contexts = contexts.push(context)
11
+ contexts.each do |target|
12
+ self.parent_feature.implications_for(self,{:on=>target})
13
+ end
14
+ end
15
+
16
+ def suggests(context,*contexts)
17
+ contexts = contexts.push(context)
18
+ contexts.each do |target|
19
+ self.parent_feature.suggestions_for(self,{:on=>target})
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,18 @@
1
+ module Phenomenal::DSL
2
+ def self.define_relationships(klass)
3
+ klass.class_eval do
4
+ # Requirements
5
+ def requirements_for(source,targets)
6
+ Phenomenal::Manager.instance.default_context.requirements_for(source,targets)
7
+ end
8
+ # Implications
9
+ def implications_for(source,targets)
10
+ Phenomenal::Manager.instance.default_context.implications_for(source,targets)
11
+ end
12
+ # Suggestions
13
+ def suggestions_for(source,targets)
14
+ Phenomenal::Manager.instance.default_context.suggestions_for(source,targets)
15
+ end
16
+ end
17
+ end
18
+ end