ruleby 0.5 → 0.6
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/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
|