ruleby 0.2 → 0.3

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.
@@ -1,285 +1,102 @@
1
- require 'ruleby'
2
-
3
- class Rulebook
4
- include Ruleby
5
- def initialize(engine)
6
- @engine = engine
7
- end
8
-
9
- attr_reader :engine
10
-
11
- def rule(name, &block)
12
- r = Core::Rule.new name
13
- yield r if block_given?
14
- @engine.assert_rule r
15
- r
16
- end
17
-
18
- def action(&block)
19
- return Core::Action.new(&block)
20
- end
21
-
22
- end
1
+ # This file is part of the Ruleby project (http://ruleby.org)
2
+ #
3
+ # This application is free software; you can redistribute it and/or
4
+ # modify it under the terms of the Ruby license defined in the
5
+ # LICENSE.txt file.
6
+ #
7
+ # Copyright (c) 2007 Joe Kutner and Matt Smith. All rights reserved.
8
+ #
9
+ # * Authors: Matt Smith, Joe Kutner
10
+ #
23
11
 
24
- class WhenBuilder < Rulebook
25
- def initialize()
26
- @pattern_hash = Hash.new
27
- @pattern_keys = []
28
- end
29
-
30
- def method_missing(method_id, *args, &block)
31
- method = method_id.to_sym
32
- wi = nil
33
- if @pattern_hash.key? method
34
- wi = @pattern_hash[method]
35
- elsif :not == method
36
- @pattern_keys.push method
37
- return self
38
- else
39
- wi = WhenInternal.new method, args[0]
40
- @pattern_hash[method] = wi
41
- @pattern_keys.push method
42
- end
43
- return wi
44
- end
45
- def pattern
46
- operands = []
47
- nt = false
48
- @pattern_keys.each do |key|
49
- if :not != key
50
- wi = @pattern_hash[key]
51
- tag = wi.tag
52
- type = wi.type
53
- atoms = wi.to_atoms
54
- p = nil
55
- if nt
56
- p = Core::NotPattern.new(tag, type, atoms)
57
- nt = false
58
- else
59
- p = Core::ObjectPattern.new(tag, type, atoms)
60
- end
61
- operands = operands + [p]
62
- else
63
- nt = true
64
- end
65
- end
66
- return and_pattern(operands)
67
- end
68
- end
12
+ require 'ruleby'
13
+ require 'dsl/ferrari'
14
+ require 'dsl/letigre'
15
+ require 'dsl/steel'
69
16
 
70
- class WhenInternal
71
- public_instance_methods.each do |m|
72
- a = [:method_missing, :new, :public_instance_methods, :__send__, :__id__]
73
- undef_method m.to_sym unless a.include? m.to_sym
74
- end
75
-
76
- attr_reader :tag, :type
77
- def initialize(tag, type)
78
- @tag = tag
79
- @type = type
80
- @builder = WhenPropertyBuilder.new self
81
- end
82
-
83
- def to_atoms
84
- atoms = []
85
- tags = [@tag]
86
- @builder.property_hash.each_value do |wp|
87
- tags.push wp.tag if wp.tag
88
- end
89
- @builder.property_keys.each do |key|
90
- wp = @builder.property_hash[key]
91
- atoms = atoms + [wp.to_atom(tags)]
17
+ module Ruleby
18
+ class Rulebook
19
+ include Ruleby
20
+ def initialize(engine)
21
+ @engine = engine
92
22
  end
93
- return atoms
94
- end
95
23
 
96
- def &
97
- return self
98
- end
24
+ attr_reader :engine
99
25
 
100
- def method_missing(method_id, *args, &block)
101
- m = method_id.to_s
102
- suffix = m.to_s[-1..-1]
103
- if suffix == '='
104
- new_m = m[0,m.size-1]
105
- if args[0].class == Array && args[0].size > 1 && args[0][1] == :%
106
- wp = @builder.create new_m do |x,y| x == y end
107
- wp.references args[0][0]
108
- return wp
109
- else
110
- wp = @builder.create new_m do |x| x == args[0] end
111
- return wp
26
+ def rule(*args, &block)
27
+ unless args.empty?
28
+ name = args[0].kind_of?(Symbol) ? args.shift : GeneratedTag.new
112
29
  end
