ruleby 0.1
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.
- data/lib/core/atoms.rb +226 -0
- data/lib/core/engine.rb +211 -0
- data/lib/core/nodes.rb +684 -0
- data/lib/core/patterns.rb +217 -0
- data/lib/core/utils.rb +390 -0
- data/lib/rulebook.rb +205 -0
- data/lib/ruleby.rb +29 -0
- metadata +51 -0
data/lib/rulebook.rb
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
require 'ruleby'
|
2
|
+
|
3
|
+
class Rulebook
|
4
|
+
include Ruleby
|
5
|
+
def initialize(rete)
|
6
|
+
@rete = rete
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :rete
|
10
|
+
|
11
|
+
def rule(name, &block)
|
12
|
+
r = Core::Rule.new name
|
13
|
+
yield r if block_given?
|
14
|
+
@rete.assert_rule r
|
15
|
+
r
|
16
|
+
end
|
17
|
+
|
18
|
+
def action(&block)
|
19
|
+
return Core::Action.new(&block)
|
20
|
+
end
|
21
|
+
|
22
|
+
def pattern(&block)
|
23
|
+
pb = PatternBuilder.new
|
24
|
+
yield pb
|
25
|
+
return pb.condition
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
class PatternInternal
|
31
|
+
def initialize(tag, type)
|
32
|
+
@tag = tag
|
33
|
+
@type = type
|
34
|
+
@atoms = []
|
35
|
+
end
|
36
|
+
|
37
|
+
def atom(tag, name, references, &block)
|
38
|
+
if references
|
39
|
+
references = [references] unless references.kind_of?(Array)
|
40
|
+
return Core::ReferenceAtom.new(tag, name, references, &block)
|
41
|
+
else
|
42
|
+
return Core::PropertyAtom.new(tag, name, &block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
def method_missing(method_id, *args, &block)
|
46
|
+
if block_given?
|
47
|
+
with(method_id.to_s, *args, &block)
|
48
|
+
else
|
49
|
+
with(method_id.to_s, *args)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
def with(property, options={}, &block)
|
53
|
+
tag = options[:name]
|
54
|
+
tag = GeneratedTag.new if tag == options.default
|
55
|
+
if block_given?
|
56
|
+
@atoms.push atom(tag, property, options[:references], &block)
|
57
|
+
else
|
58
|
+
# QUESTION do we really want to do this? What if someone does:
|
59
|
+
# :equals => -1
|
60
|
+
# How do we handle a case where it is not a ReferenceAtom? should we
|
61
|
+
# have a :equals_ref key too?
|
62
|
+
# if options[:equals] != options.default
|
63
|
+
# @atoms.push(atom(tag, property, [options[:equals]]) do |p,a| p==a end)
|
64
|
+
# elsif options[:not_equals] != options.default
|
65
|
+
# @atoms.push(atom(tag, property, [options[:not_equals]]) do |p,a| p!=a end)
|
66
|
+
# else
|
67
|
+
@atoms.push(atom(tag, property, nil) do |p| true end)
|
68
|
+
# end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def pattern
|
73
|
+
@atoms = Array.new(1){@atoms} unless @atoms.kind_of?(Array)
|
74
|
+
return Core::ObjectPattern.new(@tag, @type, @atoms)
|
75
|
+
end
|
76
|
+
|
77
|
+
def not
|
78
|
+
@atoms = Array.new(1){@atoms} unless @atoms.kind_of?(Array)
|
79
|
+
return Core::NotPattern.new(@tag, @type, @atoms)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
class PatternInternal
|
83
|
+
public_instance_methods.each do |m|
|
84
|
+
a = [:not, :pattern, :with, :method_missing, :atom, :new, :public_instance_methods, :__send__, :__id__]
|
85
|
+
undef_method m.to_sym unless a.include? m.to_sym
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class PatternBuilder < Rulebook
|
90
|
+
|
91
|
+
attr_reader :condition
|
92
|
+
|
93
|
+
def initialize()
|
94
|
+
@condition = nil
|
95
|
+
end
|
96
|
+
|
97
|
+
def has(type, tag=GeneratedTag.new, &block)
|
98
|
+
pi = pattern_internal(tag, type)
|
99
|
+
yield pi if block_given?
|
100
|
+
op = pi.pattern
|
101
|
+
if(@condition)
|
102
|
+
pat = [@condition, op]
|
103
|
+
@condition = and_pattern(pat)
|
104
|
+
else
|
105
|
+
@condition = op
|
106
|
+
end
|
107
|
+
@condition
|
108
|
+
end
|
109
|
+
def and(operands)
|
110
|
+
if @condition
|
111
|
+
p = [@condition] + operands
|
112
|
+
@condition = and_pattern(p)
|
113
|
+
else
|
114
|
+
@condition = and_pattern(operands)
|
115
|
+
end
|
116
|
+
@condition
|
117
|
+
end
|
118
|
+
|
119
|
+
def or(operands)
|
120
|
+
if(@condition)
|
121
|
+
p = [@condition] + operands
|
122
|
+
@condition = or_pattern(p)
|
123
|
+
else
|
124
|
+
@condition = or_pattern(operands)
|
125
|
+
end
|
126
|
+
@condition
|
127
|
+
end
|
128
|
+
|
129
|
+
def not(type, tag=GeneratedTag.new, &block)
|
130
|
+
pi = pattern_internal(tag, type)
|
131
|
+
yield pi if block_given?
|
132
|
+
n = pi.not
|
133
|
+
if(@condition)
|
134
|
+
p = [@condition, n]
|
135
|
+
@condition = and_pattern(p)
|
136
|
+
else
|
137
|
+
@condition = n
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
def pattern_internal(tag, type)
|
143
|
+
return PatternInternal.new(tag, type)
|
144
|
+
end
|
145
|
+
|
146
|
+
def or_pattern(operands)
|
147
|
+
# TODO raise exception if referenceAtoms from the right do not
|
148
|
+
# have the values they referenece in the left
|
149
|
+
# TODO raise exception if there are repeated tags?
|
150
|
+
left = nil
|
151
|
+
operands.each do |operand|
|
152
|
+
if left.nil?
|
153
|
+
left = operand
|
154
|
+
else
|
155
|
+
right = operand
|
156
|
+
left = Core::OrPattern.new(left, right)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
left
|
160
|
+
end
|
161
|
+
|
162
|
+
def and_pattern(operands)
|
163
|
+
# TODO raise exception if referenceAtoms from the right do not
|
164
|
+
# have the values they referenece in the left
|
165
|
+
# TODO raise exception if there are repeated tags?
|
166
|
+
left = nil
|
167
|
+
operands.each do |operand|
|
168
|
+
if left.nil?
|
169
|
+
left = operand
|
170
|
+
else
|
171
|
+
right = operand
|
172
|
+
left = Core::AndPattern.new(left, right)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
left
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
class GeneratedTag
|
180
|
+
|
181
|
+
# this counter is incremented for each UniqueTag created, and is
|
182
|
+
# appended to the end of the unique_seed in order to create a
|
183
|
+
# string that is unique for each instance of this class.
|
184
|
+
@@tag_counter = 0
|
185
|
+
|
186
|
+
# every generated tag will be prefixed with this string
|
187
|
+
@@unique_seed = 'unique_seed'
|
188
|
+
|
189
|
+
def initialize()
|
190
|
+
@@tag_counter += 1
|
191
|
+
@tag = @@unique_seed + @@tag_counter.to_s
|
192
|
+
end
|
193
|
+
|
194
|
+
attr_reader:tag_counter
|
195
|
+
attr_reader:unique_seed
|
196
|
+
attr_reader:tag
|
197
|
+
|
198
|
+
def ==(ut)
|
199
|
+
return ut && ut.kind_of?(GeneratedTag) && @tag == ut.tag
|
200
|
+
end
|
201
|
+
|
202
|
+
def to_s
|
203
|
+
return @tag.to_s
|
204
|
+
end
|
205
|
+
end
|
data/lib/ruleby.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'core/engine'
|
2
|
+
module Ruleby
|
3
|
+
#helper classes for using ruleby go here
|
4
|
+
def engine(name, &block)
|
5
|
+
e = Core::Engine.new
|
6
|
+
yield e if block_given?
|
7
|
+
return e
|
8
|
+
end
|
9
|
+
def assert(rete,object,&block)
|
10
|
+
fact(rete,object,:plus,&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def retract(rete,object,&block)
|
14
|
+
fact(rete,object,:minus,&block)
|
15
|
+
end
|
16
|
+
|
17
|
+
def modify(rete,object,&block)
|
18
|
+
retract(rete,object,&block)
|
19
|
+
assert(rete,object,&block)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def fact(rete, object, sign=:plus, &block)
|
24
|
+
f = Core::Fact.new object, sign
|
25
|
+
yield f if block_given?
|
26
|
+
rete.assert_fact f
|
27
|
+
f
|
28
|
+
end
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11
|
3
|
+
specification_version: 1
|
4
|
+
name: ruleby
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: "0.1"
|
7
|
+
date: 2007-04-29 00:00:00 -05:00
|
8
|
+
summary: the Rule Engine for Ruby
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: matt@ruleby.org
|
12
|
+
homepage: http://www.ruleby.org
|
13
|
+
rubyforge_project:
|
14
|
+
description: ruleby is the Rule Engine for Ruby
|
15
|
+
autorequire: ruleby
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: false
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.8.4
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
authors:
|
29
|
+
- Joe Kutner, Matt Smith
|
30
|
+
files:
|
31
|
+
- lib/rulebook.rb
|
32
|
+
- lib/ruleby.rb
|
33
|
+
- lib/core/atoms.rb
|
34
|
+
- lib/core/engine.rb
|
35
|
+
- lib/core/nodes.rb
|
36
|
+
- lib/core/patterns.rb
|
37
|
+
- lib/core/utils.rb
|
38
|
+
test_files: []
|
39
|
+
|
40
|
+
rdoc_options: []
|
41
|
+
|
42
|
+
extra_rdoc_files: []
|
43
|
+
|
44
|
+
executables: []
|
45
|
+
|
46
|
+
extensions: []
|
47
|
+
|
48
|
+
requirements: []
|
49
|
+
|
50
|
+
dependencies: []
|
51
|
+
|