phenomenal 0.11.11.24.4 → 0.99.0

Sign up to get free protection for your applications and to get access to all the features.
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