phenomenal 0.99.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/Rakefile +1 -7
  2. data/lib/phenomenal.rb +10 -1
  3. data/lib/phenomenal/adaptation.rb +6 -8
  4. data/lib/phenomenal/conflict_policies.rb +2 -1
  5. data/lib/phenomenal/context.rb +36 -31
  6. data/lib/phenomenal/dsl.rb +14 -9
  7. data/lib/phenomenal/feature.rb +1 -0
  8. data/lib/phenomenal/manager.rb +10 -12
  9. data/lib/phenomenal/proc.rb +2 -2
  10. data/lib/phenomenal/relationships/context_relationships.rb +2 -0
  11. data/lib/phenomenal/relationships/dsl.rb +1 -0
  12. data/lib/phenomenal/relationships/feature_relationships.rb +2 -2
  13. data/lib/phenomenal/relationships/implication.rb +10 -4
  14. data/lib/phenomenal/relationships/relationship.rb +13 -0
  15. data/lib/phenomenal/relationships/relationships_manager.rb +1 -1
  16. data/lib/phenomenal/relationships/relationships_store.rb +13 -7
  17. data/lib/phenomenal/relationships/requirement.rb +5 -0
  18. data/lib/phenomenal/relationships/suggestion.rb +14 -6
  19. data/lib/phenomenal/version.rb +1 -1
  20. data/lib/phenomenal/viewer/dsl.rb +15 -0
  21. data/lib/phenomenal/viewer/graphical.rb +136 -0
  22. data/lib/phenomenal/viewer/textual.rb +36 -0
  23. data/spec/context_spec.rb +93 -27
  24. data/spec/dsl_spec.rb +0 -39
  25. data/spec/integration/adaptation_spec.rb +127 -0
  26. data/spec/integration/combined_contexts_spec.rb +48 -0
  27. data/spec/integration/composition_spec.rb +62 -0
  28. data/spec/integration/conflict_policy_spec.rb +143 -0
  29. data/spec/integration/open_context.rb +48 -0
  30. data/spec/{behavior → integration}/relationships_spec.rb +0 -6
  31. data/spec/manager_spec.rb +30 -19
  32. data/spec/relationships/context_relationships_spec.rb +23 -3
  33. data/spec/relationships/dsl_spec.rb +9 -3
  34. data/spec/relationships/feature_relationships_spec.rb +22 -3
  35. data/spec/relationships/relationship_spec.rb +13 -1
  36. data/spec/relationships/relationships_manager_spec.rb +0 -11
  37. data/spec/relationships/relationships_store_spec.rb +31 -7
  38. data/spec/spec_helper.rb +1 -0
  39. data/spec/test_classes.rb +3 -0
  40. metadata +16 -13
  41. data/spec/behavior/adaptation_spec.rb +0 -5
  42. data/spec/behavior/combined_contexts_spec.rb +0 -5
  43. data/spec/behavior/composition_spec.rb +0 -5
  44. data/spec/behavior/conflict_policy_spec.rb +0 -5
  45. data/spec/behavior/open_context.rb +0 -5
data/spec/dsl_spec.rb CHANGED
@@ -1,18 +1,11 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe Phenomenal::DSL do
4
-
5
- describe "#phen_define_context" do
6
- pending "TODO"
7
- end
8
-
9
4
  describe "#phen_context" do
10
5
  it "should exist in Kernel" do
11
6
  Kernel.should respond_to :phen_context
12
7
  end
13
8
 
14
- pending "TODO"
15
-
16
9
  describe "#context" do
17
10
  it "should exist in Kernel" do
18
11
  Kernel.should respond_to :context
@@ -29,8 +22,6 @@ describe Phenomenal::DSL do
29
22
  Kernel.should respond_to :phen_feature
30
23
  end
31
24
 
32
- pending "TODO"
33
-
34
25
  describe "#feature" do
35
26
  it "should exist in Kernel" do
36
27
  Kernel.should respond_to :feature
@@ -46,39 +37,29 @@ describe Phenomenal::DSL do
46
37
  it "should exist in Kernel" do
47
38
  Kernel.should respond_to :phen_forget_context
48
39
  end
49
-
50
- pending "TODO"
51
40
  end
52
41
  describe "#phen_add_adaptation" do
53
42
  it "should exist in Kernel" do
