ruleby 0.5 → 0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/core/engine.rb +1 -1
- data/lib/core/nodes.rb +27 -13
- data/lib/dsl/ferrari.rb +124 -35
- data/lib/dsl/letigre.rb +0 -0
- data/lib/rulebook.rb +12 -5
- data/tests/test.rb +7 -6
- metadata +13 -12
- data/lib/dsl/treetop/treetop_helper.rb +0 -23
- data/lib/dsl/treetop/tt_dsl.treetop +0 -105
- data/lib/dsl/yaml_dsl.rb +0 -23
data/lib/core/engine.rb
CHANGED
@@ -173,7 +173,7 @@ module Ruleby
|
|
173
173
|
end
|
174
174
|
end
|
175
175
|
|
176
|
-
# This is the core class of the library. A new rule engine is
|
176
|
+
# This is the core class of the library. A new rule engine is created by
|
177
177
|
# instantiating it. Each rule engine has one inference engine, one rule set
|
178
178
|
# and one working memory.
|
179
179
|
class Engine
|
data/lib/core/nodes.rb
CHANGED
@@ -513,6 +513,12 @@ module Ruleby
|
|
513
513
|
out_node.retract_left(fact)
|
514
514
|
end
|
515
515
|
end
|
516
|
+
|
517
|
+
def retract_resolve(match)
|
518
|
+
@out_nodes.each do |o|
|
519
|
+
o.retract_resolve(match)
|
520
|
+
end
|
521
|
+
end
|
516
522
|
end
|
517
523
|
|
518
524
|
# This class is used to plug nodes into the right input of a two-input
|
@@ -528,6 +534,12 @@ module Ruleby
|
|
528
534
|
@out_nodes.each do |out_node|
|
529
535
|
out_node.retract_right(fact)
|
530
536
|
end
|
537
|
+
end
|
538
|
+
|
539
|
+
def retract_resolve(match)
|
540
|
+
@out_nodes.each do |o|
|
541
|
+
o.retract_resolve(match)
|
542
|
+
end
|
531
543
|
end
|
532
544
|
end
|
533
545
|
|
@@ -580,6 +592,19 @@ module Ruleby
|
|
580
592
|
|
581
593
|
def to_s
|
582
594
|
return "#{self.class}:#{object_id} | #{@left_memory.values} | #{@right_memory}"
|
595
|
+
end
|
596
|
+
|
597
|
+
def retract_resolve(match)
|
598
|
+
# in this method we retract an existing match from memory if it resolves
|
599
|
+
# with the match given. It would probably be better to check if it
|
600
|
+
# resolves with a list of facts. But the system is not set up for
|
601
|
+
# that yet.
|
602
|
+
@left_memory.each do |fact_id,contexts|
|
603
|
+
contexts.delete_if do |left_context|
|
604
|
+
resolve(left_context.match, match)
|
605
|
+
end
|
606
|
+
end
|
607
|
+
propagate_retract_resolve(match)
|
583
608
|
end
|
584
609
|
|
585
610
|
private
|
@@ -593,7 +618,8 @@ module Ruleby
|
|
593
618
|
if ref_mr.is_match
|
594
619
|
mr = mr.merge ref_mr
|
595
620
|
else
|
596
|
-
|
621
|
+
mr = MatchResult.new
|
622
|
+
break
|
597
623
|
end
|
598
624
|
end
|
599
625
|
return mr
|
@@ -615,18 +641,6 @@ module Ruleby
|
|
615
641
|
o.retract_resolve(match)
|
616
642
|
end
|
617
643
|
end
|
618
|
-
|
619
|
-
def retract_resolve(match)
|
620
|
-
# in this method we retract an existing match from memory if it resolves
|
621
|
-
# with the match given. It would probably be better to check if it
|
622
|
-
# resolves with a list of facts. But the system is not set up for
|
623
|
-
# that yet.
|
624
|
-
@left_memory.each do |fact_id,contexts|
|
625
|
-
value.delete_if do |left_context|
|
626
|
-
resolve(left_context.match, match)
|
627
|
-
end
|
628
|
-
end
|
629
|
-
end
|
630
644
|
end
|
631
645
|
|
632
646
|
# This node class is used when a rule is looking for a fact that does not
|
data/lib/dsl/ferrari.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# modify it under the terms of the Ruby license defined in the
|
5
5
|
# LICENSE.txt file.
|
6
6
|
#
|
7
|
-
# Copyright (c)
|
7
|
+
# Copyright (c) 2009 Joe Kutner and Matt Smith. All rights reserved.
|
8
8
|
#
|
9
9
|
# * Authors: Joe Kutner
|
10
10
|
#
|
@@ -20,37 +20,103 @@ module Ruleby
|
|
20
20
|
|
21
21
|
def rule(name, *args, &block)
|
22
22
|
options = args[0].kind_of?(Hash) ? args.shift : {}
|
23
|
-
|
24
|
-
|
23
|
+
|
24
|
+
parse_containers(args, RulesContainer.new).build(name,options,@engine,&block)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def parse_containers(args, container=AndContainer.new)
|
29
|
+
or_builders = []
|
30
|
+
and_container = AndContainer.new
|
25
31
|
args.each do |arg|
|
26
32
|
if arg.kind_of? Array
|
27
|
-
|
33
|
+
and_container << PatternContainer.new(arg)
|
34
|
+
elsif arg.kind_of? AndBuilder
|
35
|
+
and_container << parse_containers(arg.conditions)
|
36
|
+
elsif arg.kind_of? OrBuilder
|
37
|
+
or_builders << arg
|
28
38
|
else
|
29
|
-
raise 'Invalid condition.
|
39
|
+
raise 'Invalid condition. Must be an OR, AND or an Array.'
|
30
40
|
end
|
31
41
|
end
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
42
|
+
|
43
|
+
if or_builders.empty?
|
44
|
+
container << and_container
|
45
|
+
else
|
46
|
+
while !or_builders.empty?
|
47
|
+
or_builder = or_builders.pop
|
48
|
+
parse_containers(or_builder.conditions, OrContainer.new).each do |or_container|
|
49
|
+
or_container.each do |or_container_child|
|
50
|
+
rule = AndContainer.new
|
51
|
+
rule.push or_container_child
|
52
|
+
|
53
|
+
or_builders.each do |sub_or_builder|
|
54
|
+
parse_containers(sub_or_builder.conditions).each do |sub_or_container|
|
55
|
+
rule.push *sub_or_container
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
rule.push and_container
|
60
|
+
container << rule
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
return container
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class RulesContainer < Array
|
70
|
+
def build(name,options,engine,&block)
|
71
|
+
self.each do |x|
|
72
|
+
r = RuleBuilder.new name
|
73
|
+
x.build r
|
74
|
+
r.then(&block)
|
75
|
+
r.priority = options[:priority] if options[:priority]
|
76
|
+
engine.assert_rule(r.build_rule)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class AndContainer < Array
|
82
|
+
def build(builder)
|
83
|
+
self.each do |x|
|
84
|
+
x.build builder
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class OrContainer < Array
|
90
|
+
def build(builder)
|
91
|
+
# OrContainers are never built, they just contain containers that
|
92
|
+
# will be transformed into AndContainers.
|
93
|
+
raise 'Invalid Syntax'
|
37
94
|
end
|
38
|
-
|
39
95
|
end
|
40
96
|
|
97
|
+
class PatternContainer
|
98
|
+
def initialize(condition)
|
99
|
+
@condition = condition
|
100
|
+
end
|
101
|
+
|
102
|
+
def build(builder)
|
103
|
+
builder.when(*@condition)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
41
107
|
class RuleBuilder
|
42
|
-
|
108
|
+
|
43
109
|
def initialize(name, pattern=nil, action=nil, priority=0)
|
44
110
|
@name = name
|
45
111
|
@pattern = pattern
|
46
112
|
@action = action
|
47
113
|
@priority = priority
|
48
|
-
|
114
|
+
|
49
115
|
@tags = {}
|
50
116
|
@methods = {}
|
51
117
|
@when_counter = 0
|
52
118
|
end
|
53
|
-
|
119
|
+
|
54
120
|
def when(*args)
|
55
121
|
clazz = AtomBuilder === args[0] ? nil : args.shift
|
56
122
|
is_not = false
|
@@ -65,19 +131,19 @@ module Ruleby
|
|
65
131
|
end
|
66
132
|
clazz = args.empty? ? nil : args.shift
|
67
133
|
end
|
68
|
-
|
134
|
+
|
69
135
|
if clazz == nil
|
70
136
|
clazz = Object
|
71
137
|
mode = :inherits
|
72
138
|
end
|
73
|
-
|
139
|
+
|
74
140
|
deftemplate = Core::DefTemplate.new clazz, mode
|
75
141
|
atoms = []
|
76
142
|
@when_counter += 1
|
77
143
|
htag = Symbol === args[0] ? args.shift : GeneratedTag.new
|
78
144
|
head = Core::HeadAtom.new htag, deftemplate
|
79
145
|
@tags[htag] = @when_counter
|
80
|
-
|
146
|
+
|
81
147
|
args.each do |arg|
|
82
148
|
if arg.kind_of? Hash
|
83
149
|
arg.each do |ab,tag|
|
@@ -85,20 +151,20 @@ module Ruleby
|
|
85
151
|
ab.deftemplate = deftemplate
|
86
152
|
@tags[tag] = @when_counter
|
87
153
|
@methods[tag] = ab.name
|
88
|
-
atoms.push ab.
|
154
|
+
atoms.push *ab.build_atoms(@tags, @methods, @when_counter)
|
89
155
|
end
|
90
156
|
elsif arg.kind_of? AtomBuilder
|
91
157
|
arg.tag = GeneratedTag.new
|
92
158
|
arg.deftemplate = deftemplate
|
93
159
|
@methods[arg.tag] = arg.name
|
94
|
-
atoms.push arg.
|
160
|
+
atoms.push *arg.build_atoms(@tags, @methods, @when_counter)
|
95
161
|
elsif arg == false
|
96
162
|
raise 'The != operator is not allowed.'
|
97
163
|
else
|
98
164
|
raise "Invalid condition: #{arg}"
|
99
165
|
end
|
100
166
|
end
|
101
|
-
|
167
|
+
|
102
168
|
if is_not
|
103
169
|
p = mode==:inherits ? Core::NotInheritsPattern.new(head, atoms) :
|
104
170
|
Core::NotPattern.new(head, atoms)
|
@@ -107,30 +173,28 @@ module Ruleby
|
|
107
173
|
Core::ObjectPattern.new(head, atoms)
|
108
174
|
end
|
109
175
|
@pattern = @pattern ? Core::AndPattern.new(@pattern, p) : p
|
110
|
-
|
111
|
-
return nil
|
112
176
|
end
|
113
|
-
|
177
|
+
|
114
178
|
def then(&block)
|
115
179
|
@action = Core::Action.new(&block)
|
116
180
|
@action.name = @name
|
117
181
|
@action.priority = @priority
|
118
182
|
end
|
119
|
-
|
183
|
+
|
120
184
|
def priority
|
121
185
|
return @priority
|
122
186
|
end
|
123
|
-
|
187
|
+
|
124
188
|
def priority=(p)
|
125
189
|
@priority = p
|
126
190
|
@action.priority = @priority
|
127
191
|
end
|
128
|
-
|
192
|
+
|
129
193
|
def build_rule
|
130
194
|
Core::Rule.new @name, @pattern, @action, @priority
|
131
195
|
end
|
132
196
|
end
|
133
|
-
|
197
|
+
|
134
198
|
class MethodBuilder
|
135
199
|
public_instance_methods.each do |m|
|
136
200
|
a = [:method_missing, :new, :public_instance_methods, :__send__, :__id__]
|
@@ -183,12 +247,13 @@ module Ruleby
|
|
183
247
|
class AtomBuilder
|
184
248
|
attr_accessor :tag, :name, :bindings, :deftemplate, :block
|
185
249
|
|
186
|
-
def initialize(
|
187
|
-
@name =
|
250
|
+
def initialize(method_id)
|
251
|
+
@name = method_id
|
188
252
|
@deftemplate = nil
|
189
|
-
@tag =
|
253
|
+
@tag = GeneratedTag.new
|
190
254
|
@bindings = []
|
191
255
|
@block = lambda {|x| true}
|
256
|
+
@child_atom_builders = []
|
192
257
|
end
|
193
258
|
|
194
259
|
def method_missing(method_id, *args, &block)
|
@@ -227,21 +292,27 @@ module Ruleby
|
|
227
292
|
create_block value, lambda {|x,y| x =~ y}, lambda {|x| x =~ value}; self
|
228
293
|
end
|
229
294
|
|
230
|
-
def
|
295
|
+
def build_atoms(tags,methods,when_id)
|
296
|
+
atoms = @child_atom_builders.map { |atom_builder|
|
297
|
+
tags[atom_builder.tag] = when_id
|
298
|
+
methods[atom_builder.tag] = atom_builder.name
|
299
|
+
atom_builder.build_atoms(tags,methods,when_id)
|
300
|
+
}.flatten || []
|
301
|
+
|
231
302
|
if @bindings.empty?
|
232
303
|
if @atom_type == :equals
|
233
|
-
return Core::EqualsAtom.new(@tag, @name, @deftemplate, @value)
|
304
|
+
return atoms << Core::EqualsAtom.new(@tag, @name, @deftemplate, @value)
|
234
305
|
else
|
235
|
-
return Core::PropertyAtom.new(@tag, @name, @deftemplate, &@block)
|
306
|
+
return atoms << Core::PropertyAtom.new(@tag, @name, @deftemplate, &@block)
|
236
307
|
end
|
237
308
|
end
|
238
309
|
|
239
310
|
if references_self?(tags,when_id)
|
240
311
|
bind_methods = @bindings.collect{ |bb| methods[bb.tag] }
|
241
|
-
Core::SelfReferenceAtom.new(@tag,@name,bind_methods,@deftemplate,&@block)
|
312
|
+
atoms << Core::SelfReferenceAtom.new(@tag,@name,bind_methods,@deftemplate,&@block)
|
242
313
|
else
|
243
314
|
bind_tags = @bindings.collect{ |bb| bb.tag }
|
244
|
-
Core::ReferenceAtom.new(@tag,@name,bind_tags,@deftemplate,&@block)
|
315
|
+
atoms << Core::ReferenceAtom.new(@tag,@name,bind_tags,@deftemplate,&@block)
|
245
316
|
end
|
246
317
|
end
|
247
318
|
|
@@ -265,6 +336,10 @@ module Ruleby
|
|
265
336
|
if value && value.kind_of?(BindingBuilder)
|
266
337
|
@bindings = [value]
|
267
338
|
@block = ref_block
|
339
|
+
elsif value && value.kind_of?(AtomBuilder)
|
340
|
+
@child_atom_builders << value
|
341
|
+
@bindings = [BindingBuilder.new(value.tag)]
|
342
|
+
@block = ref_block
|
268
343
|
else
|
269
344
|
@block = basic_block
|
270
345
|
end
|
@@ -276,5 +351,19 @@ module Ruleby
|
|
276
351
|
create_block value, lambda {|x,y| x != y}, lambda {|x| x != value}; self
|
277
352
|
end
|
278
353
|
end
|
354
|
+
|
355
|
+
class OrBuilder
|
356
|
+
attr_reader :conditions
|
357
|
+
def initialize(conditions)
|
358
|
+
@conditions = conditions
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
class AndBuilder
|
363
|
+
attr_reader :conditions
|
364
|
+
def initialize(conditions)
|
365
|
+
@conditions = conditions
|
366
|
+
end
|
367
|
+
end
|
279
368
|
end
|
280
369
|
end
|
data/lib/dsl/letigre.rb
CHANGED
File without changes
|
data/lib/rulebook.rb
CHANGED
@@ -17,13 +17,12 @@ require 'dsl/steel'
|
|
17
17
|
module Ruleby
|
18
18
|
class Rulebook
|
19
19
|
include Ruleby
|
20
|
-
def initialize(engine,
|
20
|
+
def initialize(engine, &block)
|
21
21
|
@engine = engine
|
22
|
-
|
22
|
+
yield self if block_given?
|
23
23
|
end
|
24
24
|
|
25
25
|
attr_reader :engine
|
26
|
-
attr_reader :session
|
27
26
|
|
28
27
|
def assert(fact)
|
29
28
|
@engine.assert fact
|
@@ -45,7 +44,7 @@ module Ruleby
|
|
45
44
|
r.rule name, &block
|
46
45
|
else
|
47
46
|
i = args[0].kind_of?(Hash) ? 1 : 0
|
48
|
-
if args[i].
|
47
|
+
if [Array, Ruleby::Ferrari::OrBuilder, Ruleby::Ferrari::AndBuilder].include? args[i].class
|
49
48
|
# use ferrari DSL
|
50
49
|
r = Ferrari::RulebookHelper.new @engine
|
51
50
|
r.rule name, *args, &block
|
@@ -72,7 +71,7 @@ module Ruleby
|
|
72
71
|
end
|
73
72
|
|
74
73
|
def binding(variable_name)
|
75
|
-
b
|
74
|
+
b variable_name
|
76
75
|
end
|
77
76
|
|
78
77
|
def c(&block)
|
@@ -83,6 +82,14 @@ module Ruleby
|
|
83
82
|
return lambda(&block)
|
84
83
|
end
|
85
84
|
|
85
|
+
def OR(*args)
|
86
|
+
Ruleby::Ferrari::OrBuilder.new args
|
87
|
+
end
|
88
|
+
|
89
|
+
def AND(*args)
|
90
|
+
Ruleby::Ferrari::AndBuilder.new args
|
91
|
+
end
|
92
|
+
|
86
93
|
def __eval__(x)
|
87
94
|
eval(x)
|
88
95
|
end
|
data/tests/test.rb
CHANGED
@@ -9,10 +9,11 @@
|
|
9
9
|
# * Authors: John Mettraux
|
10
10
|
#
|
11
11
|
require 'common'
|
12
|
-
require '
|
13
|
-
require '
|
14
|
-
require '
|
15
|
-
require 'gets
|
16
|
-
require '
|
12
|
+
require 'duck_type'
|
13
|
+
require 'self_reference'
|
14
|
+
require 'regex'
|
15
|
+
require 'gets'
|
16
|
+
require 'assert_facts'
|
17
17
|
require 'not_patterns'
|
18
|
-
|
18
|
+
require 'or_patterns'
|
19
|
+
require 'join_nodes'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruleby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "0.
|
4
|
+
version: "0.6"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joe Kutner
|
@@ -10,12 +10,17 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2009-
|
13
|
+
date: 2009-11-23 00:00:00 -06:00
|
14
14
|
default_executable:
|
15
15
|
dependencies: []
|
16
16
|
|
17
|
-
description:
|
18
|
-
|
17
|
+
description: |
|
18
|
+
Ruleby is a rule engine written in the Ruby language. It is a system for executing a set
|
19
|
+
of IF-THEN statements known as production rules. These rules are matched to objects using
|
20
|
+
the forward chaining Rete algorithm. Ruleby provides an internal Domain Specific Language
|
21
|
+
(DSL) for building the productions that make up a Ruleby program.
|
22
|
+
|
23
|
+
email: jpkutner@gmail.com
|
19
24
|
executables: []
|
20
25
|
|
21
26
|
extensions: []
|
@@ -23,24 +28,20 @@ extensions: []
|
|
23
28
|
extra_rdoc_files: []
|
24
29
|
|
25
30
|
files:
|
26
|
-
- lib/core
|
27
31
|
- lib/core/atoms.rb
|
28
32
|
- lib/core/engine.rb
|
29
33
|
- lib/core/nodes.rb
|
30
34
|
- lib/core/patterns.rb
|
31
35
|
- lib/core/utils.rb
|
32
|
-
- lib/dsl
|
33
36
|
- lib/dsl/ferrari.rb
|
34
37
|
- lib/dsl/letigre.rb
|
35
38
|
- lib/dsl/steel.rb
|
36
|
-
- lib/dsl/treetop
|
37
|
-
- lib/dsl/treetop/treetop_helper.rb
|
38
|
-
- lib/dsl/treetop/tt_dsl.treetop
|
39
|
-
- lib/dsl/yaml_dsl.rb
|
40
39
|
- lib/rulebook.rb
|
41
40
|
- lib/ruleby.rb
|
42
41
|
has_rdoc: true
|
43
42
|
homepage: http://ruleby.org
|
43
|
+
licenses: []
|
44
|
+
|
44
45
|
post_install_message:
|
45
46
|
rdoc_options: []
|
46
47
|
|
@@ -61,9 +62,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
61
62
|
requirements: []
|
62
63
|
|
63
64
|
rubyforge_project: ruleby
|
64
|
-
rubygems_version: 1.
|
65
|
+
rubygems_version: 1.3.5
|
65
66
|
signing_key:
|
66
|
-
specification_version:
|
67
|
+
specification_version: 3
|
67
68
|
summary: Rete based Ruby Rule Engine
|
68
69
|
test_files:
|
69
70
|
- tests/test.rb
|
@@ -1,23 +0,0 @@
|
|
1
|
-
|
2
|
-
module Ruleby
|
3
|
-
class TreetopHelper
|
4
|
-
|
5
|
-
def self.rule(name, *args, &block)
|
6
|
-
options = args[0].kind_of?(Hash) ? args.shift : {}
|
7
|
-
|
8
|
-
r = Ferrari::RuleBuilder.new name
|
9
|
-
args.each do |arg|
|
10
|
-
if arg.kind_of? Array
|
11
|
-
r.when(*arg)
|
12
|
-
else
|
13
|
-
raise 'Invalid condition. All or none must be Arrays.'
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
r.then(&block)
|
18
|
-
r.priority = options[:priority] if options[:priority]
|
19
|
-
|
20
|
-
return r.build_rule
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,105 +0,0 @@
|
|
1
|
-
grammar Ruleby
|
2
|
-
rule root
|
3
|
-
defrule* {
|
4
|
-
def get_rules
|
5
|
-
rs = []
|
6
|
-
elements.each do |e|
|
7
|
-
rs << e.get_rule()
|
8
|
-
end
|
9
|
-
return rs
|
10
|
-
end
|
11
|
-
}
|
12
|
-
end
|
13
|
-
|
14
|
-
rule defrule
|
15
|
-
'rule' space name space foreach space action {
|
16
|
-
def get_rule()
|
17
|
-
action_text = action.text_value.strip
|
18
|
-
action_text.gsub!('do', '')
|
19
|
-
action_text.gsub!('end', '')
|
20
|
-
return foreach.get_rule(name.text_value.strip, action_text.strip)
|
21
|
-
end
|
22
|
-
}
|
23
|
-
end
|
24
|
-
|
25
|
-
rule name
|
26
|
-
[a-zA-Z] [a-zA-Z0-9]*
|
27
|
-
end
|
28
|
-
|
29
|
-
rule foreach
|
30
|
-
'foreach' space head space symbol {
|
31
|
-
def get_rule(name, action_text)
|
32
|
-
class_name = head.text_value.strip
|
33
|
-
clazz = eval(class_name)
|
34
|
-
tag = symbol.text_value.strip
|
35
|
-
tag = tag[1, tag.size - 1]
|
36
|
-
return Ruleby::TreetopHelper.rule(name, [clazz, tag.to_sym], &action_text)
|
37
|
-
end
|
38
|
-
}
|
39
|
-
end
|
40
|
-
|
41
|
-
|
42
|
-
rule action
|
43
|
-
'do' space (!'end' .)* 'end' space?
|
44
|
-
end
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
rule head
|
49
|
-
[A-Z] [a-zA-Z]*
|
50
|
-
end
|
51
|
-
rule symbol
|
52
|
-
':' [a-zA-Z]+
|
53
|
-
end
|
54
|
-
rule where
|
55
|
-
'where'
|
56
|
-
end
|
57
|
-
rule method
|
58
|
-
symbol '.' [a-z] [a-zA-Z0-9]*
|
59
|
-
end
|
60
|
-
rule string
|
61
|
-
'\'' [a-zA-Z0-9]* '\''
|
62
|
-
end
|
63
|
-
rule value
|
64
|
-
method / '-'* [0-9]+ / symbol / string
|
65
|
-
end
|
66
|
-
rule expression
|
67
|
-
value space (equal space value) / (not_equal space value) / (symbol)
|
68
|
-
end
|
69
|
-
|
70
|
-
rule clause
|
71
|
-
expression more:(and_sign clause)* {
|
72
|
-
def populate
|
73
|
-
more.elements.each do |e|
|
74
|
-
e.clause.populate
|
75
|
-
end
|
76
|
-
end
|
77
|
-
}
|
78
|
-
end
|
79
|
-
rule and_sign
|
80
|
-
'AND'
|
81
|
-
end
|
82
|
-
rule not_equal
|
83
|
-
'!='
|
84
|
-
end
|
85
|
-
rule equal
|
86
|
-
'=='
|
87
|
-
end
|
88
|
-
|
89
|
-
rule space
|
90
|
-
white+
|
91
|
-
end
|
92
|
-
|
93
|
-
|
94
|
-
rule white
|
95
|
-
blank / eol
|
96
|
-
end
|
97
|
-
|
98
|
-
rule blank
|
99
|
-
[ \t]
|
100
|
-
end
|
101
|
-
|
102
|
-
rule eol
|
103
|
-
("\r" "\n"?) / "\n"
|
104
|
-
end
|
105
|
-
end
|
data/lib/dsl/yaml_dsl.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'ruleby'
|
3
|
-
require 'dsl/letigre'
|
4
|
-
module Ruleby
|
5
|
-
module YamlDsl
|
6
|
-
require 'yaml'
|
7
|
-
def self.load_rules(rules_yaml, engine)
|
8
|
-
ry = YAML::load(rules_yaml)
|
9
|
-
ry.each do |k,v|
|
10
|
-
if k =~ /_rule/
|
11
|
-
wh = v['when']
|
12
|
-
wh.gsub!('@', '#')
|
13
|
-
wh = wh.split(',')
|
14
|
-
th = v['then']
|
15
|
-
priority = v['priority']
|
16
|
-
th = "context engine -> #{th}"
|
17
|
-
r = LeTigre::RulebookHelper.new engine
|
18
|
-
r.rule k, { :priority => priority }, *wh, &th.to_proc
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|