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,63 @@
1
+ module Wongi::Engine
2
+
3
+ module CoreExt
4
+
5
+ module ClassMethods
6
+
7
+ def attr_predicate *names
8
+
9
+ names_hash = names.inject( {} ) do |hash, element|
10
+ if Hash === element
11
+ hash.merge element
12
+ else
13
+ hash[element] = false
14
+ hash
15
+ end
16
+ end
17
+
18
+ names_hash.each do |name, def_value|
19
+
20
+ varname = "@#{name}".to_sym
21
+ predname = "#{name}?".to_sym
22
+ setname = "#{name}=".to_sym
23
+ exclname = "#{name}!".to_sym
24
+ noexclname = "no_#{name}!".to_sym
25
+
26
+ define_method predname do
27
+ if instance_variable_defined?( varname )
28
+ instance_variable_get( varname )
29
+ else
30
+ def_value
31
+ end
32
+ end
33
+
34
+ define_method setname do |newvalue|
35
+ instance_variable_set( varname, newvalue == true )
36
+ end
37
+
38
+ define_method exclname do
39
+ instance_variable_set( varname, true )
40
+ end
41
+
42
+ define_method noexclname do
43
+ instance_variable_set( varname, false )
44
+ end
45
+
46
+ end
47
+ end
48
+
49
+ def abstract name
50
+ define_method name do |*args|
51
+ raise NoMethodError.new "#{name} is not implemented for #{self.class.name}", name
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ def self.included mod
58
+ mod.extend ClassMethods
59
+ end
60
+
61
+ end
62
+
63
+ end
@@ -0,0 +1,144 @@
1
+ module Wongi::Engine
2
+ class DataOverlay
3
+
4
+ attr_reader :rete
5
+ attr_reader :parent
6
+
7
+ def initialize(rete, parent = nil)
8
+ @rete = rete
9
+ @parent = parent
10
+ @raw_wmes = Hash.new { |h, k| h[k] = [] }
11
+ @raw_tokens = Hash.new { |h, k| h[k] = [] }
12
+ rete.add_overlay(self)
13
+ end
14
+
15
+ def new_child
16
+ DataOverlay.new(rete, self)
17
+ end
18
+
19
+ def with_child
20
+ return unless block_given?
21
+ new_child.tap do |overlay|
22
+ begin
23
+ result = yield overlay
24
+ ensure
25
+ overlay.dispose
26
+ end
27
+ result
28
+ end
29
+ end
30
+
31
+ def ancestor?(other)
32
+ return false if parent.nil?
33
+ return true if parent == other
34
+ parent.ancestor?(other)
35
+ end
36
+
37
+ def dispose
38
+ return if self == rete.default_overlay
39
+ rete.remove_overlay(self)
40
+ @raw_tokens.values.each do |tokens|
41
+ tokens.each(&:dispose!)
42
+ end
43
+ @raw_tokens.clear
44
+ end
45
+
46
+ def <<(thing)
47
+ case thing
48
+ when Array
49
+ assert WME.new(*thing).tap { |wme| wme.overlay = self }
50
+ when WME
51
+ assert(thing)
52
+ else
53
+ raise Error, "overlays can only accept data"
54
+ end
55
+ end
56
+
57
+ def assert wme
58
+ @next_cascade ||= []
59
+ @next_cascade << [:assert, wme]
60
+ if @current_cascade.nil?
61
+ @current_cascade = @next_cascade
62
+ @next_cascade = nil
63
+ process_cascade
64
+ end
65
+ end
66
+
67
+ def retract wme, options = { }
68
+ if wme.is_a? Array
69
+ wme = WME.new(*wme)
70
+ end
71
+ @next_cascade ||= []
72
+ @next_cascade << [:retract, wme, options]
73
+ if @current_cascade.nil?
74
+ @current_cascade = @next_cascade
75
+ @next_cascade = nil
76
+ process_cascade
77
+ end
78
+ end
79
+
80
+ def process_cascade
81
+ while @current_cascade
82
+ @current_cascade.each do |(operation, wme, options)|
83
+ case operation
84
+ when :assert
85
+ wme.overlay = self
86
+ rete.real_assert(wme)
87
+ when :retract
88
+ rete.real_retract(wme, options)
89
+ wme.overlay = nil
90
+ end
91
+ end
92
+ @current_cascade = @next_cascade
93
+ @next_cascade = nil
94
+ end
95
+ end
96
+
97
+ def highest(other)
98
+ return self if self == other
99
+ return self if other.nil?
100
+ return self if ancestor?(other)
101
+ return other if other.ancestor?(self)
102
+ nil # unrelated lineages
103
+ end
104
+
105
+ # TODO: this is inconsistent.
106
+ # A WME retracted in-flight will be visible in active enumerators
107
+ # but a token will not.
108
+ # But this is how it works.
109
+
110
+ def wmes(alpha)
111
+ DuplicatingEnumerator.new(raw_wmes(alpha))
112
+ end
113
+
114
+ def tokens(beta)
115
+ DeleteSafeEnumerator.new(raw_tokens(beta))
116
+ end
117
+
118
+ def add_wme(wme, alpha)
119
+ wmes = raw_wmes(alpha)
120
+ wmes << wme unless wmes.include?(wme)
121
+ end
122
+
123
+ def remove_wme(wme, alpha)
124
+ raw_wmes(alpha).delete(wme)
125
+ end
126
+
127
+ def add_token(token, beta)
128
+ tokens = raw_tokens(beta)
129
+ tokens << token unless tokens.include?(token)
130
+ end
131
+
132
+ def remove_token(token, beta)
133
+ raw_tokens(beta).delete(token)
134
+ end
135
+
136
+ def raw_wmes(alpha)
137
+ @raw_wmes[alpha.object_id]
138
+ end
139
+
140
+ def raw_tokens(beta)
141
+ @raw_tokens[beta.object_id]
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,132 @@
1
+ module Wongi::Engine
2
+ module DSL
3
+ extend self
4
+
5
+ def ruleset name = nil, &definition
6
+ rs = Ruleset.new
7
+ if ! name.nil?
8
+ rs.name name
9
+ end
10
+ rs.instance_eval &definition if block_given?
11
+ rs
12
+ end
13
+
14
+ def rule name = nil, &definition
15
+ r = Rule.new name
16
+ r.instance_eval &definition
17
+ r
18
+ end
19
+
20
+ def query name, &definition
21
+ q = Query.new name
22
+ q.instance_eval &definition
23
+ q
24
+ end
25
+
26
+ def dsl &definition
27
+ Builder.new.build &definition
28
+ end
29
+ end
30
+
31
+ end
32
+
33
+ require 'wongi-engine/dsl/generated'
34
+ require 'wongi-engine/dsl/builder'
35
+ require 'wongi-engine/dsl/clause/generic'
36
+ require 'wongi-engine/dsl/clause/fact'
37
+ require 'wongi-engine/dsl/clause/assign'
38
+ require 'wongi-engine/dsl/clause/gen'
39
+ require 'wongi-engine/dsl/action/base'
40
+ require 'wongi-engine/dsl/rule'
41
+ require 'wongi-engine/dsl/ncc_subrule'
42
+ require 'wongi-engine/dsl/any_rule'
43
+ require 'wongi-engine/dsl/query'
44
+ require 'wongi-engine/dsl/assuming'
45
+ require 'wongi-engine/dsl/action/simple_action'
46
+ require 'wongi-engine/dsl/action/statement_generator'
47
+ require 'wongi-engine/dsl/action/simple_collector'
48
+ require 'wongi-engine/dsl/action/trace_action'
49
+ require 'wongi-engine/dsl/action/error_generator'
50
+
51
+ module Wongi::Engine::DSL
52
+ dsl {
53
+ section :forall
54
+
55
+ clause :has, :fact
56
+ accept Clause::Has
57
+
58
+ clause :missing, :neg
59
+ accept Clause::Neg
60
+
61
+ clause :none, :ncc
62
+ accept NccSubrule
63
+
64
+ clause :any
65
+ accept AnyRule
66
+
67
+ clause :maybe, :optional
68
+ accept Clause::Opt
69
+
70
+ clause :same, :eq, :equal
71
+ accept Wongi::Engine::EqualityTest
72
+
73
+ clause :diff, :ne
74
+ accept Wongi::Engine::InequalityTest
75
+
76
+ clause :less
77
+ accept Wongi::Engine::LessThanTest
78
+
79
+ clause :greater
80
+ accept Wongi::Engine::GreaterThanTest
81
+
82
+ clause :assert, :dynamic
83
+ accept Wongi::Engine::AssertingTest
84
+
85
+ clause :assign, :introduce
86
+ accept Clause::Assign
87
+
88
+ clause :asserted, :added
89
+ body { |s, p, o|
90
+ has s, p, o, time: 0
91
+ missing s, p, o, time: -1
92
+ }
93
+
94
+ clause :retracted, :removed
95
+ body { |s, p, o|
96
+ has s, p, o, time: -1
97
+ missing s, p, o, time: 0
98
+ }
99
+
100
+ clause :kept, :still_has
101
+ body { |s, p, o|
102
+ has s, p, o, time: -1
103
+ has s, p, o, time: 0
104
+ }
105
+
106
+ clause :kept_missing, :still_missing
107
+ body { |s, p, o|
108
+ missing s, p, o, time: -1
109
+ missing s, p, o, time: 0
110
+ }
111
+
112
+ clause :assuming
113
+ accept Wongi::Engine::AssumingClause
114
+
115
+ section :make
116
+
117
+ clause :gen
118
+ accept Clause::Gen
119
+
120
+ clause :trace
121
+ action Action::TraceAction
122
+
123
+ clause :error
124
+ action Action::ErrorGenerator
125
+
126
+ clause :collect
127
+ action Action::SimpleCollector
128
+
129
+ clause :action
130
+ action Action::SimpleAction
131
+ }
132
+ end
@@ -0,0 +1,11 @@
1
+ module Wongi::Engine
2
+ module DSL::Action
3
+ class Base
4
+ include CoreExt
5
+ attr_accessor :production
6
+ attr_accessor :rule
7
+ attr_accessor :name
8
+ attr_accessor :rete
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,31 @@
1
+ module Wongi::Engine
2
+ module DSL::Action
3
+ class ErrorGenerator < Base
4
+
5
+ def initialize message = nil, &messenger
6
+ @message, @messenger = message, messenger
7
+ end
8
+
9
+ def rete=(*)
10
+ super
11
+ rete.add_collector self, :error
12
+ end
13
+
14
+ def errors
15
+ production.tokens.map do |token|
16
+ message = if @messenger
17
+ @messenger.call token.assignments
18
+ else
19
+ @message
20
+ end
21
+ ReteError.new token, message, literate?
22
+ end
23
+ end
24
+
25
+ def literate?
26
+ not @messenger.nil?
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,60 @@
1
+ module Wongi::Engine
2
+ module DSL::Action
3
+ class SimpleAction < Base
4
+ def initialize action = nil, *args, &block
5
+ @args = args
6
+ case action
7
+ when Class
8
+ @action = @deaction = @reaction = action.new *args, &block
9
+ when Hash
10
+ @action = instance_or_proc action[:activate]
11
+ @deaction = instance_or_proc action[:deactivate]
12
+ @reaction = instance_or_proc action[:reactivate]
13
+ end
14
+ @action ||= block
15
+ end
16
+
17
+ def execute token
18
+ return unless @action
19
+ if @action.is_a?( Proc ) || @action.respond_to?( :to_proc )
20
+ rete.instance_exec token, &@action
21
+ elsif @action.respond_to? :call
22
+ @action.call token
23
+ elsif @action.respond_to? :execute
24
+ @action.execute token
25
+ end
26
+ end
27
+
28
+ def deexecute token
29
+ return unless @deaction
30
+ if @deaction.is_a?( Proc ) || @deaction.respond_to?( :to_proc )
31
+ rete.instance_exec token, &@deaction
32
+ elsif @deaction.respond_to? :call
33
+ @deaction.call token
34
+ elsif @deaction.respond_to? :deexecute
35
+ @deaction.execute token
36
+ end
37
+ end
38
+
39
+ def reexecute token, newtoken
40
+ return unless @reaction
41
+ if @reaction.is_a?( Proc ) || @reaction.respond_to?( :to_proc )
42
+ rete.instance_exec token, newtoken, &@reaction
43
+ elsif @reaction.respond_to? :call
44
+ @reaction.call token, newtoken
45
+ elsif @reaction.respond_to? :reexecute
46
+ @reaction.execute token, newtoken
47
+ end
48
+ end
49
+
50
+ def instance_or_proc thing
51
+ case thing
52
+ when Class
53
+ thing.new
54
+ when Proc
55
+ thing
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,52 @@
1
+ module Wongi::Engine
2
+ module DSL::Action
3
+ class SimpleCollector < Base
4
+
5
+ def self.collector
6
+ Class.new self
7
+ end
8
+
9
+ def initialize variable, name = nil
10
+ @variable = variable
11
+ @name = name if name
12
+ #(class << self; self; end).instance_eval do
13
+ # define_method method do
14
+ # collect variable
15
+ # end
16
+ # alias_method method, :default_collect
17
+ # end
18
+ end
19
+
20
+ def default_collect
21
+ collect @variable
22
+ end
23
+
24
+ def name= n
25
+ @name = n unless @name
26
+ end
27
+
28
+ def rete= rete
29
+ rete.add_collector self, name
30
+ end
31
+
32
+ def collect var
33
+ production.tokens.map { |token| token[var] }
34
+ end
35
+
36
+ end
37
+
38
+ class GenericCollectClause
39
+
40
+ def initialize name, variable
41
+
42
+ end
43
+
44
+ def import_into rete
45
+ collector = SimpleCollector.new @variable
46
+
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+ end