54
43
  Kernel.should respond_to :phen_add_adaptation
55
44
  end
56
-
57
- pending "TODO"
58
45
  end
59
46
 
60
47
  describe "#phen_add_class_adaptation" do
61
48
  it "should exist in Kernel" do
62
49
  Kernel.should respond_to :phen_add_class_adaptation
63
50
  end
64
-
65
- pending "TODO"
66
51
  end
67
52
 
68
53
  describe "#phen_remove_adaptation" do
69
54
  it "should exist in Kernel" do
70
55
  Kernel.should respond_to :phen_remove_adaptation
71
56
  end
72
-
73
- pending "TODO"
74
57
  end
75
58
 
76
59
  describe "#phen_remove_class_adaptation" do
77
60
  it "should exist in Kernel" do
78
61
  Kernel.should respond_to :phen_remove_class_adaptation
79
62
  end
80
-
81
- pending "TODO"
82
63
  end
83
64
 
84
65
  describe "#phen_activate_context" do
@@ -86,8 +67,6 @@ describe Phenomenal::DSL do
86
67
  Kernel.should respond_to :phen_activate_context
87
68
  end
88
69
 
89
- pending "TODO"
90
-
91
70
  describe "#activate_context" do
92
71
  it "should exist in Kernel" do
93
72
  Kernel.should respond_to :activate_context
@@ -104,8 +83,6 @@ describe Phenomenal::DSL do
104
83
  Kernel.should respond_to :phen_deactivate_context
105
84
  end
106
85
 
107
- pending "TODO"
108
-
109
86
  describe "#deactivate_context" do
110
87
  it "should exist in Kernel" do
111
88
  Kernel.should respond_to :deactivate_context
@@ -121,32 +98,24 @@ describe Phenomenal::DSL do
121
98
  it "should exist in Kernel" do
122
99
  Kernel.should respond_to :phen_context_active?
123
100
  end
124
-
125
- pending "TODO"
126
101
  end
127
102
 
128
103
  describe "#phen_context_information" do
129
104
  it "should exist in Kernel" do
130
105
  Kernel.should respond_to :phen_context_information
131
106
  end
132
-
133
- pending "TODO"
134
107
  end
135
108
 
136
109
  describe "#phen_default_context" do
137
110
  it "should exist in Kernel" do
138
111
  Kernel.should respond_to :phen_default_context
139
112
  end
140
-
141
- pending "TODO"
142
113
  end
143
114
 
144
115
  describe "#phen_defined_contexts" do
145
116
  it "should exist in Kernel" do
146
117
  Kernel.should respond_to :phen_defined_contexts
147
118
  end
148
-
149
- pending "TODO"
150
119
  end
151
120
 
152
121
  describe "#phen_proceed" do
@@ -154,8 +123,6 @@ describe Phenomenal::DSL do
154
123
  Kernel.should respond_to :phen_proceed
155
124
  end
156
125
 
157
- pending "TODO"
158
-
159
126
  describe "#proceed" do
160
127
  it "should exist in Kernel" do
161
128
  Kernel.should respond_to :proceed
@@ -171,11 +138,5 @@ describe Phenomenal::DSL do
171
138
  it "should exist in Kernel" do
172
139
  Kernel.should respond_to :phen_change_conflict_policy
173
140
  end
174
-
175
- pending "TODO"
176
- end
177
-
178
- describe ".phen_alias" do
179
- pending "TODO"
180
141
  end
181
142
  end
