wongi-engine 0.3.9 → 0.4.0.pre.alpha1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +2 -2
- data/.gitignore +2 -0
- data/README.md +12 -12
- data/lib/wongi-engine/alpha_index.rb +58 -0
- data/lib/wongi-engine/alpha_memory.rb +2 -24
- data/lib/wongi-engine/beta/aggregate_node.rb +16 -15
- data/lib/wongi-engine/beta/assignment_node.rb +7 -2
- data/lib/wongi-engine/beta/beta_node.rb +27 -23
- data/lib/wongi-engine/beta/filter_node.rb +8 -13
- data/lib/wongi-engine/beta/join_node.rb +15 -28
- data/lib/wongi-engine/beta/ncc_node.rb +14 -26
- data/lib/wongi-engine/beta/ncc_partner.rb +18 -18
- data/lib/wongi-engine/beta/neg_node.rb +23 -55
- data/lib/wongi-engine/beta/optional_node.rb +24 -48
- data/lib/wongi-engine/beta/or_node.rb +24 -1
- data/lib/wongi-engine/beta/production_node.rb +9 -3
- data/lib/wongi-engine/beta/root_node.rb +47 -0
- data/lib/wongi-engine/beta.rb +1 -1
- data/lib/wongi-engine/compiler.rb +6 -34
- data/lib/wongi-engine/dsl/action/{base.rb → base_action.rb} +5 -1
- data/lib/wongi-engine/dsl/action/error_generator.rb +1 -1
- data/lib/wongi-engine/dsl/action/simple_action.rb +1 -1
- data/lib/wongi-engine/dsl/action/simple_collector.rb +1 -1
- data/lib/wongi-engine/dsl/action/statement_generator.rb +21 -22
- data/lib/wongi-engine/dsl/action/trace_action.rb +1 -1
- data/lib/wongi-engine/dsl/clause/fact.rb +2 -6
- data/lib/wongi-engine/dsl.rb +1 -25
- data/lib/wongi-engine/graph.rb +1 -1
- data/lib/wongi-engine/network/debug.rb +2 -10
- data/lib/wongi-engine/network.rb +44 -105
- data/lib/wongi-engine/overlay.rb +589 -0
- data/lib/wongi-engine/template.rb +22 -2
- data/lib/wongi-engine/token.rb +10 -26
- data/lib/wongi-engine/token_assignment.rb +15 -0
- data/lib/wongi-engine/version.rb +1 -1
- data/lib/wongi-engine/wme.rb +10 -39
- data/lib/wongi-engine.rb +3 -1
- data/spec/alpha_index_spec.rb +78 -0
- data/spec/bug_specs/issue_4_spec.rb +11 -11
- data/spec/high_level_spec.rb +8 -101
- data/spec/network_spec.rb +8 -6
- data/spec/overlay_spec.rb +161 -3
- data/spec/rule_specs/any_rule_spec.rb +39 -0
- data/spec/rule_specs/assign_spec.rb +1 -1
- data/spec/rule_specs/maybe_rule_spec.rb +58 -1
- data/spec/rule_specs/ncc_spec.rb +78 -19
- data/spec/rule_specs/negative_rule_spec.rb +12 -14
- data/spec/spec_helper.rb +4 -0
- data/spec/wme_spec.rb +0 -32
- metadata +11 -9
- data/lib/wongi-engine/beta/beta_memory.rb +0 -60
- data/lib/wongi-engine/data_overlay.rb +0 -149
- data/spec/rule_specs/or_rule_spec.rb +0 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cf15effd33cba1faca7c6b2a6ce8b8a4730981a9b778fb5d41e11b4dce7803f8
|
4
|
+
data.tar.gz: 8d3cc0c99061e7097747b4339c55a83c11e79bb0edfbba4a0c95e4c850301595
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7140c583e23389df8f5c959b7ed31220782d72afcbd10f0883ba7314f24534656f1ca3fed33ed9d49a7962da8cbe7535f48bf160be88eef86d3798efe7ccece5
|
7
|
+
data.tar.gz: 3f0e9957b8497666a25c3ac933bcfe93495ed2c4cdac2f4eb27468c95401a107139f6a23840816241f94c0811edf69ab373818dd33def938d3ae9450505c68b5
|
data/.github/workflows/test.yml
CHANGED
@@ -11,10 +11,10 @@ jobs:
|
|
11
11
|
|
12
12
|
strategy:
|
13
13
|
matrix:
|
14
|
-
ruby-version: ["3.1", "3.0", "2.7", "
|
14
|
+
ruby-version: ["3.1", "3.0", "2.7", "jruby-head"]
|
15
15
|
|
16
16
|
steps:
|
17
|
-
- uses: actions/checkout@
|
17
|
+
- uses: actions/checkout@v3
|
18
18
|
- name: Set up Ruby ${{ matrix.ruby-version }}
|
19
19
|
uses: ruby/setup-ruby@v1
|
20
20
|
with:
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -3,26 +3,26 @@
|
|
3
3
|
[![Gem](https://img.shields.io/gem/v/wongi-engine.svg)](https://rubygems.org/gems/wongi-engine/)
|
4
4
|
[![Build Status](https://github.com/ulfurinn/wongi-engine/actions/workflows/test.yml/badge.svg)](https://github.com/ulfurinn/wongi-engine/actions/workflows/test.yml)
|
5
5
|
|
6
|
+
This is a pure-Ruby forward-chaining rule engine based on the classic [Rete algorithm](http://en.wikipedia.org/wiki/Rete_algorithm).
|
7
|
+
|
6
8
|
Ruby >= 2.7 and JRuby are supported. Rubinius should work but isn't actively supported.
|
7
9
|
|
8
|
-
##
|
10
|
+
## Documentation
|
11
|
+
|
12
|
+
There is no API documentation, as most of the library's interfaces are for internal use only and would not be safe to use directly.
|
13
|
+
|
14
|
+
Instead, follow the [tutorial](http://ulfurinn.github.io/wongi-engine/) and stick to the constructs described in it.
|
9
15
|
|
10
|
-
|
16
|
+
## Upgrading
|
11
17
|
|
12
|
-
|
18
|
+
Until there is a 1.0 release, all minor versions should be treated as potentially breaking.
|
13
19
|
|
14
|
-
|
20
|
+
Always test your rules extensively. There's always a chance of you finding a bug in the engine that is only triggered by a very specific rule configuration.
|
21
|
+
|
22
|
+
[Feature annoucements](https://github.com/ulfurinn/wongi-engine/issues?q=is%3Aissue+label%3Aannoucement)
|
15
23
|
|
16
24
|
[Open discussions](https://github.com/ulfurinn/wongi-engine/issues?q=is%3Aopen+is%3Aissue+label%3Adiscussion)
|
17
25
|
|
18
26
|
## Acknowledgements
|
19
27
|
|
20
28
|
The Rete implementation in this library largely follows the outline presented in [\[Doorenbos, 1995\]](http://reports-archive.adm.cs.cmu.edu/anon/1995/CMU-CS-95-113.pdf).
|
21
|
-
|
22
|
-
## Contributing
|
23
|
-
|
24
|
-
1. Fork it
|
25
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
26
|
-
3. Commit your changes (`git commit -am 'Added some feature'`)
|
27
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
28
|
-
5. Create new Pull Request
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Wongi::Engine
|
2
|
+
class AlphaIndex
|
3
|
+
attr_reader :pattern, :index
|
4
|
+
private :pattern
|
5
|
+
private :index
|
6
|
+
|
7
|
+
def initialize(pattern)
|
8
|
+
@pattern = pattern
|
9
|
+
@index = Hash.new { |h, k| h[k] = [] }
|
10
|
+
end
|
11
|
+
|
12
|
+
def add(wme)
|
13
|
+
collection_for_wme(wme).push(wme)
|
14
|
+
end
|
15
|
+
|
16
|
+
def remove(wme)
|
17
|
+
collection = collection_for_wme(wme)
|
18
|
+
collection.delete(wme)
|
19
|
+
if collection.empty?
|
20
|
+
# release some memory
|
21
|
+
index.delete(hashed_key(wme))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def collection_for_wme(wme)
|
26
|
+
index[hashed_key(wme)]
|
27
|
+
end
|
28
|
+
|
29
|
+
def collections_for_template(template)
|
30
|
+
return nil unless template_matches_pattern?(template)
|
31
|
+
|
32
|
+
# here we know that all fields on which we're indexing are concrete in the template
|
33
|
+
collection_for_wme(template)
|
34
|
+
end
|
35
|
+
|
36
|
+
private def template_matches_pattern?(template)
|
37
|
+
template_element_matches_pattern?(:subject, template.subject) &&
|
38
|
+
template_element_matches_pattern?(:predicate, template.predicate) &&
|
39
|
+
template_element_matches_pattern?(:object, template.object)
|
40
|
+
end
|
41
|
+
|
42
|
+
private def template_element_matches_pattern?(member, template_element)
|
43
|
+
if Template.concrete?(template_element)
|
44
|
+
pattern.include?(member)
|
45
|
+
else
|
46
|
+
!pattern.include?(member)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private def key(wme)
|
51
|
+
pattern.map { wme.public_send(_1) }
|
52
|
+
end
|
53
|
+
|
54
|
+
private def hashed_key(wme)
|
55
|
+
key(wme).map(&:hash)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -2,16 +2,14 @@ module Wongi::Engine
|
|
2
2
|
class AlphaMemory
|
3
3
|
attr_reader :betas, :template, :rete
|
4
4
|
|
5
|
-
def initialize(template, rete
|
5
|
+
def initialize(template, rete)
|
6
6
|
@template = template
|
7
7
|
@rete = rete
|
8
8
|
@betas = []
|
9
|
-
@wmes = []
|
10
9
|
@frozen = false
|
11
10
|
end
|
12
11
|
|
13
12
|
def activate(wme)
|
14
|
-
wme.overlay.add_wme(wme, self)
|
15
13
|
# TODO: it used to activate before adding to the list. mandated by the original thesis. investigate. it appears to create duplicate tokens - needs a remedy in collecting nodes
|
16
14
|
betas.each do |beta|
|
17
15
|
beta.alpha_activate wme
|
@@ -19,18 +17,12 @@ module Wongi::Engine
|
|
19
17
|
end
|
20
18
|
|
21
19
|
def deactivate(wme)
|
22
|
-
wme
|
20
|
+
# p deactivate: {wme:}
|
23
21
|
betas.each do |beta|
|
24
22
|
beta.alpha_deactivate wme
|
25
23
|
end
|
26
24
|
end
|
27
25
|
|
28
|
-
def snapshot!(alpha)
|
29
|
-
alpha.wmes.map(&:dup).each do |wme|
|
30
|
-
activate wme
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
26
|
def inspect
|
35
27
|
"<Alpha #{__id__} template=#{template}>"
|
36
28
|
end
|
@@ -38,19 +30,5 @@ module Wongi::Engine
|
|
38
30
|
def to_s
|
39
31
|
inspect
|
40
32
|
end
|
41
|
-
|
42
|
-
def size
|
43
|
-
wmes.count
|
44
|
-
end
|
45
|
-
|
46
|
-
def wmes
|
47
|
-
Enumerator.new do |y|
|
48
|
-
rete.overlays.each do |overlay|
|
49
|
-
overlay.raw_wmes(self).dup.each do |wme|
|
50
|
-
y << wme
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
33
|
end
|
56
34
|
end
|
@@ -27,41 +27,42 @@ module Wongi::Engine
|
|
27
27
|
|
28
28
|
def alpha_activate(wme)
|
29
29
|
# we need to re-run all WMEs through the aggregator, so the new incoming one doesn't matter
|
30
|
-
|
31
|
-
evaluate(wme, token)
|
30
|
+
tokens.each do |token|
|
31
|
+
evaluate(wme: wme, token: token)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
35
|
def alpha_deactivate(wme)
|
36
36
|
# we need to re-run all WMEs through the aggregator, so the new incoming one doesn't matter
|
37
|
-
|
38
|
-
evaluate(wme, token)
|
37
|
+
tokens.each do |token|
|
38
|
+
evaluate(wme: wme, token: token)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
42
|
def beta_activate(token)
|
43
|
-
|
43
|
+
return if tokens.find { |t| t.duplicate? token }
|
44
|
+
|
45
|
+
overlay.add_token(token)
|
46
|
+
evaluate(wme: nil, token: token)
|
44
47
|
end
|
45
48
|
|
46
49
|
def beta_deactivate(token)
|
47
|
-
|
48
|
-
|
49
|
-
child.beta_deactivate t if t.parent == token
|
50
|
-
end
|
51
|
-
end
|
50
|
+
overlay.remove_token(token)
|
51
|
+
beta_deactivate_children(token: token)
|
52
52
|
end
|
53
53
|
|
54
54
|
def refresh_child(child)
|
55
|
-
|
56
|
-
evaluate(nil, token, child)
|
55
|
+
tokens.each do |token|
|
56
|
+
evaluate(wme: nil, token: token, child: child)
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
-
def evaluate(wme
|
60
|
+
def evaluate(wme:, token:, child: nil)
|
61
61
|
# clean up previous decisions
|
62
|
-
|
62
|
+
# # TODO: optimise: only clean up if the value changed
|
63
|
+
beta_deactivate_children(token: token)
|
63
64
|
|
64
|
-
candidates = alpha.
|
65
|
+
candidates = select_wmes(alpha.template) { |asserted_wme| matches?(token, asserted_wme) }
|
65
66
|
|
66
67
|
return if candidates.empty?
|
67
68
|
|
@@ -7,12 +7,17 @@ module Wongi::Engine
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def beta_activate(token, _wme = nil, _assignments = {})
|
10
|
+
return if tokens.find { |t| t.duplicate? token }
|
11
|
+
|
12
|
+
overlay.add_token(token)
|
10
13
|
children.each do |child|
|
11
|
-
|
14
|
+
value = @body.respond_to?(:call) ? @body.call(token) : @body
|
15
|
+
child.beta_activate Token.new(child, token, nil, { @variable => value })
|
12
16
|
end
|
13
17
|
end
|
14
18
|
|
15
19
|
def beta_deactivate(token)
|
20
|
+
overlay.remove_token(token)
|
16
21
|
children.each do |child|
|
17
22
|
child.tokens.each do |t|
|
18
23
|
if t.parent == token
|
@@ -24,7 +29,7 @@ module Wongi::Engine
|
|
24
29
|
end
|
25
30
|
|
26
31
|
def refresh_child(child)
|
27
|
-
|
32
|
+
tokens.each do |token|
|
28
33
|
child.beta_activate Token.new(child, token, nil, { @variable => @body.respond_to?(:call) ? @body.call(token) : @body })
|
29
34
|
end
|
30
35
|
end
|
@@ -1,26 +1,5 @@
|
|
1
1
|
module Wongi::Engine
|
2
2
|
class BetaNode
|
3
|
-
module TokenContainer
|
4
|
-
def tokens
|
5
|
-
Enumerator.new do |y|
|
6
|
-
rete.overlays.each do |overlay|
|
7
|
-
overlay.raw_tokens(self).dup.each do |token|
|
8
|
-
y << token unless token.deleted?
|
9
|
-
end
|
10
|
-
overlay.raw_tokens(self).reject!(&:deleted?)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def empty?
|
16
|
-
tokens.first.nil?
|
17
|
-
end
|
18
|
-
|
19
|
-
def size
|
20
|
-
tokens.count
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
3
|
include CoreExt
|
25
4
|
|
26
5
|
attr_writer :rete
|
@@ -58,6 +37,7 @@ module Wongi::Engine
|
|
58
37
|
abstract :beta_activate
|
59
38
|
abstract :beta_deactivate
|
60
39
|
abstract :beta_reactivate
|
40
|
+
abstract :refresh_child
|
61
41
|
|
62
42
|
def assignment_node(variable, body)
|
63
43
|
node = AssignmentNode.new self, variable, body
|
@@ -69,8 +49,32 @@ module Wongi::Engine
|
|
69
49
|
parent.refresh_child self
|
70
50
|
end
|
71
51
|
|
72
|
-
def
|
73
|
-
|
52
|
+
def beta_deactivate_children(token: nil, wme: nil, children: self.children)
|
53
|
+
children.each do |child|
|
54
|
+
child.tokens.select { (token.nil? || _1.parent == token) && (wme.nil? || _1.wme == wme) }.each do |child_token|
|
55
|
+
child.beta_deactivate(child_token)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private def select_wmes(template)
|
61
|
+
rete.current_overlay.select(template)
|
62
|
+
end
|
63
|
+
|
64
|
+
def tokens
|
65
|
+
overlay.node_tokens(self)
|
66
|
+
end
|
67
|
+
|
68
|
+
def overlay
|
69
|
+
rete.current_overlay
|
70
|
+
end
|
71
|
+
|
72
|
+
def empty?
|
73
|
+
tokens.first.nil?
|
74
|
+
end
|
75
|
+
|
76
|
+
def size
|
77
|
+
tokens.count
|
74
78
|
end
|
75
79
|
|
76
80
|
private
|
@@ -10,22 +10,20 @@ module Wongi
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def beta_activate(token)
|
13
|
+
return if tokens.find { |t| t.duplicate? token }
|
14
|
+
|
13
15
|
return unless test.passes?(token)
|
14
16
|
|
17
|
+
overlay.add_token(token)
|
18
|
+
|
15
19
|
children.each do |child|
|
16
20
|
child.beta_activate Token.new(child, token, nil, {})
|
17
21
|
end
|
18
22
|
end
|
19
23
|
|
20
24
|
def beta_deactivate(token)
|
21
|
-
|
22
|
-
|
23
|
-
if t.parent == token
|
24
|
-
child.beta_deactivate t
|
25
|
-
# token.destroy
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
25
|
+
overlay.remove_token(token)
|
26
|
+
beta_deactivate_children(token: token)
|
29
27
|
end
|
30
28
|
|
31
29
|
def equivalent?(test)
|
@@ -33,12 +31,9 @@ module Wongi
|
|
33
31
|
end
|
34
32
|
|
35
33
|
def refresh_child(child)
|
36
|
-
|
37
|
-
|
38
|
-
parent.tokens.each do |token|
|
39
|
-
beta_activate token
|
34
|
+
tokens.select { test.passes?(_1) }.each do |token|
|
35
|
+
child.beta_activate Token.new(child, token, nil, {})
|
40
36
|
end
|
41
|
-
self.children = tmp
|
42
37
|
end
|
43
38
|
end
|
44
39
|
end
|
@@ -1,19 +1,5 @@
|
|
1
1
|
module Wongi
|
2
2
|
module Engine
|
3
|
-
TokenAssignment = Struct.new(:wme, :field) do
|
4
|
-
def call(_token = nil)
|
5
|
-
wme.send field
|
6
|
-
end
|
7
|
-
|
8
|
-
def inspect
|
9
|
-
"#{field} of #{wme}"
|
10
|
-
end
|
11
|
-
|
12
|
-
def to_s
|
13
|
-
inspect
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
3
|
class BetaTest
|
18
4
|
attr_reader :field, :variable
|
19
5
|
|
@@ -57,8 +43,10 @@ module Wongi
|
|
57
43
|
end
|
58
44
|
|
59
45
|
def alpha_activate(wme)
|
46
|
+
# p alpha_activate: {class: self.class, object_id:, wme:}
|
60
47
|
assignments = collect_assignments(wme)
|
61
|
-
|
48
|
+
|
49
|
+
tokens.each do |token|
|
62
50
|
next unless matches?(token, wme)
|
63
51
|
|
64
52
|
children.each do |beta|
|
@@ -68,15 +56,16 @@ module Wongi
|
|
68
56
|
end
|
69
57
|
|
70
58
|
def alpha_deactivate(wme)
|
71
|
-
|
72
|
-
child.tokens.each do |token|
|
73
|
-
child.beta_deactivate token if token.wme == wme
|
74
|
-
end
|
75
|
-
end
|
59
|
+
beta_deactivate_children(wme: wme)
|
76
60
|
end
|
77
61
|
|
78
62
|
def beta_activate(token)
|
79
|
-
|
63
|
+
# p beta_activate: {class: self.class, object_id:, token:}
|
64
|
+
return if tokens.find { |t| t.duplicate? token }
|
65
|
+
|
66
|
+
overlay.add_token(token)
|
67
|
+
|
68
|
+
select_wmes(alpha.template).each do |wme|
|
80
69
|
next unless matches?(token, wme)
|
81
70
|
|
82
71
|
assignments = collect_assignments(wme)
|
@@ -87,17 +76,15 @@ module Wongi
|
|
87
76
|
end
|
88
77
|
|
89
78
|
def beta_deactivate(token)
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
end
|
94
|
-
end
|
79
|
+
# p beta_deactivate: {class: self.class, object_id:, token:}
|
80
|
+
overlay.remove_token(token)
|
81
|
+
beta_deactivate_children(token: token)
|
95
82
|
end
|
96
83
|
|
97
84
|
def refresh_child(child)
|
98
|
-
alpha.
|
85
|
+
select_wmes(alpha.template).each do |wme|
|
99
86
|
assignments = collect_assignments(wme)
|
100
|
-
|
87
|
+
tokens.each do |token|
|
101
88
|
child.beta_activate Token.new(child, token, wme, assignments) if matches?(token, wme)
|
102
89
|
end
|
103
90
|
end
|
@@ -1,52 +1,40 @@
|
|
1
1
|
module Wongi
|
2
2
|
module Engine
|
3
3
|
class NccNode < BetaNode
|
4
|
-
include TokenContainer
|
5
|
-
|
6
4
|
attr_accessor :partner
|
7
5
|
|
8
6
|
def beta_activate(token)
|
9
|
-
|
7
|
+
# p beta_activate: {class: self.class, object_id:, token:}
|
8
|
+
return if tokens.find { |t| t.duplicate? token }
|
10
9
|
|
11
|
-
|
12
|
-
t.overlay.add_token(t, self)
|
10
|
+
overlay.add_token(token)
|
13
11
|
partner.tokens.each do |ncc_token|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
ncc_token.owner = t
|
12
|
+
if partner.owner_for(ncc_token) == token
|
13
|
+
overlay.add_ncc_token(token, ncc_token)
|
14
|
+
end
|
18
15
|
end
|
19
|
-
return
|
16
|
+
return if overlay.ncc_tokens_for(token).any?
|
20
17
|
|
21
18
|
children.each do |child|
|
22
|
-
child.beta_activate Token.new(child,
|
19
|
+
child.beta_activate Token.new(child, token, nil, {})
|
23
20
|
end
|
24
21
|
end
|
25
22
|
|
26
23
|
def beta_deactivate(token)
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
t.overlay.remove_token(t, self)
|
31
|
-
t.deleted!
|
32
|
-
partner.tokens.select { |ncc| ncc.owner == t }.each do |ncc_token|
|
33
|
-
ncc_token.owner = nil
|
34
|
-
t.ncc_results.delete(ncc_token)
|
35
|
-
end
|
36
|
-
children.each do |beta|
|
37
|
-
beta.tokens.select { |child_token| child_token.parent == t }.each do |child_token|
|
38
|
-
beta.beta_deactivate(child_token)
|
39
|
-
end
|
40
|
-
end
|
24
|
+
# p beta_deactivate: {class: self.class, object_id:, token:}
|
25
|
+
overlay.remove_token(token)
|
26
|
+
beta_deactivate_children(token: token)
|
41
27
|
end
|
42
28
|
|
43
29
|
def ncc_activate(token)
|
30
|
+
# p ncc_activate: {class: self.class, object_id:, token:}
|
44
31
|
children.each do |child|
|
45
32
|
child.beta_activate Token.new(child, token, nil, {})
|
46
33
|
end
|
47
34
|
end
|
48
35
|
|
49
36
|
def ncc_deactivate(token)
|
37
|
+
# p ncc_deactivate: {class: self.class, object_id:, token:}
|
50
38
|
children.each do |beta|
|
51
39
|
beta.tokens.select { |t| t.parent == token }.each do |t|
|
52
40
|
beta.beta_deactivate t
|
@@ -56,7 +44,7 @@ module Wongi
|
|
56
44
|
|
57
45
|
def refresh_child(child)
|
58
46
|
tokens.each do |token|
|
59
|
-
child.beta_activate Token.new(child, token, nil, {}) if token.
|
47
|
+
child.beta_activate Token.new(child, token, nil, {}) if overlay.ncc_tokens_for(token).empty?
|
60
48
|
end
|
61
49
|
end
|
62
50
|
end
|
@@ -1,39 +1,39 @@
|
|
1
1
|
module Wongi
|
2
2
|
module Engine
|
3
3
|
class NccPartner < BetaNode
|
4
|
-
include TokenContainer
|
5
|
-
|
6
4
|
attr_accessor :ncc, :divergent
|
7
5
|
|
8
6
|
def beta_activate(token)
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
# p beta_activate: {class: self.class, object_id:, token:}
|
8
|
+
return if tokens.find { |t| t.duplicate? token }
|
9
|
+
|
10
|
+
overlay.add_token(token)
|
11
|
+
|
12
|
+
owner = owner_for(token)
|
12
13
|
return unless owner
|
13
14
|
|
14
|
-
owner
|
15
|
-
t.owner = owner
|
15
|
+
overlay.add_ncc_token(owner, token)
|
16
16
|
owner.node.ncc_deactivate owner
|
17
17
|
end
|
18
18
|
|
19
|
-
def beta_deactivate(
|
20
|
-
|
21
|
-
return unless token
|
19
|
+
def beta_deactivate(token)
|
20
|
+
# p beta_deactivate: {class: self.class, object_id:, token:}
|
22
21
|
|
23
|
-
token
|
22
|
+
# fetch the owner before deleting the token
|
23
|
+
owner = overlay.ncc_owner(token)
|
24
24
|
|
25
|
-
|
25
|
+
overlay.remove_token(token)
|
26
26
|
return unless owner
|
27
27
|
|
28
|
-
owner.
|
29
|
-
ncc.ncc_activate owner if owner.ncc_results.empty?
|
28
|
+
ncc.ncc_activate owner if overlay.ncc_tokens_for(owner).empty?
|
30
29
|
end
|
31
30
|
|
32
|
-
private
|
33
|
-
|
34
31
|
def owner_for(token)
|
35
|
-
|
36
|
-
|
32
|
+
# find a token in the NCC node that has the same lineage as this token:
|
33
|
+
# - the NCC token will be a direct descendant of the divergent, therefore
|
34
|
+
# - one of this token's ancestors will be a duplicate of that token
|
35
|
+
# TODO: this should be more resilient, but child token creation does not allow for much else at the moment
|
36
|
+
ncc.tokens.find { |t| token.ancestors.any? { |ancestor| ancestor.duplicate?(t) } }
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|