113
- else
114
- wp = @builder.create(m, &block)
115
- if args.size > 0 && args[0]
116
- if block_given?
117
- wp.references args[0]
30
+
31
+ if args.empty?
32
+ # use steel DSL
33
+ r = Steel::RulebookHelper.new @engine
34
+ r.rule name, &block
35
+ else
36
+ i = args[0].kind_of?(Hash) ? 1 : 0
37
+ if args[i].kind_of? Array
38
+ # use ferrari DSL
39
+ r = Ferrari::RulebookHelper.new @engine
40
+ r.rule name, *args, &block
41
+ elsif args[i].kind_of? String
42
+ # use letigre DSL
43
+ r = LeTigre::RulebookHelper.new @engine
44
+ r.rule name, *args, &block
118
45
  else
119
- wp.tag = args[0]
46
+ raise 'Rule format not recognized.'
120
47
  end
121
48
  end
122
- return wp
123
- end
124
- end
125
- end
126
-
127
- class WhenPropertyBuilder
128
- attr_reader:property_hash
129
- attr_reader:property_keys
130
-
131
- def initialize(parent)
132
- @parent = parent
133
- @property_hash = Hash.new
134
- @property_keys = []
135
- end
136
-
137
- def create(method_id,&block)
138
- method = method_id.to_sym
139
- wp = nil
140
- if @property_hash.key? method
141
- wp = @property_hash[method]
142
- else
143
- wp = WhenProperty.new @parent, method do |p| true end
144
- @property_hash[method] = wp
145
- @property_keys.push method
146
49
  end
147
- if block_given?
148
- wp.block = block
149
- end
150
- return wp
151
- end
152
- end
153
-
154
- class WhenProperty
155
- attr_accessor :block
156
- def initialize(parent,name, &block)
157
- @tag = nil
158
- @name = name
159
- @references = nil
160
- @block = block
161
- @parent = parent
162
- end
163
- attr:tag,true
164
- attr:type,true
165
- attr:value,true
166
-
167
- def &
168
- return @parent
169
- end
170
-
171
- def bind(n)
172
- @tag = n
173
- end
174
-
175
- def not=(value,ref=nil)
176
- if ref && ref == :%
177
- raise 'Using \'not=\' for references is not yet supported'
178
- set_block do |x,y| x != y end
179
- references value
180
- else
181
- set_block do |s| s != value end
50
+
51
+ def m
52
+ Ruleby::Ferrari::MethodBuilder.new
182
53
  end
183
54
 
184
- end
185
- def set_block(&block)
186
- @block = block
187
- end
188
- private:set_block
189
-
190
- def references(refs)
191
- @references = refs
192
- end
193
-
194
- def to_atom(pattern_tags)
195
- unless @tag
196
- @tag = GeneratedTag.new
55
+ def method
56
+ m
197
57
  end
198
- if @references
199
- @references = [@references] unless @references.kind_of?(Array)
200
- i = includes_how_many(@references, pattern_tags)
201
- if i == 0
202
- return Core::ReferenceAtom.new(@tag, @name, @references, &@block)
203
- elsif i == @references.size
204
- return Core::SelfReferenceAtom.new(@tag, @name, @references, &@block)
205
- else
206
- raise 'Referencing self AND other patterns in the same atom is not yet supported'
207
- end
208
- else
209
- return Core::PropertyAtom.new(@tag, @name, &@block)
58
+
59
+ def b(variable_name)
60
+ Ruleby::Ferrari::BindingBuilder.new(variable_name)
210
61
  end
211
- end
212
-
213
- private
214
- def includes_how_many(list1, list2)
215
- i = 0
216
- list2.each do |a|
217
- i += 1 if list1.include?(a)
62
+
63
+ def binding(variable_name)
64
+ b
218
65
  end
