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,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