@@ -0,0 +1,127 @@
1
+ require "spec_helper"
2
+
3
+ describe "Simple adaptations" do
4
+ before :each do
5
+
6
+ phen_change_conflict_policy { |a,b| no_resolution_conflict_policy(a,b) }
7
+
8
+ context(:quiet) do
9
+ adaptations_for Phone
10
+ adapt :advertise do |a_call|
11
+ "vibrator"
12
+ end
13
+ end
14
+
15
+ context(:offHook) do
16
+ adaptations_for Phone
17
+ adapt :advertise do |a_call|
18
+ "call waiting signal"
19
+ end
20
+ end
21
+
22
+
23
+ context(:test) do
24
+ adaptations_for TestClass
25
+ adapt :to_s do
26
+ @value + " @access " + value + " attr_accessor_access"
27
+ end
28
+ end
29
+
30
+ context(:test_2) do
31
+ adaptations_for TestClass
32
+ adapt_class :klass_var_access do
33
+ @@klass_var+1
34
+ end
35
+ end
36
+
37
+ context(:test_3) do
38
+ adaptations_for TestClass
39
+ adapt_class :klass_inst_var_access do
40
+ @klass_inst_var+1
41
+ end
42
+ end
43
+
44
+ end
45
+
46
+ after :each do
47
+ force_forget_context(context(:quiet))
48
+ force_forget_context(context(:offHook))
49
+ force_forget_context(context(:test))
50
+ force_forget_context(context(:test_2))
51
+ force_forget_context(context(:test_3))
52
+ end
53
+
54
+ it "should override default behavior" do
55
+ phone = Phone.new
56
+ call = Call.new("Bob")
57
+ phone.receive(call)
58
+ phone.advertise(call).should=="ringtone"
59
+ activate_context(:quiet)
60
+ phone.advertise(call).should=="vibrator"
61
+ deactivate_context(:quiet)
62
+ phone.advertise(call).should=="ringtone"
63
+ end
64
+
65
+ it "should refuse confliction adaptations in the same context" do
66
+ expect{context(:quiet).add_adaptation(Phone,:advertise,true) do |a_call|
67
+ "A call test"
68
+ end}.to raise_error Phenomenal::Error
69
+ end
70
+
71
+ it "should refuse adaptations for inexistent methods" do
72
+ expect{phen_add_adaptation(:test,Phone,:phonyAdvertise){|a_call| "vibrator"}}.
73
+ to raise_error Phenomenal::Error
74
+ end
75
+
76
+ it "should be possible to add/remove adaptations at runtime" do
77
+ phone = Phone.new
78
+ call = Call.new("Bob")
79
+ phone.receive(call)
80
+
81
+ activate_context(:quiet)
82
+ phen_context_active?(:quiet).should be_true
83
+ expect{phen_remove_adaptation(:quiet,Phone,:advertise)}.to_not raise_error
84
+
85
+ phone.advertise(call).should=="ringtone"
86
+
87
+ expect{phen_add_adaptation(:quiet,Phone,:advertise){|a_call| "vibrator" }}.to_not raise_error
88
+
89
+ phone.advertise(call).should=="vibrator"
90
+ expect{deactivate_context(:quiet)}.to_not raise_error
91
+
92
+ phone.advertise(call).should=="ringtone"
93
+ end
94
+
95
+ it "should be possible to access instance variables in adaptations" do
96
+ t = TestClass.new("VAR")
97
+ t.to_s.should=="VAR"
98
+
99
+ activate_context(:test)
100
+
101
+ t.to_s.should == "VAR @access VAR attr_accessor_access"
102
+
103
+ deactivate_context(:test)
104
+ t.to_s.should=="VAR"
105
+ end
106
+
107
+ it "sould be possible to access class variables" do
108
+ TestClass.klass_var_access.should==1
109
+ activate_context(:test_2)
110
+
111
+ pending "Adaptations doesn't have access to class variables, seems to be a Ruby bug"
112
+ TestClass.klass_var_access.should==2
113
+
114
+ deactivate_context(:test_2)
115
+ TestClass.klass_var_access.should==1
116
+ end
117
+
118
+ it "should be possible to access class instance variables adaptations" do
119
+ TestClass.klass_inst_var_access.should==2
120
+
121
+ activate_context(:test_3)
122
+ TestClass.klass_inst_var_access.should==3
123
+
124
+ deactivate_context(:test_3)
125
+ TestClass.klass_inst_var_access.should==2
126
+ end
127
+ end
@@ -0,0 +1,48 @@
1
+ require "spec_helper"
2
+
3
+ describe "Combined contexts" do
4
+ it "should be possible to define combined contexts" do
5
+ expect{ context :a,:b}.to_not raise_error
6
+ force_forget_context(:a)
7
+ force_forget_context(:b)
8
+ end
9
+
10
+ it "should reopen the same combined context " do
11
+ context(:a,:b).should==context(:a,:b)
12
+ force_forget_context(:a)
13
+ force_forget_context(:b)
14
+ end
15
+
16
+ it "should use the adaptation of the combined context before the adaptations of the separated contexts" do
17
+ context :a do
18
+ adaptations_for TestString2
19
+ adapt :length do
20
+ 84
21
+ end
22
+ end
23
+
24
+ context :a,:b do
25
+ adaptations_for TestString2
26
+ adapt :length do
27
+ 42
28
+ end
29
+ end
30
+
31
+
32
+ inst = TestString2.new("1234")
33
+ inst.length.should==4
34
+ activate_context :a
35
+ inst.length.should==84
36
+ activate_context :b
37
+ inst.length.should==42
38
+ activate_context :a
39
+ inst.length.should==42
40
+ deactivate_context :a
41
+ deactivate_context :a
42
+ inst.length.should==4
43
+
44
+ force_forget_context(:a)
45
+ force_forget_context(:b)
46
+ end
47
+
48
+ end
@@ -0,0 +1,62 @@
1
+ require "spec_helper"
2
+
3
+ describe "Composition of adaptations" do
4
+ before :each do
5
+
6
+ context(:screening) do
7
+ adaptations_for Phone
8
+ adapt :advertise do |a_call|
9
+ proceed(a_call)+" with screening"
10
+ end
11
+ end
12
+
13
+ context(:test)
14
+ end
15
+
16
+ after :each do
17
+ force_forget_context(:screening)
18
+ force_forget_context(:test)
19
+ end
20
+
21
+ it "should adapt methods without args" do
22
+ prefix = "It's a nice "
23
+ suffix = "simple composition"
24
+ composed = prefix+suffix
25
+ inst = TestClass.new(prefix)
26
+ phen_add_adaptation(:test,String,:to_s) {phen_proceed+suffix}
27
+
28
+ inst.to_s.should == prefix
29
+ activate_context(:test)
30
+ inst.to_s.should==composed
31
+ end
32
+
33
+ it "should adapt methods with args" do
34
+ str="Nice String!"
35
+ inst= TestClass.new(str)
36
+ phen_add_adaptation(:test,String,:eql?) do | str |
37
+ if phen_proceed(str)
38
+ "OK"
39
+ else
40
+ "KO"
41
+ end
42
+ end
43
+
44
+ inst.eql?(str).should be_true
45
+ activate_context(:test)
46
+
47
+ inst.eql?(str).should=="OK"
48
+ inst.eql?(str+str).should=="KO"
49
+ end
50
+
51
+ it "should allow nested compositions" do
52
+ phone = Phone.new
53
+ call = Call.new("Alice")
54
+ phone.receive(call)
55
+
56
+ phone.advertise(call).should=="ringtone"
57
+ activate_context(:screening)
58
+ phone.advertise(call).should=="ringtone with screening"
59
+ deactivate_context(:screening)
60
+ phone.advertise(call).should=="ringtone"
61
+ end
62
+ end
@@ -0,0 +1,143 @@
1
+ require "spec_helper"
2
+
3
+ describe "Conflict policies" do
4
+
5
+ before :each do
6
+ phen_change_conflict_policy { |a,b| no_resolution_conflict_policy(a,b) }
7
+ context(:screening) do
8
+ adaptations_for Phone
9
+ adapt :advertise do |a_call|
10
+ phen_proceed(a_call)+" with screening"
11
+ end
12
+ end
13
+
14
+ context(:quiet) do
15
+ adaptations_for Phone
16
+ adapt :advertise do |a_call|
17
+ "vibrator"
18
+ end
19
+ end
20
+ end
21
+
22
+ after :each do
23
+ force_forget_context(:screening)
24
+ force_forget_context(:quiet)
25
+ phen_change_conflict_policy { |a,b| age_conflict_policy(a,b) }
26
+ end
27
+
28
+ it "should not allow two contexts with an adaptation for the same method to be active at the same time" do
29
+
30
+ expect{activate_context(:screening)}.to_not raise_error
31
+ expect{activate_context(:quiet)}.to raise_error Phenomenal::Error
32
+ end
33
+
34
+ it "should set the age of the context such that the most recent one has the smaller age" do
35
+ phen_change_conflict_policy { |a,b| age_conflict_policy(a,b) }
36
+
37
+ phen_context_active?(phen_default_context).should be_true
38
+ phen_context_active?(:screening).should be_false
39
+ phen_context_active?(:quiet).should be_false
40
+
41
+ phen_activate_context(:screening)
42
+
43
+ (phen_context_information(:screening)[:age] <
44
+ phen_context_information(phen_default_context)[:age]).should be_true,
45
+ "screening context has been activated more recently than default"
46
+
47
+ phen_activate_context(:quiet)
48
+ (phen_context_information(:quiet)[:age] <
49
+ phen_context_information(:screening)[:age]).should be_true
50
+ "quiet context has been activated more recently than screening"
51
+ (phen_context_information(:screening)[:age] <
52
+ phen_context_information(phen_default_context)[:age]).should be_true,
53
+ "quiet context has still been activated more recently than default"
54
+ phen_deactivate_context(:quiet)
55
+ phen_deactivate_context(:screening)
56
+ phen_activate_context(:screening)
57
+ (phen_context_information(:screening)[:age] <
58
+ phen_context_information(:quiet)[:age]).should be_true,
59
+ "screening context has now been activated more recently than quiet"
60
+ end
61
+
62
+ it "should choose the context the most recently activated" do
63
+ phen_change_conflict_policy { |a,b| age_conflict_policy(a,b) }
64
+ expect{activate_context(:screening)}.to_not raise_error
65
+ expect{activate_context(:quiet)}.to_not raise_error
66
+ end
67
+
68
+ it "should work with interleaved activation of contexts" do
69
+ phen_change_conflict_policy { |a,b| age_conflict_policy(a,b) }
70
+ phone = Phone.new
71
+ call = Call.new("Alice")
72
+ phone.receive(call)
73
+
74
+ phone.advertise(call).should=="ringtone"
75
+
76
+ activate_context(:quiet)
77
+ phone.advertise(call).should=="vibrator"
78
+
79
+ activate_context(:screening)
80
+ phone.advertise(call).should=="vibrator with screening"
81
+
82
+ deactivate_context(:quiet)
83
+ phone.advertise(call).should=="ringtone with screening"
84
+
85
+ deactivate_context(:screening)
86
+ phone.advertise(call).should=="ringtone"
87
+ end
88
+
89
+ it "should nest calls with the age policy" do
90
+ phen_change_conflict_policy { |a,b| age_conflict_policy(a,b) }
91
+ phone = Phone.new
92
+ call = Call.new("Alice")
93
+ phone.receive(call)
94
+
95
+ phone.advertise(call).should=="ringtone"
96
+
97
+ activate_context(:quiet)
98
+ phone.advertise(call).should=="vibrator"
99
+
100
+ activate_context(:screening)
101
+ phone.advertise(call).should=="vibrator with screening"
102
+
103
+ deactivate_context(:screening)
104
+ phone.advertise(call).should=="vibrator"
105
+
106
+ deactivate_context(:quiet)
107
+ phone.advertise(call).should=="ringtone"
108
+ end
109
+
110
+ it "should PPPPPPPPPPPPPPPPPPPP" do
111
+ phen_change_conflict_policy { |a,b| age_conflict_policy(a,b) }
112
+ context(:level1)
113
+ phen_add_adaptation(:level1,TestClass,:print) do |arg|
114
+ phen_proceed(arg) + " 1 -> ARG1: #{arg.to_s}"
115
+ end
116
+
117
+ context(:level2)
118
+ phen_add_adaptation(:level2,TestClass,:print) do |arg|
119
+ phen_proceed(arg) + " 2 -> ARG2: #{arg.to_s}"
120
+ end
121
+
122
+ context(:level3)
123
+ phen_add_adaptation(:level3,TestClass,:print) do |arg|
124
+ phen_proceed(arg) + " 3 -> ARG3: #{arg.to_s}"
125
+ end
126
+
127
+ context(:level4)
128
+ phen_add_adaptation(:level4,TestClass,:print) do |arg|
129
+ phen_proceed(arg) + " 4 -> ARG4: #{arg.to_s}"
130
+ end
131
+ t = TestClass.new("Foo")
132
+ t.print("bar").should=="0 -> ARG: bar"
133
+ activate_context(:level1)
134
+ activate_context(:level2)
135
+ activate_context(:level3)
136
+ activate_context(:level4)
137
+ t.print("bar").should=="0 -> ARG: bar 1 -> ARG1: bar 2 -> ARG2: bar 3 -> ARG3: bar 4 -> ARG4: bar"
138
+ force_forget_context(:level1)
139
+ force_forget_context(:level2)
140
+ force_forget_context(:level3)
141
+ force_forget_context(:level4)
142
+ end
143
+ end