wongi-engine 0.3.2 → 0.3.6
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.
- checksums.yaml +5 -5
- data/.travis.yml +8 -5
- data/lib/wongi-engine/beta/ncc_node.rb +1 -1
- data/lib/wongi-engine/beta/production_node.rb +1 -1
- data/lib/wongi-engine/compiler.rb +1 -1
- data/lib/wongi-engine/dsl/action/simple_action.rb +2 -2
- data/lib/wongi-engine/dsl.rb +6 -0
- data/lib/wongi-engine/filter/greater_than_or_equal_test.rb +32 -0
- data/lib/wongi-engine/filter/less_than_or_equal_test.rb +32 -0
- data/lib/wongi-engine/filter.rb +3 -1
- data/lib/wongi-engine/version.rb +1 -1
- data/spec/action_class_spec.rb +62 -0
- data/spec/filter_specs/greater_than_equality_test_spec.rb +33 -0
- data/spec/filter_specs/less_than_equality_test_spec.rb +33 -0
- data/spec/rule_specs/any_rule_spec.rb +69 -0
- data/spec/rule_specs/ncc_spec.rb +16 -0
- metadata +14 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5d9f803da98de1a0ec47f26a1adc83940f6ef2d3e8dbfc3dbfb9527c9efe4daf
|
4
|
+
data.tar.gz: 3d1ace03974a04999b3e4f969c64d0bad2b4da99dc11606db06b1723d056b881
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e7d0c9d09716e02cb60256f048b97d04742733e8587c110a8e3b80b0f641e0bc213f8a3baea543f89a3f4f454a7f9f987321b66b0ed6decd530d7ec568cdbe11
|
7
|
+
data.tar.gz: e5e3f2158f9975ad23aa7c4115886c17c4b92529967d97395f39c7a28d608dcf2adc7827cecdc9b6bcb1dd8200699c9ad61c8997e638c07cb15534bdbaa61701
|
data/.travis.yml
CHANGED
@@ -49,7 +49,7 @@ module Wongi::Engine
|
|
49
49
|
def join_node(condition, tests, assignment)
|
50
50
|
alpha = rete.compile_alpha(condition)
|
51
51
|
beta_memory
|
52
|
-
self.node = if existing = node.children.find { |n| n.is_a?(JoinNode) && n.equivalent?(alpha, tests, assignment) }
|
52
|
+
self.node = if existing = node.children.find { |n| n.is_a?(JoinNode) && n.equivalent?(alpha, tests, assignment) && !n.children.map(&:class).include?(Wongi::Engine::OrNode) }
|
53
53
|
existing
|
54
54
|
else
|
55
55
|
JoinNode.new(node, tests, assignment).tap do |join|
|
@@ -32,7 +32,7 @@ module Wongi::Engine
|
|
32
32
|
elsif @deaction.respond_to? :call
|
33
33
|
@deaction.call token
|
34
34
|
elsif @deaction.respond_to? :deexecute
|
35
|
-
@deaction.
|
35
|
+
@deaction.deexecute token
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
@@ -43,7 +43,7 @@ module Wongi::Engine
|
|
43
43
|
elsif @reaction.respond_to? :call
|
44
44
|
@reaction.call token, newtoken
|
45
45
|
elsif @reaction.respond_to? :reexecute
|
46
|
-
@reaction.
|
46
|
+
@reaction.reexecute token, newtoken
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
data/lib/wongi-engine/dsl.rb
CHANGED
@@ -81,9 +81,15 @@ module Wongi::Engine::DSL
|
|
81
81
|
clause :less
|
82
82
|
accept Wongi::Engine::LessThanTest
|
83
83
|
|
84
|
+
clause :lte
|
85
|
+
accept Wongi::Engine::LessThanOrEqualTest
|
86
|
+
|
84
87
|
clause :greater
|
85
88
|
accept Wongi::Engine::GreaterThanTest
|
86
89
|
|
90
|
+
clause :gte
|
91
|
+
accept Wongi::Engine::GreaterThanOrEqualTest
|
92
|
+
|
87
93
|
clause :assert, :dynamic
|
88
94
|
accept Wongi::Engine::AssertingTest
|
89
95
|
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Wongi::Engine
|
3
|
+
class GreaterThanOrEqualTest < FilterTest
|
4
|
+
attr_reader :x, :y
|
5
|
+
|
6
|
+
def initialize(x, y)
|
7
|
+
@x = x
|
8
|
+
@y = y
|
9
|
+
end
|
10
|
+
|
11
|
+
def passes?(token)
|
12
|
+
x = if Template.variable? @x
|
13
|
+
token[@x]
|
14
|
+
else
|
15
|
+
@x
|
16
|
+
end
|
17
|
+
|
18
|
+
y = if Template.variable? @y
|
19
|
+
token[@y]
|
20
|
+
else
|
21
|
+
@y
|
22
|
+
end
|
23
|
+
|
24
|
+
return false if x == :_ || y == :_
|
25
|
+
x >= y
|
26
|
+
end
|
27
|
+
|
28
|
+
def ==(other)
|
29
|
+
super && x == other.x && y == other.y
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Wongi::Engine
|
3
|
+
class LessThanOrEqualTest < FilterTest
|
4
|
+
attr_reader :x, :y
|
5
|
+
|
6
|
+
def initialize(x, y)
|
7
|
+
@x = x
|
8
|
+
@y = y
|
9
|
+
end
|
10
|
+
|
11
|
+
def passes?(token)
|
12
|
+
x = if Template.variable? @x
|
13
|
+
token[@x]
|
14
|
+
else
|
15
|
+
@x
|
16
|
+
end
|
17
|
+
|
18
|
+
y = if Template.variable? @y
|
19
|
+
token[@y]
|
20
|
+
else
|
21
|
+
@y
|
22
|
+
end
|
23
|
+
|
24
|
+
return false if x == :_ || y == :_
|
25
|
+
x <= y
|
26
|
+
end
|
27
|
+
|
28
|
+
def ==(other)
|
29
|
+
super && x == other.x && y == other.y
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/wongi-engine/filter.rb
CHANGED
@@ -3,4 +3,6 @@ require 'wongi-engine/filter/equality_test'
|
|
3
3
|
require 'wongi-engine/filter/inequality_test'
|
4
4
|
require 'wongi-engine/filter/asserting_test'
|
5
5
|
require 'wongi-engine/filter/less_than_test'
|
6
|
-
require 'wongi-engine/filter/greater_than_test'
|
6
|
+
require 'wongi-engine/filter/greater_than_test'
|
7
|
+
require 'wongi-engine/filter/less_than_or_equal_test'
|
8
|
+
require 'wongi-engine/filter/greater_than_or_equal_test'
|
data/lib/wongi-engine/version.rb
CHANGED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe 'action classes' do
|
5
|
+
|
6
|
+
include Wongi::Engine::DSL
|
7
|
+
|
8
|
+
let :engine do
|
9
|
+
Wongi::Engine.create
|
10
|
+
end
|
11
|
+
|
12
|
+
let :action_class do
|
13
|
+
Class.new do
|
14
|
+
class << self
|
15
|
+
attr_accessor :execute_body
|
16
|
+
attr_accessor :deexecute_body
|
17
|
+
end
|
18
|
+
|
19
|
+
def execute(token)
|
20
|
+
self.class.execute_body.call(token)
|
21
|
+
end
|
22
|
+
|
23
|
+
def deexecute(token)
|
24
|
+
self.class.deexecute_body.call(token)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should have appropriate callbacks executed' do
|
30
|
+
|
31
|
+
executed = 0
|
32
|
+
deexecuted = 0
|
33
|
+
|
34
|
+
klass = action_class
|
35
|
+
|
36
|
+
klass.execute_body = lambda do |token|
|
37
|
+
executed += 1
|
38
|
+
end
|
39
|
+
klass.deexecute_body = lambda do |token|
|
40
|
+
deexecuted += 1
|
41
|
+
end
|
42
|
+
|
43
|
+
engine << rule {
|
44
|
+
forall {
|
45
|
+
has :A, :x, :B
|
46
|
+
}
|
47
|
+
make {
|
48
|
+
action klass
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
engine << [1, :x, 2]
|
53
|
+
expect(executed).to be == 1
|
54
|
+
expect(deexecuted).to be == 0
|
55
|
+
|
56
|
+
engine.retract [1, :x, 2]
|
57
|
+
expect(executed).to be == 1
|
58
|
+
expect(deexecuted).to be == 1
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe 'Greater Than Or Equal test' do
|
6
|
+
before :each do
|
7
|
+
@engine = Wongi::Engine.create
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :engine
|
11
|
+
|
12
|
+
attr_reader :production
|
13
|
+
|
14
|
+
def test_rule(&block)
|
15
|
+
@production = (engine << rule('test-rule', &block))
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should interact with optional node correctly' do
|
19
|
+
# before the fix, filters would try to piggy-back on optional templates
|
20
|
+
|
21
|
+
test_rule do
|
22
|
+
forall do
|
23
|
+
has :Number, :assign_check, :_
|
24
|
+
gte :Number, 6
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
engine << [6, :assign_check, nil]
|
29
|
+
engine << [7, :assign_check, nil]
|
30
|
+
engine << [5, :assign_check, nil]
|
31
|
+
expect(@production.size).to eq(2)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe 'Less Than Or Equal test' do
|
6
|
+
before :each do
|
7
|
+
@engine = Wongi::Engine.create
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :engine
|
11
|
+
|
12
|
+
attr_reader :production
|
13
|
+
|
14
|
+
def test_rule(&block)
|
15
|
+
@production = (engine << rule('test-rule', &block))
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should interact with optional node correctly' do
|
19
|
+
# before the fix, filters would try to piggy-back on optional templates
|
20
|
+
|
21
|
+
test_rule do
|
22
|
+
forall do
|
23
|
+
has :Number, :assign_check, :_
|
24
|
+
lte :Number, 6
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
engine << [5, :assign_check, nil]
|
29
|
+
engine << [6, :assign_check, nil]
|
30
|
+
engine << [7, :assign_check, nil] #should not pass
|
31
|
+
expect(@production.size).to eq(2)
|
32
|
+
end
|
33
|
+
end
|
@@ -106,4 +106,73 @@ describe "ANY rule" do
|
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
109
|
+
describe "ordering rules" do
|
110
|
+
let :any_stale_pastry_rule do
|
111
|
+
rule do
|
112
|
+
forall {
|
113
|
+
# has :A, :name, :Name # uncomment this line will make test pass
|
114
|
+
any {
|
115
|
+
option {
|
116
|
+
has :A, :name, 'Donut'
|
117
|
+
}
|
118
|
+
option {
|
119
|
+
has :A, :name, 'Cookie'
|
120
|
+
}
|
121
|
+
}
|
122
|
+
has :A, :condition, 'stale' # moving this line above 'any' will make test pass
|
123
|
+
}
|
124
|
+
make {
|
125
|
+
collect :A, :stale_pastries
|
126
|
+
}
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
let :fresh_donut_rule do
|
131
|
+
rule do
|
132
|
+
forall {
|
133
|
+
has :A, :name, 'Donut'
|
134
|
+
has :A, :condition, 'fresh'
|
135
|
+
}
|
136
|
+
make {
|
137
|
+
collect :A, :fresh_donuts
|
138
|
+
}
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
let :fresh_cookie_rule do
|
143
|
+
rule do
|
144
|
+
forall {
|
145
|
+
# swapping the following lines will make test pass
|
146
|
+
has :A, :name, 'Cookie'
|
147
|
+
has :A, :condition, 'fresh'
|
148
|
+
}
|
149
|
+
make {
|
150
|
+
collect :A, :fresh_cookies
|
151
|
+
}
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
before do
|
156
|
+
engine << any_stale_pastry_rule # commenting this rule, or moving it to end of rules will make test pass
|
157
|
+
|
158
|
+
engine << fresh_donut_rule
|
159
|
+
engine << fresh_cookie_rule # commenting this rule will make test pass
|
160
|
+
|
161
|
+
engine << [:donut, :name, 'Donut']
|
162
|
+
engine << [:donut, :condition, 'fresh']
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'has no fresh cookies' do
|
166
|
+
# this expectation fails; the collection contains [:donut]!
|
167
|
+
expect(engine.collection(:fresh_cookies)).to match_array([])
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'has one fresh donut' do
|
171
|
+
expect(engine.collection(:fresh_donuts)).to match_array([:donut])
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'has no stale pastries' do
|
175
|
+
expect(engine.collection(:stale_pastries)).to match_array([])
|
176
|
+
end
|
177
|
+
end
|
109
178
|
end
|
data/spec/rule_specs/ncc_spec.rb
CHANGED
@@ -255,4 +255,20 @@ describe Wongi::Engine::NccNode do
|
|
255
255
|
expect(engine.find "StudentA", :passes_for, "CourseC").to be_nil
|
256
256
|
end
|
257
257
|
|
258
|
+
specify 'regression #71' do
|
259
|
+
prod = engine << rule {
|
260
|
+
forall {
|
261
|
+
none {
|
262
|
+
has "TestSet", :contains, :B
|
263
|
+
has "MatchSet", :contains, :B
|
264
|
+
}
|
265
|
+
}
|
266
|
+
}
|
267
|
+
engine << ["TestSet", :contains, "not matching"]
|
268
|
+
engine << ["MatchSet", :contains, "match 1"]
|
269
|
+
engine << ["MatchSet", :contains, "match 2"]
|
270
|
+
|
271
|
+
expect(prod).to have(1).tokens
|
272
|
+
end
|
273
|
+
|
258
274
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wongi-engine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Valeri Sokolov
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-10-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -131,8 +131,10 @@ files:
|
|
131
131
|
- lib/wongi-engine/filter/asserting_test.rb
|
132
132
|
- lib/wongi-engine/filter/equality_test.rb
|
133
133
|
- lib/wongi-engine/filter/filter_test.rb
|
134
|
+
- lib/wongi-engine/filter/greater_than_or_equal_test.rb
|
134
135
|
- lib/wongi-engine/filter/greater_than_test.rb
|
135
136
|
- lib/wongi-engine/filter/inequality_test.rb
|
137
|
+
- lib/wongi-engine/filter/less_than_or_equal_test.rb
|
136
138
|
- lib/wongi-engine/filter/less_than_test.rb
|
137
139
|
- lib/wongi-engine/graph.rb
|
138
140
|
- lib/wongi-engine/network.rb
|
@@ -144,12 +146,15 @@ files:
|
|
144
146
|
- lib/wongi-engine/version.rb
|
145
147
|
- lib/wongi-engine/wme.rb
|
146
148
|
- lib/wongi-engine/wme_match_data.rb
|
149
|
+
- spec/action_class_spec.rb
|
147
150
|
- spec/beta_node_spec.rb
|
148
151
|
- spec/bug_specs/issue_4_spec.rb
|
149
152
|
- spec/dataset_spec.rb
|
150
153
|
- spec/dsl_spec.rb
|
151
154
|
- spec/filter_specs/assert_test_spec.rb
|
155
|
+
- spec/filter_specs/greater_than_equality_test_spec.rb
|
152
156
|
- spec/filter_specs/less_test_spec.rb
|
157
|
+
- spec/filter_specs/less_than_equality_test_spec.rb
|
153
158
|
- spec/generation_spec.rb
|
154
159
|
- spec/high_level_spec.rb
|
155
160
|
- spec/network_spec.rb
|
@@ -170,7 +175,7 @@ homepage: https://github.com/ulfurinn/wongi-engine
|
|
170
175
|
licenses:
|
171
176
|
- MIT
|
172
177
|
metadata: {}
|
173
|
-
post_install_message:
|
178
|
+
post_install_message:
|
174
179
|
rdoc_options: []
|
175
180
|
require_paths:
|
176
181
|
- lib
|
@@ -185,18 +190,20 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
185
190
|
- !ruby/object:Gem::Version
|
186
191
|
version: '0'
|
187
192
|
requirements: []
|
188
|
-
|
189
|
-
|
190
|
-
signing_key:
|
193
|
+
rubygems_version: 3.1.4
|
194
|
+
signing_key:
|
191
195
|
specification_version: 4
|
192
196
|
summary: A forward-chaining rule engine in pure Ruby.
|
193
197
|
test_files:
|
198
|
+
- spec/action_class_spec.rb
|
194
199
|
- spec/beta_node_spec.rb
|
195
200
|
- spec/bug_specs/issue_4_spec.rb
|
196
201
|
- spec/dataset_spec.rb
|
197
202
|
- spec/dsl_spec.rb
|
198
203
|
- spec/filter_specs/assert_test_spec.rb
|
204
|
+
- spec/filter_specs/greater_than_equality_test_spec.rb
|
199
205
|
- spec/filter_specs/less_test_spec.rb
|
206
|
+
- spec/filter_specs/less_than_equality_test_spec.rb
|
200
207
|
- spec/generation_spec.rb
|
201
208
|
- spec/high_level_spec.rb
|
202
209
|
- spec/network_spec.rb
|