mort666-wongi-engine 0.2.9

Sign up to get free protection for your applications and to get access to all the features.
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