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.
- data/LICENSE +1 -1
- data/README +3 -4
- data/Rakefile +3 -0
- data/lib/phenomenal.rb +15 -2
- data/lib/phenomenal/adaptation.rb +22 -12
- data/lib/phenomenal/context.rb +127 -134
- data/lib/phenomenal/dsl.rb +41 -14
- data/lib/phenomenal/feature.rb +8 -0
- data/lib/phenomenal/logger.rb +0 -1
- data/lib/phenomenal/manager.rb +117 -35
- data/lib/phenomenal/relationships/context_relationships.rb +22 -0
- data/lib/phenomenal/relationships/dsl.rb +18 -0
- data/lib/phenomenal/relationships/feature_relationships.rb +42 -0
- data/lib/phenomenal/relationships/implication.rb +35 -0
- data/lib/phenomenal/relationships/relationship.rb +42 -0
- data/lib/phenomenal/relationships/relationships_manager.rb +63 -0
- data/lib/phenomenal/relationships/relationships_store.rb +73 -0
- data/lib/phenomenal/relationships/requirement.rb +26 -0
- data/lib/phenomenal/relationships/suggestion.rb +41 -0
- data/lib/phenomenal/version.rb +3 -0
- data/spec/adaptation_spec.rb +64 -0
- data/spec/behavior/adaptation_spec.rb +5 -0
- data/spec/behavior/combined_contexts_spec.rb +5 -0
- data/spec/behavior/composition_spec.rb +5 -0
- data/spec/behavior/conflict_policy_spec.rb +5 -0
- data/spec/behavior/open_context.rb +5 -0
- data/spec/behavior/relationships_spec.rb +249 -0
- data/spec/context_spec.rb +268 -0
- data/spec/dsl_spec.rb +181 -0
- data/spec/feature_spec.rb +5 -0
- data/spec/manager_spec.rb +84 -0
- data/spec/proc_spec.rb +20 -0
- data/spec/relationships/context_relationships_spec.rb +13 -0
- data/spec/relationships/dsl_spec.rb +13 -0
- data/spec/relationships/feature_relationships_spec.rb +13 -0
- data/spec/relationships/relationship_spec.rb +31 -0
- data/spec/relationships/relationships_manager_spec.rb +15 -0
- data/spec/relationships/relationships_store_spec.rb +19 -0
- data/spec/spec_helper.rb +18 -0
- data/{test → spec}/test_classes.rb +3 -0
- metadata +69 -24
- data/demo.rb +0 -24
- data/demo_age.rb +0 -89
- data/demo_dsl.rb +0 -28
- data/phenomenal-0.11.11.24.3.gem +0 -0
- data/phenomenal.gemspec +0 -15
- data/test/test_cop_adaptation.rb +0 -168
- data/test/test_cop_composition.rb +0 -84
- data/test/test_cop_conflictpolicy.rb +0 -177
- data/test/test_cop_infrastructure.rb +0 -129
- data/test_declaration.rb +0 -18
data/lib/phenomenal/dsl.rb
CHANGED
@@ -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(
|
12
|
-
Phenomenal::Context.create(
|
11
|
+
def phen_context(context,*contexts,&block)
|
12
|
+
Phenomenal::Context.create(context,*contexts,false,nil,&block)
|
13
13
|
end
|
14
|
-
|
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(
|
19
|
-
Phenomenal::
|
17
|
+
def phen_feature(context,*contexts,&block)
|
18
|
+
Phenomenal::Feature.create(context,*contexts,false,nil,&block)
|
20
19
|
end
|
21
|
-
|
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
|
-
|
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
|
-
|
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
|
62
|
-
Phenomenal::Manager.instance.find_context(context).
|
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
|
-
|
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
|
|
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, :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
|
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
|
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
|
-
|
67
|
-
|
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
|
-
#
|
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
|
-
#
|
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.
|
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
|
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
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
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
|
-
|
199
|
+
Phenomenal::Logger.instance.error(
|
200
|
+
"Multiple definition of combined context #{contexts}"
|
201
|
+
)
|
122
202
|
end
|
123
203
|
end
|
124
|
-
|
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
|
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::
|
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
|