phenomenal 0.99.0 → 1.0.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 (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