mort666-wongi-engine 0.2.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.hgignore +6 -0
- data/.hgtags +13 -0
- data/.ruby-gemset +1 -0
- data/.travis.yml +19 -0
- data/CHANGELOG.md +106 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +27 -0
- data/Rakefile +9 -0
- data/examples/ex01.rb +23 -0
- data/examples/ex02.rb +37 -0
- data/examples/graphviz.rb +16 -0
- data/examples/rdf.n3 +6 -0
- data/examples/rdf.rb +14 -0
- data/examples/timeline.rb +48 -0
- data/lib/wongi-engine.rb +36 -0
- data/lib/wongi-engine/alpha_memory.rb +60 -0
- data/lib/wongi-engine/beta.rb +11 -0
- data/lib/wongi-engine/beta/assignment_node.rb +40 -0
- data/lib/wongi-engine/beta/beta_memory.rb +49 -0
- data/lib/wongi-engine/beta/beta_node.rb +94 -0
- data/lib/wongi-engine/beta/filter_node.rb +48 -0
- data/lib/wongi-engine/beta/join_node.rb +140 -0
- data/lib/wongi-engine/beta/ncc_node.rb +67 -0
- data/lib/wongi-engine/beta/ncc_partner.rb +40 -0
- data/lib/wongi-engine/beta/neg_node.rb +115 -0
- data/lib/wongi-engine/beta/optional_node.rb +142 -0
- data/lib/wongi-engine/beta/or_node.rb +37 -0
- data/lib/wongi-engine/beta/production_node.rb +31 -0
- data/lib/wongi-engine/compiler.rb +115 -0
- data/lib/wongi-engine/core_ext.rb +63 -0
- data/lib/wongi-engine/data_overlay.rb +144 -0
- data/lib/wongi-engine/dsl.rb +132 -0
- data/lib/wongi-engine/dsl/action/base.rb +11 -0
- data/lib/wongi-engine/dsl/action/error_generator.rb +31 -0
- data/lib/wongi-engine/dsl/action/simple_action.rb +60 -0
- data/lib/wongi-engine/dsl/action/simple_collector.rb +52 -0
- data/lib/wongi-engine/dsl/action/statement_generator.rb +46 -0
- data/lib/wongi-engine/dsl/action/trace_action.rb +49 -0
- data/lib/wongi-engine/dsl/any_rule.rb +33 -0
- data/lib/wongi-engine/dsl/assuming.rb +31 -0
- data/lib/wongi-engine/dsl/builder.rb +44 -0
- data/lib/wongi-engine/dsl/clause/assign.rb +15 -0
- data/lib/wongi-engine/dsl/clause/fact.rb +71 -0
- data/lib/wongi-engine/dsl/clause/gen.rb +17 -0
- data/lib/wongi-engine/dsl/clause/generic.rb +38 -0
- data/lib/wongi-engine/dsl/generated.rb +43 -0
- data/lib/wongi-engine/dsl/ncc_subrule.rb +17 -0
- data/lib/wongi-engine/dsl/query.rb +24 -0
- data/lib/wongi-engine/dsl/rule.rb +84 -0
- data/lib/wongi-engine/enumerators.rb +21 -0
- data/lib/wongi-engine/error.rb +22 -0
- data/lib/wongi-engine/filter.rb +6 -0
- data/lib/wongi-engine/filter/asserting_test.rb +20 -0
- data/lib/wongi-engine/filter/equality_test.rb +36 -0
- data/lib/wongi-engine/filter/filter_test.rb +18 -0
- data/lib/wongi-engine/filter/greater_than_test.rb +36 -0
- data/lib/wongi-engine/filter/inequality_test.rb +36 -0
- data/lib/wongi-engine/filter/less_than_test.rb +36 -0
- data/lib/wongi-engine/graph.rb +73 -0
- data/lib/wongi-engine/network.rb +416 -0
- data/lib/wongi-engine/network/collectable.rb +42 -0
- data/lib/wongi-engine/network/debug.rb +85 -0
- data/lib/wongi-engine/ruleset.rb +74 -0
- data/lib/wongi-engine/template.rb +78 -0
- data/lib/wongi-engine/token.rb +114 -0
- data/lib/wongi-engine/version.rb +5 -0
- data/lib/wongi-engine/wme.rb +89 -0
- data/lib/wongi-engine/wme_match_data.rb +34 -0
- data/spec/beta_node_spec.rb +29 -0
- data/spec/bug_specs/issue_4_spec.rb +141 -0
- data/spec/dataset_spec.rb +27 -0
- data/spec/dsl_spec.rb +9 -0
- data/spec/filter_specs/assert_test_spec.rb +102 -0
- data/spec/filter_specs/less_test_spec.rb +41 -0
- data/spec/generation_spec.rb +116 -0
- data/spec/high_level_spec.rb +378 -0
- data/spec/network_spec.rb +182 -0
- data/spec/overlay_spec.rb +61 -0
- data/spec/rule_specs/any_rule_spec.rb +75 -0
- data/spec/rule_specs/assign_spec.rb +88 -0
- data/spec/rule_specs/assuming_spec.rb +66 -0
- data/spec/rule_specs/maybe_rule_spec.rb +101 -0
- data/spec/rule_specs/ncc_spec.rb +258 -0
- data/spec/rule_specs/negative_rule_spec.rb +105 -0
- data/spec/ruleset_spec.rb +54 -0
- data/spec/simple_action_spec.rb +40 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/wme_spec.rb +83 -0
- data/wongi-engine.gemspec +40 -0
- 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
|