219
- return i
220
- end
221
- end
222
-
223
-
224
-
225
- private
226
-
227
- def or_pattern(operands)
228
- # TODO raise exception if referenceAtoms from the right do not
229
- # have the values they referenece in the left
230
- # TODO raise exception if there are repeated tags?
231
- left = nil
232
- operands.each do |operand|
233
- if left.nil?
234
- left = operand
235
- else
236
- right = operand
237
- left = Core::OrPattern.new(left, right)
66
+
67
+ def c(&block)
68
+ return lambda(&block)
238
69
  end
239
- end
240
- left
241
- end
242
-
243
- def and_pattern(operands)
244
- # TODO raise exception if referenceAtoms from the right do not
245
- # have the values they referenece in the left
246
- # TODO raise exception if there are repeated tags?
247
- left = nil
248
- operands.each do |operand|
249
- if left.nil?
250
- left = operand
251
- else
252
- right = operand
253
- left = Core::AndPattern.new(left, right)
70
+
71
+ def condition(&block)
72
+ return lambda(&block)
254
73
  end
255
- end
256
- left
257
- end
258
-
259
- class GeneratedTag
260
-
261
- # this counter is incremented for each UniqueTag created, and is
262
- # appended to the end of the unique_seed in order to create a
263
- # string that is unique for each instance of this class.
264
- @@tag_counter = 0
265
-
266
- # every generated tag will be prefixed with this string
267
- @@unique_seed = 'unique_seed'
268
-
269
- def initialize()
270
- @@tag_counter += 1
271
- @tag = @@unique_seed + @@tag_counter.to_s
272
- end
74
+ end
273
75
 
274
- attr_reader:tag_counter
275
- attr_reader:unique_seed
276
- attr_reader:tag
277
-
278
- def ==(ut)
279
- return ut && ut.kind_of?(GeneratedTag) && @tag == ut.tag
280
- end
76
+ class GeneratedTag
77
+ # this counter is incremented for each UniqueTag created, and is
78
+ # appended to the end of the unique_seed in order to create a
79
+ # string that is unique for each instance of this class.
80
+ @@tag_counter = 0
81
+
82
+ # every generated tag will be prefixed with this string
83
+ @@unique_seed = 'unique_seed'
281
84
 
282
- def to_s
283
- return @tag.to_s
85
+ def initialize()
86
+ @@tag_counter += 1
87
+ @tag = @@unique_seed + @@tag_counter.to_s
88
+ end
89
+
90
+ attr_reader:tag_counter
91
+ attr_reader:unique_seed
92
+ attr_reader:tag
93
+
94
+ def ==(ut)
95
+ return ut && ut.kind_of?(GeneratedTag) && @tag == ut.tag
96
+ end
97
+
98
+ def to_s
99
+ return @tag.to_s
100
+ end
284
101
  end
285
- end
102
+ end
@@ -1,4 +1,17 @@
1
+ # This file is part of the Ruleby project (http://ruleby.org)
2
+ #
3
+ # This application is free software; you can redistribute it and/or
4
+ # modify it under the terms of the Ruby license defined in the
5
+ # LICENSE.txt file.
6
+ #
7
+ # Copyright (c) 2007 Joe Kutner and Matt Smith. All rights reserved.
8
+ #
9
+ # * Authors: Joe Kutner, Matt Smith
10
+ #
11
+
1
12
  require 'core/engine'
13
+ require 'rulebook'
14
+
2
15
  module Ruleby
3
16
  #helper classes for using ruleby go here
4
17
  def engine(name, &block)
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.3
2
+ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: ruleby
5
5
  version: !ruby/object:Gem::Version
6
- version: "0.2"
7
- date: 2007-07-10 00:00:00 -05:00
6
+ version: "0.3"
7
+ date: 2007-09-03 00:00:00 -05:00
8
8
  summary: the Rule Engine for Ruby
9
9
  require_paths:
10
10
  - lib
@@ -29,29 +29,31 @@ post_install_message:
29
29
  authors:
30
30
  - Joe Kutner, Matt Smith
31
31
  files:
32
- - ./benchmarks/50_joined_rules.rb
33
- - ./benchmarks/50_rules.rb
34
- - ./benchmarks/5_joined_rules.rb
35
- - ./benchmarks/5_rules.rb
36
- - ./benchmarks/miss_manners/data.rb
32
+ - ./lib/ruleby.rb
33
+ - ./lib/rulebook.rb
34
+ - ./lib/dsl/ferrari.rb
35
+ - ./lib/dsl/letigre.rb
36
+ - ./lib/dsl/steel.rb
37
+ - ./lib/core/patterns.rb
38
+ - ./lib/core/utils.rb
39
+ - ./lib/core/atoms.rb
40
+ - ./lib/core/engine.rb
41
+ - ./lib/core/nodes.rb
42
+ - ./benchmarks/model.rb
43
+ - ./benchmarks/joined_rules.rb
44
+ - ./benchmarks/basic_rules.rb
37
45
  - ./benchmarks/miss_manners/miss_manners.rb
38
46
  - ./benchmarks/miss_manners/model.rb
47
+ - ./benchmarks/miss_manners/data.rb
39
48
  - ./benchmarks/miss_manners/rules.rb
40
- - ./examples/example_diagnosis.rb
41
- - ./examples/example_hello.rb
42
- - ./examples/example_politician.rb
43
- - ./examples/example_ticket.rb
44
49
  - ./examples/fibonacci_example1.rb
45
50
  - ./examples/fibonacci_example2.rb
51
+ - ./examples/example_hello.rb
52
+ - ./examples/example_ticket.rb
46
53
  - ./examples/fibonacci_rulebook.rb
54
+ - ./examples/example_politician.rb
47
55
  - ./examples/test_self_reference.rb
48
- - ./lib/rulebook.rb
49
- - ./lib/ruleby.rb
50
- - ./lib/core/atoms.rb
51
- - ./lib/core/engine.rb
52
- - ./lib/core/nodes.rb
53
- - ./lib/core/patterns.rb
54
- - ./lib/core/utils.rb
56
+ - ./examples/example_diagnosis.rb
55
57
  test_files: []
56
58
 
57
59
  rdoc_options: []
@@ -1,78 +0,0 @@
1
- $LOAD_PATH << File.join(File.dirname(__FILE__), '../lib/')
2
- require 'ruleby'
3
- require 'rulebook'
4
-
5
- class Account
6
- def initialize(status, title, account_id)
7
- @status = status
8
- @title = title
9
- @account_id = account_id
10
- end
11
-
12
- attr :status, true
13
- attr :title, true
14
- attr :account_id, true
15
- end
16
-
17
- class Address
18
- def initialize(addr_id, city, state, zip)
19
- @addr_id = addr_id
20
- @city = city
21
- @state = state
22
- @zip = zip
23
- end
24
-
25
- attr :addr_id, true
26
- attr :city, true
27
- attr :state, true
28
- attr :zip, true
29
- end
30
-
31
- class TestRulebook < Rulebook
32
- def rules
33
- (0..50).each do |index|
34
- rule "Rule-#{index}" do |r|
35
- r.when do |has|
36
- has.a Account
37
- has.a.status = 'standard'
38
-
39
- has.addr Address
40
- has.addr.addr_id = "acc#{index}"
41
- has.addr.city = 'Foobar'
42
- has.addr.state = 'FB'
43
- has.addr.zip = '12345'
44
- end
45
-
46
- r.then do |e,vars|
47
- puts "rule #{index} fired"
48
- end
49
- end
50
- end
51
- end
52
- end
53
-
54
- include Ruleby
55
-
56
- t1 = Time.new
57
- engine :engine do |e|
58
- TestRulebook.new(e).rules
59
-
60
- t2 = Time.new
61
- diff = t2.to_f - t1.to_f
62
- puts 'time to create rule set: ' + diff.to_s
63
-
64
- e.assert Account.new('standard', nil, nil)
65
- for k in (0..500)
66
- e.assert Address.new(('acc'+k.to_s),'Foobar', 'FB', '12345')
67
- end
68
-
69
- t3 = Time.new
70
- diff = t3.to_f - t2.to_f
71
- puts 'time to assert facts: ' + diff.to_s
72
-
73
- e.match
74
-
75
- t4 = Time.new
76
- diff = t4.to_f - t3.to_f
77
- puts 'time to match rules: ' + diff.to_s
78
- end