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,34 @@
1
+ module Wongi::Engine
2
+
3
+ class WMEMatchData
4
+
5
+ attr_reader :assignments
6
+
7
+ def initialize assignments = { }, match = false
8
+ @assignments = assignments
9
+ @match = match
10
+ end
11
+
12
+ def [] key
13
+ assignments[key]
14
+ end
15
+
16
+ def []= key, value
17
+ assignments[key] = value
18
+ end
19
+
20
+ def match?
21
+ @match
22
+ end
23
+
24
+ def match!
25
+ @match = true
26
+ end
27
+
28
+ def & other
29
+ WMEMatchData.new( assignments.merge( other.assignments ), match? && other.match? )
30
+ end
31
+
32
+ end
33
+
34
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Wongi::Engine::BetaNode do
4
+
5
+ include Wongi::Engine::DSL
6
+
7
+ let( :engine ) { Wongi::Engine.create }
8
+
9
+ describe '#tokens' do
10
+
11
+ it 'should be enumerable' do
12
+
13
+ production = engine << rule {
14
+ forall {
15
+ has :x, :y, :Z
16
+ }
17
+ }
18
+
19
+ engine << [:x, :y, 1]
20
+ engine << [:x, :y, 2]
21
+ engine << [:x, :y, 3]
22
+ zs = production.tokens.map { |token| token[:Z] }
23
+ expect( zs ).to be == [1, 2, 3]
24
+
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,141 @@
1
+ require 'spec_helper'
2
+
3
+ describe "issue 4" do
4
+
5
+ it "should correctly retract pre-added items from within a rule" do
6
+
7
+ engine = Wongi::Engine.create
8
+
9
+ 10.times{ |i| engine << [i, :is_number, true] }
10
+
11
+ engine.rule 'segregate' do
12
+ forall {
13
+ has :Number, :is_number, true
14
+ }
15
+ make {
16
+ action { |token|
17
+ number = token[:Number]
18
+ engine << [number, :is_even, true]
19
+ engine.retract [number, :is_number, true]
20
+ }
21
+ }
22
+ end
23
+
24
+ numbers = engine.select :_, :is_number, true
25
+ evens = engine.select :_, :is_even, true
26
+
27
+ expect(numbers).to be_empty
28
+ expect(evens.length).to eq(10)
29
+
30
+ end
31
+
32
+ it "should correctly retract post-added items from within a rule" do
33
+
34
+ engine = Wongi::Engine.create
35
+
36
+ engine.rule 'segregate' do
37
+ forall {
38
+ has :Number, :is_number, true
39
+ }
40
+ make {
41
+ action { |token|
42
+ number = token[:Number]
43
+ engine << [number, :is_even, true]
44
+ engine.retract [number, :is_number, true]
45
+ }
46
+ }
47
+ end
48
+
49
+ 10.times{ |i| engine << [i, :is_number, true] }
50
+
51
+ numbers = engine.select :_, :is_number, true
52
+ evens = engine.select :_, :is_even, true
53
+
54
+ expect(numbers).to be_empty
55
+ expect(evens.length).to eq(10)
56
+
57
+ end
58
+
59
+ # cascaded processing affects this
60
+ it "should not retract later items from within a rule" do
61
+
62
+ engine = Wongi::Engine.create
63
+
64
+ 10.times{ |i| engine << [i, :is_number, true] }
65
+
66
+ engine.rule 'segregate' do
67
+ forall {
68
+ has :Number, :is_number, true
69
+ }
70
+ make {
71
+ action { |token|
72
+ number = token[:Number]
73
+ if number % 2 == 0
74
+ engine << [number, :is_even, true]
75
+ engine.retract [number, :is_number, true]
76
+ engine.retract [number + 1, :is_number, true]
77
+ else
78
+ # this is not reached without cascades
79
+ engine << [number, :is_odd, true]
80
+ end
81
+ }
82
+ }
83
+ end
84
+
85
+ numbers = engine.select :_, :is_number, true
86
+ evens = engine.select :_, :is_even, true
87
+ odds = engine.select :_, :is_odd, true
88
+
89
+ expect(numbers).to be_empty
90
+ expect(evens).to have(5).items
91
+ expect(odds).to have(5).items
92
+
93
+ end
94
+
95
+
96
+ it "should not lose track when another rule affects a set" do
97
+ engine = Wongi::Engine.create
98
+
99
+ 10.times{ |i| engine << [i, :is_number, true] }
100
+
101
+ engine.rule 'find odds' do
102
+ forall {
103
+ has :Number, :is_number, true
104
+ has :Number, :probably_odd, true
105
+ }
106
+ make {
107
+ action { |token|
108
+ number = token[:Number]
109
+ if number % 2 != 0
110
+ engine << [number, :is_odd, true]
111
+ engine.retract [number, :is_number, true]
112
+ end
113
+ }
114
+ }
115
+ end
116
+ engine.rule 'find evens' do
117
+ forall {
118
+ has :Number, :is_number, true
119
+ neg :Number, :is_odd, true
120
+ }
121
+ make {
122
+ action { |token|
123
+ number = token[:Number]
124
+ if number % 2 == 0
125
+ engine << [number, :is_even, true]
126
+ else
127
+ engine << [number, :probably_odd, true]
128
+ end
129
+ }
130
+ }
131
+ end
132
+
133
+ numbers = engine.select :_, :is_number, true
134
+ evens = engine.select :_, :is_even, true
135
+ odds = engine.select :_, :is_odd, true
136
+
137
+ # numbers.should be_empty
138
+ expect(evens.length).to eq(5)
139
+ expect(odds.length).to eq(5)
140
+ end
141
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Wongi::Engine::Network do
4
+
5
+ it 'should expose compiled productions' do
6
+
7
+ ds = Wongi::Engine::Network.new
8
+
9
+ ds << rule('test-rule') {
10
+ forall {
11
+ has 1, 2, 3
12
+ }
13
+ }
14
+
15
+ production = ds.productions['test-rule']
16
+ expect(production).not_to be_nil
17
+
18
+ expect(production).to be_empty
19
+
20
+ ds << [1, 2, 3]
21
+
22
+ expect(production.size).to eq(1)
23
+ expect( production.size ).to be == 1
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'DSL' do
4
+
5
+ it 'should register rulesets globally' do
6
+
7
+ end
8
+
9
+ end
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+
3
+ describe "ASSERT test" do
4
+
5
+ before :each do
6
+ @engine = Wongi::Engine.create
7
+ end
8
+
9
+ def engine
10
+ @engine
11
+ end
12
+
13
+ def production
14
+ @production
15
+ end
16
+
17
+ def test_rule &block
18
+ @production = ( engine << rule( 'test-rule', &block ) )
19
+ end
20
+
21
+ it "should pass with a constant 'true'" do
22
+
23
+ test_rule {
24
+ forall {
25
+ assert { |token|
26
+ true
27
+ }
28
+ }
29
+ }
30
+
31
+ expect(production).to have(1).token
32
+
33
+ end
34
+
35
+ it "should fail with a constant 'false'" do
36
+
37
+ test_rule {
38
+ forall {
39
+ assert { |token|
40
+ false
41
+ }
42
+ }
43
+ }
44
+
45
+ expect(production).to have(0).tokens
46
+
47
+ end
48
+
49
+ it "should use the token with no arguments" do
50
+
51
+ test_rule {
52
+ forall {
53
+ has :X, "is", :Y
54
+ assert { |token|
55
+ token[:X] == "resistance"
56
+ }
57
+ }
58
+ }
59
+
60
+ engine << ["resistance", "is", "futile"]
61
+
62
+ expect(production).to have(1).token
63
+ expect(production.tokens.first[:X]).to eq("resistance")
64
+
65
+ end
66
+
67
+ it "should be retractable" do
68
+
69
+ test_rule {
70
+ forall {
71
+ has :X, "is", :Y
72
+ assert { |token|
73
+ token[:X] == "resistance"
74
+ }
75
+ }
76
+ }
77
+
78
+ engine << ["resistance", "is", "futile"]
79
+ engine.retract ["resistance", "is", "futile"]
80
+ expect(production).to have(0).tokens
81
+
82
+ end
83
+
84
+ it "should use individual variables with arguments" do
85
+
86
+ test_rule {
87
+ forall {
88
+ has :X, "is", :Y
89
+ assert :X, :Y do |x, y|
90
+ y == "futile"
91
+ end
92
+ }
93
+ }
94
+
95
+ engine << ["resistance", "is", "futile"]
96
+
97
+ expect(production).to have(1).token
98
+ expect(production.tokens.first[:X]).to eq("resistance")
99
+
100
+ end
101
+
102
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe "LESS test" do
4
+
5
+ before :each do
6
+ @engine = Wongi::Engine.create
7
+ end
8
+
9
+ def engine
10
+ @engine
11
+ end
12
+
13
+ def production
14
+ @production
15
+ end
16
+
17
+ def test_rule &block
18
+ @production = ( engine << rule( 'test-rule', &block ) )
19
+ end
20
+
21
+ it "should interact with optional node correctly" do
22
+
23
+ # before the fix, filters would try to piggy-back on optional templates
24
+
25
+ test_rule {
26
+ forall {
27
+ maybe "Z", "Z", "Z"
28
+ less 6,4 # this should fail
29
+ }
30
+
31
+ make {
32
+ gen ".", ".", "."
33
+ }
34
+ }
35
+
36
+ engine << ["A", "B", "C"]
37
+
38
+ expect(@production.size).to eq(0)
39
+ end
40
+
41
+ end
@@ -0,0 +1,116 @@
1
+ require 'spec_helper'
2
+
3
+ describe Wongi::Engine::DSL::Action::StatementGenerator do
4
+
5
+ let( :engine ) { Wongi::Engine.create }
6
+
7
+ let( :transitive_rule ) {
8
+ rule {
9
+ forall {
10
+ has :P, :transitive, true
11
+ has :X, :P, :Y
12
+ has :Y, :P, :Z
13
+ }
14
+ make {
15
+ gen :X, :P, :Z
16
+ }
17
+ }
18
+ }
19
+
20
+ let( :production ) { engine << transitive_rule }
21
+
22
+ shared_examples 'generation' do
23
+
24
+ it 'should generate facts' do
25
+ engine << %w( Alice relative Bob )
26
+ engine << %w( Bob relative Dwight )
27
+
28
+ expect( production ).to have(1).token
29
+ expect( engine.find *%w( Alice relative Dwight ) ).not_to be_nil
30
+ end
31
+
32
+ it 'should retrct generated facts' do
33
+ engine << %w( Alice relative Bob )
34
+ engine << %w( Bob relative Dwight )
35
+ engine.retract %w( Bob relative Dwight )
36
+
37
+ expect( production ).to have(0).tokens
38
+ expect( engine.find *%w( Alice relative Dwight ) ).to be_nil
39
+ end
40
+
41
+ context 'transitive diamond' do
42
+
43
+ before :each do
44
+ engine << %w( Alice relative Bob )
45
+ engine << %w( Bob relative Dwight )
46
+ engine << %w( Alice relative Claire )
47
+ engine << %w( Claire relative Dwight )
48
+ end
49
+
50
+ it 'should be created' do
51
+ expect( production ).to have(2).tokens
52
+ expect( engine.find *%w( Alice relative Dwight ) ).not_to be_nil
53
+ end
54
+
55
+ it 'should remain after a single retraction' do
56
+ engine.retract %w( Claire relative Dwight )
57
+
58
+ expect( production ).to have(1).token
59
+ expect( engine.find *%w( Alice relative Dwight ) ).not_to be_nil
60
+ end
61
+
62
+ it 'should be destroyed after both retractions' do
63
+ engine.retract %w( Claire relative Dwight )
64
+ engine.retract %w( Alice relative Bob )
65
+
66
+ expect( production ).to have(0).tokens
67
+ expect( engine.find *%w( Alice relative Dwight ) ).to be_nil
68
+ end
69
+
70
+ end
71
+
72
+ end
73
+
74
+ context "pre-asserted", :pre do
75
+
76
+ before :each do
77
+ engine << [ "relative", :transitive, true ]
78
+ end
79
+
80
+ it_behaves_like 'generation'
81
+
82
+ end
83
+
84
+ context "post-asserted", :post do
85
+
86
+ before :each do
87
+ production
88
+ engine << [ "relative", :transitive, true ]
89
+ end
90
+
91
+ it_behaves_like 'generation'
92
+
93
+ it 'should not retract generated facts marked as manual', :wip do
94
+ engine << %w( Alice relative Bob )
95
+ engine << %w( Bob relative Dwight )
96
+ engine << %w( Alice relative Dwight )
97
+ engine.retract %w( Alice relative Bob )
98
+
99
+ expect( production ).to have(0).tokens
100
+ expect( engine.find *%w( Alice relative Dwight ) ).not_to be_nil
101
+ end
102
+
103
+ it 'should retract generated facts unmarked as manual', :wip do
104
+ engine << %w( Alice relative Bob )
105
+ engine << %w( Bob relative Dwight )
106
+ engine << %w( Alice relative Dwight )
107
+ engine.retract %w( Alice relative Dwight )
108
+ engine.retract %w( Alice relative Bob )
109
+
110
+ expect( production ).to have(0).tokens
111
+ expect( engine.find *%w( Alice relative Dwight ) ).to be_nil
112
+ end
113
+
114
+ end
115
+
116
+ end