mort666-wongi-engine 0.2.9

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 (93) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.hgignore +6 -0
  4. data/.hgtags +13 -0
  5. data/.ruby-gemset +1 -0
  6. data/.travis.yml +19 -0
  7. data/CHANGELOG.md +106 -0
  8. data/Gemfile +4 -0
  9. data/LICENSE +22 -0
  10. data/README.md +27 -0
  11. data/Rakefile +9 -0
  12. data/examples/ex01.rb +23 -0
  13. data/examples/ex02.rb +37 -0
  14. data/examples/graphviz.rb +16 -0
  15. data/examples/rdf.n3 +6 -0
  16. data/examples/rdf.rb +14 -0
  17. data/examples/timeline.rb +48 -0
  18. data/lib/wongi-engine.rb +36 -0
  19. data/lib/wongi-engine/alpha_memory.rb +60 -0
  20. data/lib/wongi-engine/beta.rb +11 -0
  21. data/lib/wongi-engine/beta/assignment_node.rb +40 -0
  22. data/lib/wongi-engine/beta/beta_memory.rb +49 -0
  23. data/lib/wongi-engine/beta/beta_node.rb +94 -0
  24. data/lib/wongi-engine/beta/filter_node.rb +48 -0
  25. data/lib/wongi-engine/beta/join_node.rb +140 -0
  26. data/lib/wongi-engine/beta/ncc_node.rb +67 -0
  27. data/lib/wongi-engine/beta/ncc_partner.rb +40 -0
  28. data/lib/wongi-engine/beta/neg_node.rb +115 -0
  29. data/lib/wongi-engine/beta/optional_node.rb +142 -0
  30. data/lib/wongi-engine/beta/or_node.rb +37 -0
  31. data/lib/wongi-engine/beta/production_node.rb +31 -0
  32. data/lib/wongi-engine/compiler.rb +115 -0
  33. data/lib/wongi-engine/core_ext.rb +63 -0
  34. data/lib/wongi-engine/data_overlay.rb +144 -0
  35. data/lib/wongi-engine/dsl.rb +132 -0
  36. data/lib/wongi-engine/dsl/action/base.rb +11 -0
  37. data/lib/wongi-engine/dsl/action/error_generator.rb +31 -0
  38. data/lib/wongi-engine/dsl/action/simple_action.rb +60 -0
  39. data/lib/wongi-engine/dsl/action/simple_collector.rb +52 -0
  40. data/lib/wongi-engine/dsl/action/statement_generator.rb +46 -0
  41. data/lib/wongi-engine/dsl/action/trace_action.rb +49 -0
  42. data/lib/wongi-engine/dsl/any_rule.rb +33 -0
  43. data/lib/wongi-engine/dsl/assuming.rb +31 -0
  44. data/lib/wongi-engine/dsl/builder.rb +44 -0
  45. data/lib/wongi-engine/dsl/clause/assign.rb +15 -0
  46. data/lib/wongi-engine/dsl/clause/fact.rb +71 -0
  47. data/lib/wongi-engine/dsl/clause/gen.rb +17 -0
  48. data/lib/wongi-engine/dsl/clause/generic.rb +38 -0
  49. data/lib/wongi-engine/dsl/generated.rb +43 -0
  50. data/lib/wongi-engine/dsl/ncc_subrule.rb +17 -0
  51. data/lib/wongi-engine/dsl/query.rb +24 -0
  52. data/lib/wongi-engine/dsl/rule.rb +84 -0
  53. data/lib/wongi-engine/enumerators.rb +21 -0
  54. data/lib/wongi-engine/error.rb +22 -0
  55. data/lib/wongi-engine/filter.rb +6 -0
  56. data/lib/wongi-engine/filter/asserting_test.rb +20 -0
  57. data/lib/wongi-engine/filter/equality_test.rb +36 -0
  58. data/lib/wongi-engine/filter/filter_test.rb +18 -0
  59. data/lib/wongi-engine/filter/greater_than_test.rb +36 -0
  60. data/lib/wongi-engine/filter/inequality_test.rb +36 -0
  61. data/lib/wongi-engine/filter/less_than_test.rb +36 -0
  62. data/lib/wongi-engine/graph.rb +73 -0
  63. data/lib/wongi-engine/network.rb +416 -0
  64. data/lib/wongi-engine/network/collectable.rb +42 -0
  65. data/lib/wongi-engine/network/debug.rb +85 -0
  66. data/lib/wongi-engine/ruleset.rb +74 -0
  67. data/lib/wongi-engine/template.rb +78 -0
  68. data/lib/wongi-engine/token.rb +114 -0
  69. data/lib/wongi-engine/version.rb +5 -0
  70. data/lib/wongi-engine/wme.rb +89 -0
  71. data/lib/wongi-engine/wme_match_data.rb +34 -0
  72. data/spec/beta_node_spec.rb +29 -0
  73. data/spec/bug_specs/issue_4_spec.rb +141 -0
  74. data/spec/dataset_spec.rb +27 -0
  75. data/spec/dsl_spec.rb +9 -0
  76. data/spec/filter_specs/assert_test_spec.rb +102 -0
  77. data/spec/filter_specs/less_test_spec.rb +41 -0
  78. data/spec/generation_spec.rb +116 -0
  79. data/spec/high_level_spec.rb +378 -0
  80. data/spec/network_spec.rb +182 -0
  81. data/spec/overlay_spec.rb +61 -0
  82. data/spec/rule_specs/any_rule_spec.rb +75 -0
  83. data/spec/rule_specs/assign_spec.rb +88 -0
  84. data/spec/rule_specs/assuming_spec.rb +66 -0
  85. data/spec/rule_specs/maybe_rule_spec.rb +101 -0
  86. data/spec/rule_specs/ncc_spec.rb +258 -0
  87. data/spec/rule_specs/negative_rule_spec.rb +105 -0
  88. data/spec/ruleset_spec.rb +54 -0
  89. data/spec/simple_action_spec.rb +40 -0
  90. data/spec/spec_helper.rb +3 -0
  91. data/spec/wme_spec.rb +83 -0
  92. data/wongi-engine.gemspec +40 -0
  93. metadata +212 -0
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe Wongi::Engine::DataOverlay do
4
+ include Wongi::Engine::DSL
5
+
6
+ let(:engine) { Wongi::Engine.create }
7
+
8
+ it 'should be disposable' do
9
+ production = engine << rule {
10
+ forall {
11
+ has 1, 2, :X
12
+ }
13
+ }
14
+ engine.with_overlay { |overlay|
15
+ overlay << [1,2,3]
16
+ expect(production).to have(1).token
17
+ }
18
+ expect(production).to have(0).tokens
19
+ end
20
+
21
+ it 'should generate into correct overlays' do
22
+ production = engine << rule {
23
+ forall {
24
+ has 1, 2, :X
25
+ }
26
+ make {
27
+ gen :X, 4, 5
28
+ }
29
+ }
30
+ engine.with_overlay { |overlay|
31
+ overlay << [1,2,3]
32
+ expect(production).to have(1).token
33
+ expect(engine.find(3, 4, 5)).not_to be_nil
34
+ }
35
+ expect(production).to have(0).tokens
36
+ expect(engine.find(3, 4, 5)).to be_nil
37
+ end
38
+
39
+ it 'works with assignments' do
40
+ production = engine << rule {
41
+ forall {
42
+ has 1, 2, :X
43
+ assign(:Something) { 6 }
44
+ }
45
+ make {
46
+ collect :Something, :stuff
47
+ gen :person, 'stuff', :Something
48
+ }
49
+ }
50
+
51
+ engine.with_overlay { |overlay|
52
+ overlay << [1,2,3]
53
+ expect(production).to have(1).token
54
+ expect(engine.find(:_, :_, :_)).not_to be_nil
55
+ }
56
+
57
+ expect(production).to have(0).tokens
58
+ expect(engine.find(:_, :_, :_)).to be_nil
59
+ end
60
+
61
+ end
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ describe "ANY rule" do
4
+
5
+ before :each do
6
+ @engine = Wongi::Engine.create
7
+ end
8
+
9
+ def engine
10
+ @engine
11
+ end
12
+
13
+ context "with just one option" do
14
+
15
+ it "should act like a positive matcher" do
16
+
17
+ engine << rule('one-option') {
18
+ forall {
19
+ any {
20
+ option {
21
+ has 1, 2, :X
22
+ has :X, 4, 5
23
+ }
24
+ }
25
+ }
26
+ }
27
+
28
+ production = engine.productions['one-option']
29
+
30
+ engine << [1, 2, 3]
31
+ engine << [3, 4, 5]
32
+
33
+ expect(production.size).to eq(1)
34
+
35
+ end
36
+
37
+ end
38
+
39
+ context "with several options" do
40
+
41
+ specify "all matching branches must pass" do
42
+
43
+ engine << rule('two-options') {
44
+ forall {
45
+ has 1, 2, :X
46
+ any {
47
+ option {
48
+ has :X, 4, 5
49
+ }
50
+ option {
51
+ has :X, "four", "five"
52
+ }
53
+ }
54
+ }
55
+ make {
56
+ collect :X, :threes
57
+ }
58
+ }
59
+
60
+ production = engine.productions['two-options']
61
+
62
+ engine << [1, 2, 3]
63
+ engine << [3, 4, 5]
64
+ engine << [1, 2, "three"]
65
+ engine << ["three", "four", "five"]
66
+
67
+ expect(production.size).to eq(2)
68
+ expect( engine.collection(:threes) ).to include(3)
69
+ expect( engine.collection(:threes) ).to include("three")
70
+
71
+ end
72
+
73
+ end
74
+
75
+ end
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+
3
+ describe "ASSIGN rule" do
4
+
5
+ let( :engine ) { Wongi::Engine.create }
6
+
7
+ it "should assign simple expressions" do
8
+
9
+ production = engine << rule {
10
+ forall {
11
+ assign :X do
12
+ 42
13
+ end
14
+ }
15
+ }
16
+ expect(production.size).to eq(1)
17
+ expect(production.tokens.first[:X]).to eq(42)
18
+
19
+ end
20
+
21
+ it "should be able to access previous assignments" do
22
+
23
+ production = engine << rule {
24
+ forall {
25
+ has 1, 2, :X
26
+ assign :Y do |token|
27
+ token[:X] * 2
28
+ end
29
+ }
30
+ }
31
+
32
+ engine << [1, 2, 5]
33
+ expect(production.tokens.first[:Y]).to eq(10)
34
+
35
+ end
36
+
37
+ it 'should be deactivatable' do
38
+
39
+ prod = engine << rule {
40
+ forall {
41
+ has 1, 2, :X
42
+ assign :Y do |token|
43
+ token[:X] * 2
44
+ end
45
+ }
46
+ }
47
+
48
+ engine << [1, 2, 5]
49
+ engine.retract [1, 2, 5]
50
+
51
+ expect( prod ).to have(0).tokens
52
+
53
+ end
54
+
55
+ it 'should be evaluated once' do
56
+ x = 0
57
+ prod = engine << rule {
58
+ forall {
59
+ has :a, :b, :c
60
+ assign :T do
61
+ x += 1
62
+ end
63
+ }
64
+ make {
65
+ gen :d, :e, :T
66
+ gen :f, :g, :T
67
+ }
68
+ }
69
+ engine << [:a, :b, :c]
70
+ expect(x).to be == 1
71
+ end
72
+
73
+ it 'should handle booleans' do
74
+ engine << rule do
75
+ for_all {
76
+ has :a, :b, :c
77
+ assign :X do |token|
78
+ false
79
+ end
80
+ }
81
+ make {
82
+ gen :d, :e, :X
83
+ }
84
+ end
85
+ engine << [:a, :b, :c]
86
+ end
87
+
88
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ describe Wongi::Engine::AssumingClause do
4
+
5
+ let( :engine ) { Wongi::Engine.create }
6
+
7
+ it 'should include base rules' do
8
+
9
+ engine << rule( :base ) {
10
+ forall {
11
+ has :x, :y, :Z
12
+ }
13
+ }
14
+
15
+ extended = engine << rule {
16
+ forall {
17
+ assuming :base
18
+ has :Z, :u, :W
19
+ }
20
+ }
21
+
22
+ engine << [:x, :y, 1]
23
+ engine << [:x, :y, 2]
24
+ engine << [1, :u, :a]
25
+ engine << [2, :u, :b]
26
+ result = Hash[ extended.tokens.map { |token| [ token[:Z], token[:W] ] } ]
27
+ expect( result ).to eq(1 => :a, 2 => :b)
28
+
29
+ end
30
+
31
+ it 'should check for base rule\'s existence' do
32
+
33
+ f = -> {
34
+ engine << rule {
35
+ forall {
36
+ assuming :base
37
+ }
38
+ }
39
+ }
40
+
41
+ expect( &f ).to raise_error Wongi::Engine::UndefinedBaseRule
42
+
43
+ end
44
+
45
+ it 'should come first in a rule' do
46
+
47
+ f = -> {
48
+ engine << rule( :base ) {
49
+ forall {
50
+ has :x, :y, :Z
51
+ }
52
+ }
53
+
54
+ engine << rule {
55
+ forall {
56
+ has :Z, :u, :W
57
+ assuming :base
58
+ }
59
+ }
60
+ }
61
+
62
+ expect( &f ).to raise_error Wongi::Engine::DefinitionError
63
+
64
+ end
65
+
66
+ end
@@ -0,0 +1,101 @@
1
+ require "spec_helper"
2
+
3
+ describe "MAYBE rule" do
4
+
5
+ let( :engine ) { Wongi::Engine.create }
6
+ let( :maybe_rule ) {
7
+ rule {
8
+ forall {
9
+ has 1, 2, :X
10
+ maybe :X, 4, :Y
11
+ }
12
+ }
13
+ }
14
+
15
+ it "should pass with existing facts" do
16
+
17
+ production = engine << maybe_rule
18
+
19
+ engine << [1, 2, 3]
20
+ engine << [3, 4, 5]
21
+
22
+ expect(production.size).to eq(1)
23
+
24
+ expect(production.tokens.first[:X]).to eq(3)
25
+ expect(production.tokens.first[:Y]).to eq(5)
26
+
27
+ end
28
+
29
+ it "should pass with missing facts" do
30
+
31
+ production = engine << maybe_rule
32
+
33
+ engine << [1, 2, 3]
34
+
35
+ expect(production.size).to eq(1)
36
+
37
+ expect(production.tokens.first[:X]).to eq(3)
38
+ expect(production.tokens.first[:Y]).to be_nil
39
+
40
+ end
41
+
42
+ it "should pass with pre-added missing facts" do
43
+
44
+ engine << [1, 2, 3]
45
+
46
+ production = engine << maybe_rule
47
+
48
+ expect(production.size).to eq(1)
49
+
50
+ expect(production.tokens.first[:X]).to eq(3)
51
+ expect(production.tokens.first[:Y]).to be_nil
52
+
53
+ end
54
+
55
+ it 'should pass with retracted facts' do
56
+
57
+ prod = engine << maybe_rule
58
+
59
+ engine << [1, 2, 3]
60
+ engine << [3, 4, 5]
61
+ engine.retract [3, 4, 5]
62
+
63
+ expect(prod.size).to eq(1)
64
+
65
+ expect(prod.tokens.first[:X]).to eq(3)
66
+ expect(prod.tokens.first[:Y]).to be_nil
67
+
68
+ end
69
+
70
+ it 'should work with repeated activations' do
71
+
72
+ prod = engine << maybe_rule
73
+
74
+ engine << [1, 2, 3]
75
+ engine << [3, 4, 5]
76
+ engine.retract [3, 4, 5]
77
+
78
+ 10.times {
79
+ engine << [3, 4, 5]
80
+ expect(prod.size).to eq(1)
81
+ expect(prod.tokens.first[:Y]).to be == 5
82
+
83
+ engine.retract [3, 4, 5]
84
+ expect(prod.size).to eq(1)
85
+ expect(prod.tokens.first[:Y]).to be_nil
86
+ }
87
+
88
+ end
89
+
90
+ it 'should handle retracted parent tokens' do
91
+ prod = engine << maybe_rule
92
+
93
+ engine << [1, 2, 3]
94
+ engine << [3, 4, 5]
95
+ engine.retract [1, 2, 3]
96
+
97
+ expect(prod).to have(0).tokens
98
+ expect(engine.find(3,4,5).opt_join_results).to be_empty
99
+ end
100
+
101
+ end
@@ -0,0 +1,258 @@
1
+ require 'spec_helper'
2
+
3
+ describe Wongi::Engine::NccNode do
4
+
5
+ before :each do
6
+ @engine = Wongi::Engine.create
7
+ end
8
+
9
+ def engine
10
+ @engine
11
+ end
12
+
13
+ def ncc_rule
14
+ rule('ncc') {
15
+ forall {
16
+ has "base", "is", :Base
17
+ none {
18
+ has :Base, 2, :X
19
+ has :X, 4, 5
20
+ }
21
+ }
22
+ }
23
+ end
24
+
25
+ def ncc_rule_post_has
26
+ rule('ncc post has') {
27
+ forall {
28
+ has "base", "is", :Base
29
+ none {
30
+ has :Base, 2, :X
31
+ has :X, 4, 5
32
+ }
33
+ has "base", "is", :Base2
34
+ }
35
+ }
36
+ end
37
+
38
+ it 'should pass with a mismatching subchain' do
39
+
40
+ engine << ncc_rule
41
+ production = engine.productions['ncc']
42
+
43
+ engine << ["base", "is", 1]
44
+
45
+ expect(production).to have(1).token
46
+
47
+ engine << [1, 2, 3]
48
+
49
+ expect(production).to have(1).token
50
+
51
+ engine << [3, 4, 5]
52
+
53
+ expect(production).to have(0).token
54
+
55
+ end
56
+
57
+ it 'should remain consistent after retraction' do
58
+
59
+ engine << ncc_rule
60
+ production = engine.productions['ncc']
61
+
62
+ engine << ["base", "is", 1]
63
+ engine << [1, 2, 3]
64
+ engine << [3, 4, 5]
65
+
66
+ expect(production).to have(0).tokens
67
+
68
+ engine.retract [3, 4, 5]
69
+ expect( production ).to have(1).token
70
+
71
+ engine.retract ["base", "is", 1]
72
+ expect(production).to have(0).tokens
73
+
74
+ end
75
+
76
+ it 'can handle an alpha node template introduced after the negative-conjunctive-condition' do
77
+
78
+ engine << ncc_rule_post_has
79
+
80
+ production = engine.productions['ncc post has']
81
+
82
+ engine << ["base", "is", 1]
83
+ engine << [1, 2, 3]
84
+ engine << [3, 4, 5]
85
+
86
+ expect( production ).to have(0).tokens
87
+
88
+ engine.retract [3, 4, 5]
89
+ expect( production ).to have(1).tokens
90
+
91
+ engine.retract ["base", "is", 1]
92
+ expect( production ).to have(0).tokens
93
+
94
+ end
95
+
96
+ it 'should clean up correctly' do
97
+
98
+ engine.rule :rule1 do
99
+ forall {
100
+ has :light_kitchen, :value, :on
101
+ }
102
+ make {
103
+ #trace values: true, generation: true
104
+ gen self.name, :light_bathroom, :on
105
+ gen self.name, :want_action_for, :light_bathroom
106
+ }
107
+ end
108
+
109
+ prod = engine.rule "action" do
110
+ forall {
111
+ has :Requestor, :want_action_for, :Actor
112
+ has :Requestor, :Actor, :Value
113
+ has :Requestor, :priority, :Priority
114
+ ncc {
115
+ has :OtherRequestor, :want_action_for, :Actor
116
+ diff :OtherRequestor, :Requestor
117
+ has :OtherRequestor, :priority, :OtherPriority
118
+ greater :OtherPriority, :Priority
119
+ }
120
+ }
121
+ make {
122
+ #trace values: true, generation: true
123
+ gen :Actor, :value, :Value
124
+ gen :Actor, :last_user, :Requestor
125
+ }
126
+ end
127
+
128
+ engine << [:user, :priority, 1]
129
+ engine << [:rule1, :priority, 2]
130
+ engine << [:poweruser, :priority, 3]
131
+ engine << [:god, :priority, 4]
132
+
133
+ engine << [:user, :want_action_for, :light_bathroom]
134
+ engine << [:user, :light_bathroom, :off]
135
+ expect( engine.select(:light_bathroom, :value, :_) ).to be == [ Wongi::Engine::WME.new(:light_bathroom, :value, :off) ]
136
+ expect( engine.select(:light_bathroom, :last_user, :_) ).to be == [ Wongi::Engine::WME.new(:light_bathroom, :last_user, :user) ]
137
+
138
+ engine << [:light_kitchen, :value, :on]
139
+ expect( engine.select(:light_bathroom, :value, :_) ).to be == [ Wongi::Engine::WME.new(:light_bathroom, :value, :on) ]
140
+ expect( engine.select(:light_bathroom, :last_user, :_) ).to be == [ Wongi::Engine::WME.new(:light_bathroom, :last_user, :rule1) ]
141
+
142
+ engine << [:poweruser, :want_action_for, :light_bathroom]
143
+ engine << [:poweruser, :light_bathroom, :super_on]
144
+ expect( engine.select(:light_bathroom, :value, :_) ).to be == [ Wongi::Engine::WME.new(:light_bathroom, :value, :super_on) ]
145
+ expect( engine.select(:light_bathroom, :last_user, :_) ).to be == [ Wongi::Engine::WME.new(:light_bathroom, :last_user, :poweruser) ]
146
+
147
+ engine << [:god, :want_action_for, :light_bathroom]
148
+ engine << [:god, :light_bathroom, :let_there_be_light]
149
+ expect( engine.select(:light_bathroom, :value, :_) ).to be == [ Wongi::Engine::WME.new(:light_bathroom, :value, :let_there_be_light) ]
150
+ expect( engine.select(:light_bathroom, :last_user, :_) ).to be == [ Wongi::Engine::WME.new(:light_bathroom, :last_user, :god) ]
151
+
152
+ end
153
+
154
+ it 'should clean up correctly with a different activation order' do
155
+
156
+ engine.rule :rule1 do
157
+ forall {
158
+ has :light_kitchen, :value, :on
159
+ }
160
+ make {
161
+ #trace values: true, generation: true
162
+ gen self.name, :light_bathroom, :on
163
+ gen self.name, :want_action_for, :light_bathroom
164
+ }
165
+ end
166
+
167
+ prod = engine.rule "action" do
168
+ forall {
169
+ has :Requestor, :want_action_for, :Actor
170
+ has :Requestor, :Actor, :Value
171
+ has :Requestor, :priority, :Priority
172
+ ncc {
173
+ has :OtherRequestor, :want_action_for, :Actor
174
+ diff :OtherRequestor, :Requestor
175
+ has :OtherRequestor, :priority, :OtherPriority
176
+ greater :OtherPriority, :Priority
177
+ }
178
+ }
179
+ make {
180
+ #trace values: true, generation: true
181
+ gen :Actor, :value, :Value
182
+ gen :Actor, :last_user, :Requestor
183
+ }
184
+ end
185
+
186
+ engine << [:user, :priority, 2]
187
+ engine << [:rule1, :priority, 1]
188
+ engine << [:poweruser, :priority, 3]
189
+ engine << [:god, :priority, 4]
190
+
191
+ engine << [:user, :want_action_for, :light_bathroom]
192
+ engine << [:user, :light_bathroom, :off]
193
+ expect( engine.select(:light_bathroom, :value, :_) ).to be == [ Wongi::Engine::WME.new(:light_bathroom, :value, :off) ]
194
+ expect( engine.select(:light_bathroom, :last_user, :_) ).to be == [ Wongi::Engine::WME.new(:light_bathroom, :last_user, :user) ]
195
+
196
+ engine << [:light_kitchen, :value, :on]
197
+ expect( engine.select(:light_bathroom, :value, :_) ).to be == [ Wongi::Engine::WME.new(:light_bathroom, :value, :off) ]
198
+ expect( engine.select(:light_bathroom, :last_user, :_) ).to be == [ Wongi::Engine::WME.new(:light_bathroom, :last_user, :user) ]
199
+
200
+ engine << [:poweruser, :want_action_for, :light_bathroom]
201
+ engine << [:poweruser, :light_bathroom, :super_on]
202
+ expect( engine.select(:light_bathroom, :value, :_) ).to be == [ Wongi::Engine::WME.new(:light_bathroom, :value, :super_on) ]
203
+ expect( engine.select(:light_bathroom, :last_user, :_) ).to be == [ Wongi::Engine::WME.new(:light_bathroom, :last_user, :poweruser) ]
204
+
205
+ engine << [:god, :want_action_for, :light_bathroom]
206
+ engine << [:god, :light_bathroom, :let_there_be_light]
207
+ expect( engine.select(:light_bathroom, :value, :_) ).to be == [ Wongi::Engine::WME.new(:light_bathroom, :value, :let_there_be_light) ]
208
+ expect( engine.select(:light_bathroom, :last_user, :_) ).to be == [ Wongi::Engine::WME.new(:light_bathroom, :last_user, :god) ]
209
+
210
+ end
211
+
212
+ it 'should ncc-deactivate without destroying tokens' do
213
+ engine << rule {
214
+ forall {
215
+ has :Student, :is_a, :student
216
+ has :Course, :is_a, :course
217
+ none {
218
+ has :Requirement, :is_a, :requirement
219
+ has :Course, :Requirement, :RequiredGrade
220
+ any {
221
+ option {
222
+ neg :Student, :Requirement, :_
223
+ }
224
+ option {
225
+ has :Student, :Requirement, :ReceivedGrade
226
+ less :ReceivedGrade, :RequiredGrade
227
+ }
228
+ }
229
+ }
230
+ }
231
+ make {
232
+ gen :Student, :passes_for, :Course
233
+ }
234
+ }
235
+
236
+ %w( math science english bio ).each { |req| engine << [ req, :is_a, :requirement ] }
237
+ %w( CourseA CourseB CourseC ).each { |course| engine << [ course, :is_a, :course ] }
238
+ engine << [ "StudentA", :is_a, :student ]
239
+
240
+ engine << ["CourseA", "math", 50]
241
+ engine << ["CourseA", "science", 50]
242
+
243
+ engine << ["CourseB", "math", 50]
244
+ engine << ["CourseB", "english", 50]
245
+
246
+ engine << ["CourseC", "math", 50]
247
+ engine << ["CourseC", "bio", 50]
248
+
249
+ engine << ["StudentA", "math", 60]
250
+ engine << ["StudentA", "science", 60]
251
+ engine << ["StudentA", "bio", 40]
252
+
253
+ expect(engine.find "StudentA", :passes_for, "CourseA").not_to be_nil
254
+ expect(engine.find "StudentA", :passes_for, "CourseB").to be_nil
255
+ expect(engine.find "StudentA", :passes_for, "CourseC").to be_nil
256
+ end
257
+
258
+ end