ruleby 0.8.b9 → 0.8
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 +50 -47
- data/lib/core/nodes.rb +26 -26
- data/lib/dsl/ferrari.rb +35 -21
- data/lib/rulebook.rb +2 -9
- metadata +5 -7
- data/lib/dsl/letigre.rb +0 -238
- data/lib/dsl/steel.rb +0 -314
data/lib/core/atoms.rb
CHANGED
|
@@ -14,17 +14,17 @@ module Ruleby
|
|
|
14
14
|
module Core
|
|
15
15
|
|
|
16
16
|
class Atom
|
|
17
|
-
attr_reader :tag, :proc, :
|
|
17
|
+
attr_reader :tag, :proc, :slot, :template
|
|
18
18
|
|
|
19
|
-
def initialize(tag,
|
|
19
|
+
def initialize(tag, slot, template, block)
|
|
20
20
|
@tag = tag
|
|
21
|
-
@
|
|
22
|
-
@
|
|
23
|
-
@proc =
|
|
21
|
+
@slot = slot
|
|
22
|
+
@template = template
|
|
23
|
+
@proc = block
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def to_s
|
|
27
|
-
|
|
27
|
+
"#{self.class},#{@tag},#{@slot},#{@template}"
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
|
|
@@ -34,16 +34,25 @@ module Ruleby
|
|
|
34
34
|
# a.person{ |p| p.is_a? Person }
|
|
35
35
|
#
|
|
36
36
|
# So there are no references to other atoms.
|
|
37
|
-
class PropertyAtom < Atom
|
|
37
|
+
class PropertyAtom < Atom
|
|
38
|
+
|
|
39
|
+
attr_reader :value
|
|
40
|
+
|
|
41
|
+
def initialize(tag, slot, template, value, block)
|
|
42
|
+
super(tag,slot,template, block)
|
|
43
|
+
@value = value
|
|
44
|
+
end
|
|
45
|
+
|
|
38
46
|
def ==(atom)
|
|
39
|
-
|
|
47
|
+
shareable?(atom) && @tag == atom.tag
|
|
40
48
|
end
|
|
41
49
|
|
|
42
50
|
def shareable?(atom)
|
|
43
|
-
|
|
44
|
-
@
|
|
45
|
-
@
|
|
46
|
-
@proc == atom.proc
|
|
51
|
+
PropertyAtom === atom &&
|
|
52
|
+
@slot == atom.slot &&
|
|
53
|
+
@template == atom.template &&
|
|
54
|
+
@proc == atom.proc &&
|
|
55
|
+
@value == atom.value
|
|
47
56
|
end
|
|
48
57
|
end
|
|
49
58
|
|
|
@@ -53,30 +62,21 @@ module Ruleby
|
|
|
53
62
|
|
|
54
63
|
def initialize(tag, template, arguments, block)
|
|
55
64
|
@tag = tag
|
|
56
|
-
@
|
|
57
|
-
@
|
|
65
|
+
@slot = nil
|
|
66
|
+
@template = template
|
|
58
67
|
@arguments = arguments
|
|
59
68
|
@proc = block
|
|
60
69
|
end
|
|
61
70
|
|
|
62
71
|
def shareable?(atom)
|
|
63
72
|
FunctionAtom === atom &&
|
|
64
|
-
@
|
|
73
|
+
@template == atom.template &&
|
|
65
74
|
@arguments == atom.arguments &&
|
|
66
75
|
@proc == atom.proc
|
|
67
76
|
end
|
|
68
77
|
|
|
69
78
|
def to_s
|
|
70
|
-
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
# TODO use this
|
|
75
|
-
class BlockAtom < PropertyAtom
|
|
76
|
-
def shareable?(atom)
|
|
77
|
-
return super &&
|
|
78
|
-
BlockAtom === atom &&
|
|
79
|
-
@proc == atom.proc
|
|
79
|
+
"#{self.class},#{@template},#{@arguments.inspect}"
|
|
80
80
|
end
|
|
81
81
|
end
|
|
82
82
|
|
|
@@ -87,16 +87,16 @@ module Ruleby
|
|
|
87
87
|
#
|
|
88
88
|
# So there are no references to other atoms.
|
|
89
89
|
class EqualsAtom < PropertyAtom
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
EQUAL_PROC = lambda {|x, y| x == y}
|
|
91
|
+
|
|
92
|
+
def initialize(tag, slot, template, value)
|
|
93
|
+
super(tag,slot,template, value, EQUAL_PROC)
|
|
94
94
|
end
|
|
95
|
-
|
|
95
|
+
|
|
96
96
|
def shareable?(atom)
|
|
97
|
-
|
|
98
|
-
@
|
|
99
|
-
@
|
|
97
|
+
EqualsAtom === atom &&
|
|
98
|
+
@slot == atom.slot &&
|
|
99
|
+
@template == atom.template
|
|
100
100
|
end
|
|
101
101
|
end
|
|
102
102
|
|
|
@@ -105,17 +105,20 @@ module Ruleby
|
|
|
105
105
|
# 'For each Person as :p'
|
|
106
106
|
#
|
|
107
107
|
# It is only used at the start of a pattern.
|
|
108
|
-
class HeadAtom <
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
108
|
+
class HeadAtom < PropertyAtom
|
|
109
|
+
HEAD_EQUAL_PROC = lambda {|t, c| t == c}
|
|
110
|
+
HEAD_INHERITS_PROC = lambda {|t, c| t === c}
|
|
111
|
+
|
|
112
|
+
def initialize(tag, template)
|
|
113
|
+
if template.mode == :equals
|
|
114
|
+
super tag, :class, template, template.clazz, HEAD_EQUAL_PROC
|
|
115
|
+
elsif template.mode == :inherits
|
|
116
|
+
super tag, :class, template, template.clazz, HEAD_INHERITS_PROC
|
|
114
117
|
end
|
|
115
118
|
end
|
|
116
119
|
|
|
117
120
|
def shareable?(atom)
|
|
118
|
-
|
|
121
|
+
HeadAtom === atom && @template == atom.template
|
|
119
122
|
end
|
|
120
123
|
end
|
|
121
124
|
|
|
@@ -128,8 +131,8 @@ module Ruleby
|
|
|
128
131
|
class ReferenceAtom < Atom
|
|
129
132
|
attr_reader :vars
|
|
130
133
|
|
|
131
|
-
def initialize(tag,
|
|
132
|
-
super(tag,
|
|
134
|
+
def initialize(tag, slot, vars, template, block)
|
|
135
|
+
super(tag, slot, template, block)
|
|
133
136
|
@vars = vars # list of referenced variable names
|
|
134
137
|
end
|
|
135
138
|
|
|
@@ -138,21 +141,21 @@ module Ruleby
|
|
|
138
141
|
end
|
|
139
142
|
|
|
140
143
|
def ==(atom)
|
|
141
|
-
|
|
144
|
+
ReferenceAtom === atom &&
|
|
142
145
|
@proc == atom.proc &&
|
|
143
146
|
@tag == atom.tag &&
|
|
144
147
|
@vars == atom.vars &&
|
|
145
|
-
@
|
|
148
|
+
@template == atom.template
|
|
146
149
|
end
|
|
147
150
|
|
|
148
151
|
def to_s
|
|
149
|
-
|
|
152
|
+
super + ", vars=#{vars.join(',')}"
|
|
150
153
|
end
|
|
151
154
|
end
|
|
152
155
|
|
|
153
156
|
# This is an atom that references another atom that is in the same pattern.
|
|
154
157
|
# Note that in a SelfReferenceAtom, the 'vars' argument must be a list of the
|
|
155
|
-
# *
|
|
158
|
+
# *slots* that this atom references (not the variable names)!
|
|
156
159
|
class SelfReferenceAtom < ReferenceAtom
|
|
157
160
|
end
|
|
158
161
|
|
|
@@ -179,4 +182,4 @@ module Ruleby
|
|
|
179
182
|
end
|
|
180
183
|
|
|
181
184
|
end
|
|
182
|
-
end
|
|
185
|
+
end
|
data/lib/core/nodes.rb
CHANGED
|
@@ -222,27 +222,23 @@ module Ruleby
|
|
|
222
222
|
end
|
|
223
223
|
@atom_nodes.each {|n| return n if n.shareable? node}
|
|
224
224
|
@atom_nodes.push node
|
|
225
|
-
|
|
225
|
+
node
|
|
226
226
|
end
|
|
227
227
|
|
|
228
228
|
def create_self_reference_node(atom)
|
|
229
229
|
node = SelfReferenceNode.new(@bucket, atom)
|
|
230
230
|
@atom_nodes.push node
|
|
231
|
-
|
|
231
|
+
node
|
|
232
232
|
end
|
|
233
233
|
|
|
234
234
|
def create_reference_node(atom)
|
|
235
235
|
node = ReferenceNode.new(@bucket, atom)
|
|
236
236
|
@atom_nodes.push node
|
|
237
|
-
|
|
237
|
+
node
|
|
238
238
|
end
|
|
239
239
|
|
|
240
240
|
def create_adapter_node(side)
|
|
241
|
-
|
|
242
|
-
return LeftAdapterNode.new(@bucket)
|
|
243
|
-
else
|
|
244
|
-
return RightAdapterNode.new(@bucket)
|
|
245
|
-
end
|
|
241
|
+
side == :left ? LeftAdapterNode.new(@bucket) : RightAdapterNode.new(@bucket)
|
|
246
242
|
end
|
|
247
243
|
|
|
248
244
|
# This method is used to update each TypeNode based on the facts in
|
|
@@ -294,7 +290,7 @@ module Ruleby
|
|
|
294
290
|
end
|
|
295
291
|
end
|
|
296
292
|
end
|
|
297
|
-
|
|
293
|
+
true
|
|
298
294
|
end
|
|
299
295
|
end
|
|
300
296
|
|
|
@@ -370,15 +366,15 @@ module Ruleby
|
|
|
370
366
|
end
|
|
371
367
|
|
|
372
368
|
def ==(node)
|
|
373
|
-
|
|
369
|
+
AtomNode === node && @atom == node.atom
|
|
374
370
|
end
|
|
375
371
|
|
|
376
372
|
def shareable?(node)
|
|
377
|
-
|
|
373
|
+
@atom.shareable?(node.atom)
|
|
378
374
|
end
|
|
379
375
|
|
|
380
376
|
def to_s
|
|
381
|
-
super + " - #{@atom.
|
|
377
|
+
super + " - #{@atom.slot}"
|
|
382
378
|
end
|
|
383
379
|
end
|
|
384
380
|
|
|
@@ -406,7 +402,7 @@ module Ruleby
|
|
|
406
402
|
end
|
|
407
403
|
|
|
408
404
|
def assert(assertable)
|
|
409
|
-
k = assertable.fact.object.send(@atom.
|
|
405
|
+
k = assertable.fact.object.send(@atom.slot)
|
|
410
406
|
|
|
411
407
|
# TODOwe need to do this for ALL tags if this node is shared
|
|
412
408
|
assertable.add_tag(@atom.tag, k)
|
|
@@ -424,7 +420,7 @@ module Ruleby
|
|
|
424
420
|
# is matched exactly (ignoring inheritance).
|
|
425
421
|
class TypeNode < HashedNode
|
|
426
422
|
def hash_by(atom)
|
|
427
|
-
atom.
|
|
423
|
+
atom.template.clazz
|
|
428
424
|
end
|
|
429
425
|
|
|
430
426
|
def retract(fact)
|
|
@@ -432,7 +428,7 @@ module Ruleby
|
|
|
432
428
|
end
|
|
433
429
|
|
|
434
430
|
def assert(fact)
|
|
435
|
-
k = fact.object.send(@atom.
|
|
431
|
+
k = fact.object.send(@atom.slot)
|
|
436
432
|
# TODO we should create the Assertion object here, not in propogate
|
|
437
433
|
propagate_assert fact, (@values[k] ? @values[k] : {})
|
|
438
434
|
rescue NoMethodError => e
|
|
@@ -468,8 +464,8 @@ module Ruleby
|
|
|
468
464
|
class PropertyNode < AtomNode
|
|
469
465
|
def assert(assertable)
|
|
470
466
|
begin
|
|
471
|
-
|
|
472
|
-
assertable.add_tag(@atom.tag,
|
|
467
|
+
v = assertable.fact.object.send(@atom.slot)
|
|
468
|
+
assertable.add_tag(@atom.tag, v)
|
|
473
469
|
rescue NoMethodError => e
|
|
474
470
|
@bucket.add_error Error.new(:no_method, :warn, {
|
|
475
471
|
:object => assertable.fact.object.to_s,
|
|
@@ -479,12 +475,16 @@ module Ruleby
|
|
|
479
475
|
return
|
|
480
476
|
end
|
|
481
477
|
begin
|
|
482
|
-
|
|
478
|
+
if @atom.proc.arity == 1
|
|
479
|
+
super if @atom.proc.call(v)
|
|
480
|
+
else
|
|
481
|
+
super if @atom.proc.call(v, @atom.value)
|
|
482
|
+
end
|
|
483
483
|
rescue Exception => e
|
|
484
484
|
@bucket.add_error Error.new(:proc_call, :error, {
|
|
485
485
|
:object => assertable.fact.object.to_s,
|
|
486
|
-
:method => @atom.
|
|
487
|
-
:value =>
|
|
486
|
+
:method => @atom.slot,
|
|
487
|
+
:value => v.to_s,
|
|
488
488
|
:message => e.message
|
|
489
489
|
})
|
|
490
490
|
end
|
|
@@ -500,7 +500,7 @@ module Ruleby
|
|
|
500
500
|
end
|
|
501
501
|
end
|
|
502
502
|
|
|
503
|
-
# This node class is used
|
|
503
|
+
# This node class is used conditions that are simply a function, which returns true or false.
|
|
504
504
|
class FunctionNode < AtomNode
|
|
505
505
|
def assert(assertable)
|
|
506
506
|
begin
|
|
@@ -522,7 +522,7 @@ module Ruleby
|
|
|
522
522
|
# invoked by the two input node.
|
|
523
523
|
class ReferenceNode < AtomNode
|
|
524
524
|
def match(left_context,right_fact)
|
|
525
|
-
val = right_fact.object.send(@atom.
|
|
525
|
+
val = right_fact.object.send(@atom.slot)
|
|
526
526
|
args = [val]
|
|
527
527
|
match = left_context.match
|
|
528
528
|
@atom.vars.each do |var|
|
|
@@ -558,7 +558,7 @@ module Ruleby
|
|
|
558
558
|
end
|
|
559
559
|
|
|
560
560
|
def match(fact)
|
|
561
|
-
args = [fact.object.send(@atom.
|
|
561
|
+
args = [fact.object.send(@atom.slot)]
|
|
562
562
|
@atom.vars.each do |var|
|
|
563
563
|
args.push fact.object.send(var)
|
|
564
564
|
end
|
|
@@ -596,11 +596,11 @@ module Ruleby
|
|
|
596
596
|
if atom == @pattern.head
|
|
597
597
|
# TODO once we fix up TypeNode, we won't need this
|
|
598
598
|
mr[atom.tag] = fact.object
|
|
599
|
-
elsif !mr.key?(atom.tag) and atom.
|
|
599
|
+
elsif !mr.key?(atom.tag) and atom.slot
|
|
600
600
|
# this is a big hack for the sake of performance. should really do whats described below
|
|
601
601
|
unless atom.tag.is_a?(GeneratedTag)
|
|
602
602
|
# TODO it should be possible to get rid of this, and just capture it in the Nodes above
|
|
603
|
-
mr[atom.tag] = fact.object.send(atom.
|
|
603
|
+
mr[atom.tag] = fact.object.send(atom.slot)
|
|
604
604
|
end
|
|
605
605
|
end
|
|
606
606
|
end
|
|
@@ -1002,4 +1002,4 @@ module Ruleby
|
|
|
1002
1002
|
end
|
|
1003
1003
|
|
|
1004
1004
|
end
|
|
1005
|
-
end
|
|
1005
|
+
end
|
data/lib/dsl/ferrari.rb
CHANGED
|
@@ -301,7 +301,7 @@ module Ruleby
|
|
|
301
301
|
public_instance_methods.each do |m|
|
|
302
302
|
# maybe we shouldn't be undefing object_id. What are the implications? Can we make object_id a
|
|
303
303
|
# pass through to the underlying object's object_id?
|
|
304
|
-
a = [:method_missing, :new, :public_instance_methods, :__send__, :__id__]
|
|
304
|
+
a = [:method_missing, :new, :public_instance_methods, :__send__, :__id__, :object_id]
|
|
305
305
|
undef_method m.to_sym unless a.include? m.to_sym
|
|
306
306
|
end
|
|
307
307
|
|
|
@@ -316,7 +316,7 @@ module Ruleby
|
|
|
316
316
|
puts args.class.to_s + ' --- ' + args.to_s
|
|
317
317
|
raise 'Arguments not supported for short-hand conditions'
|
|
318
318
|
end
|
|
319
|
-
|
|
319
|
+
ab
|
|
320
320
|
end
|
|
321
321
|
end
|
|
322
322
|
|
|
@@ -361,46 +361,59 @@ module Ruleby
|
|
|
361
361
|
|
|
362
362
|
class AtomBuilder
|
|
363
363
|
attr_accessor :tag, :name, :bindings, :deftemplate, :block
|
|
364
|
-
|
|
364
|
+
|
|
365
|
+
EQ_PROC = lambda {|x,y| x and x == y}
|
|
366
|
+
GT_PROC = lambda {|x,y| x and x > y}
|
|
367
|
+
LT_PROC = lambda {|x,y| x and x < y}
|
|
368
|
+
MATCH_PROC = lambda {|x,y| x and x =~ y}
|
|
369
|
+
LTE_PROC = lambda {|x,y| x and x <= y}
|
|
370
|
+
GTE_PROC = lambda {|x,y| x and x >= y}
|
|
371
|
+
TRUE_PROC = lambda {|x| true}
|
|
372
|
+
|
|
365
373
|
def initialize(method_id)
|
|
366
374
|
@name = method_id
|
|
367
375
|
@deftemplate = nil
|
|
368
376
|
@tag = GeneratedTag.new
|
|
369
377
|
@bindings = []
|
|
370
|
-
@block =
|
|
378
|
+
@block = TRUE_PROC
|
|
371
379
|
@child_atom_builders = []
|
|
372
380
|
end
|
|
373
381
|
|
|
374
382
|
def method_missing(method_id, *args, &block)
|
|
375
383
|
if method_id == :not
|
|
376
|
-
|
|
384
|
+
NotOperatorBuilder.new(@name)
|
|
377
385
|
end
|
|
378
386
|
end
|
|
379
387
|
|
|
380
388
|
def ==(value)
|
|
381
389
|
@atom_type = :equals
|
|
382
|
-
|
|
383
|
-
|
|
390
|
+
create_block value, EQ_PROC
|
|
391
|
+
self
|
|
384
392
|
end
|
|
385
393
|
|
|
386
394
|
def >(value)
|
|
387
|
-
create_block value,
|
|
395
|
+
create_block value, GT_PROC
|
|
396
|
+
self
|
|
388
397
|
end
|
|
389
398
|
|
|
390
399
|
def <(value)
|
|
391
|
-
create_block value,
|
|
400
|
+
create_block value, LT_PROC
|
|
401
|
+
self
|
|
392
402
|
end
|
|
393
403
|
|
|
394
404
|
def =~(value)
|
|
395
|
-
create_block value,
|
|
405
|
+
create_block value, MATCH_PROC
|
|
406
|
+
self
|
|
396
407
|
end
|
|
397
408
|
|
|
398
409
|
def <=(value)
|
|
399
|
-
create_block value,
|
|
410
|
+
create_block value, LTE_PROC
|
|
411
|
+
self
|
|
400
412
|
end
|
|
401
413
|
|
|
402
414
|
def >=(value)
|
|
403
|
-
create_block value,
|
|
415
|
+
create_block value, GTE_PROC
|
|
416
|
+
self
|
|
404
417
|
end
|
|
405
418
|
|
|
406
419
|
def build_atoms(tags,methods,when_id)
|
|
@@ -414,16 +427,16 @@ module Ruleby
|
|
|
414
427
|
if @atom_type == :equals
|
|
415
428
|
return atoms << Core::EqualsAtom.new(@tag, @name, @deftemplate, @value)
|
|
416
429
|
else
|
|
417
|
-
return atoms << Core::PropertyAtom.new(@tag, @name, @deftemplate,
|
|
430
|
+
return atoms << Core::PropertyAtom.new(@tag, @name, @deftemplate, @value, @block)
|
|
418
431
|
end
|
|
419
432
|
end
|
|
420
433
|
|
|
421
434
|
if references_self?(tags,when_id)
|
|
422
435
|
bind_methods = @bindings.collect{ |bb| methods[bb.tag] }
|
|
423
|
-
atoms << Core::SelfReferenceAtom.new(@tag,@name,bind_methods,@deftemplate
|
|
436
|
+
atoms << Core::SelfReferenceAtom.new(@tag,@name,bind_methods,@deftemplate,@block)
|
|
424
437
|
else
|
|
425
438
|
bind_tags = @bindings.collect{ |bb| bb.tag }
|
|
426
|
-
atoms << Core::ReferenceAtom.new(@tag,@name,bind_tags,@deftemplate
|
|
439
|
+
atoms << Core::ReferenceAtom.new(@tag,@name,bind_tags,@deftemplate,@block)
|
|
427
440
|
end
|
|
428
441
|
end
|
|
429
442
|
|
|
@@ -440,26 +453,27 @@ module Ruleby
|
|
|
440
453
|
raise 'Binding to self and another pattern in the same condition is not yet supported.'
|
|
441
454
|
end
|
|
442
455
|
|
|
443
|
-
|
|
456
|
+
ref_self > 0
|
|
444
457
|
end
|
|
445
458
|
|
|
446
|
-
def create_block(value,
|
|
459
|
+
def create_block(value, block)
|
|
460
|
+
@block = block
|
|
447
461
|
if value && value.kind_of?(BindingBuilder)
|
|
448
462
|
@bindings = [value]
|
|
449
|
-
@block = ref_block
|
|
450
463
|
elsif value && value.kind_of?(AtomBuilder)
|
|
451
464
|
@child_atom_builders << value
|
|
452
465
|
@bindings = [BindingBuilder.new(value.tag)]
|
|
453
|
-
@block = ref_block
|
|
454
466
|
else
|
|
455
|
-
@
|
|
467
|
+
@value = value
|
|
456
468
|
end
|
|
457
469
|
end
|
|
458
470
|
end
|
|
459
471
|
|
|
460
472
|
class NotOperatorBuilder < AtomBuilder
|
|
473
|
+
NOT_PROC = lambda {|x,y| x != y}
|
|
461
474
|
def ==(value)
|
|
462
|
-
create_block value,
|
|
475
|
+
create_block value, NOT_PROC
|
|
476
|
+
self
|
|
463
477
|
end
|
|
464
478
|
end
|
|
465
479
|
|
data/lib/rulebook.rb
CHANGED
|
@@ -12,8 +12,6 @@
|
|
|
12
12
|
require 'ruleby'
|
|
13
13
|
require 'rule_helper'
|
|
14
14
|
require 'dsl/ferrari'
|
|
15
|
-
require 'dsl/letigre'
|
|
16
|
-
require 'dsl/steel'
|
|
17
15
|
|
|
18
16
|
module Ruleby
|
|
19
17
|
class Rulebook
|
|
@@ -36,15 +34,10 @@ module Ruleby
|
|
|
36
34
|
@engine.modify fact
|
|
37
35
|
end
|
|
38
36
|
def rule(*args, &block)
|
|
39
|
-
unless args.empty?
|
|
40
|
-
name = args[0].kind_of?(Symbol) ? args.shift : GeneratedTag.new
|
|
41
|
-
end
|
|
42
|
-
|
|
43
37
|
if args.empty?
|
|
44
|
-
|
|
45
|
-
r = Steel::RulebookHelper.new @engine
|
|
46
|
-
r.rule name, &block
|
|
38
|
+
raise 'Must provide arguments to rule'
|
|
47
39
|
else
|
|
40
|
+
name = args[0].kind_of?(Symbol) ? args.shift : GeneratedTag.new
|
|
48
41
|
i = args[0].kind_of?(Hash) ? 1 : 0
|
|
49
42
|
if [Array, Ruleby::Ferrari::OrBuilder, Ruleby::Ferrari::AndBuilder].include? args[i].class
|
|
50
43
|
# use ferrari DSL
|
metadata
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruleby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
prerelease:
|
|
5
|
-
version: 0.8
|
|
4
|
+
prerelease:
|
|
5
|
+
version: "0.8"
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
8
8
|
- Joe Kutner
|
|
@@ -11,7 +11,7 @@ autorequire:
|
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
13
|
|
|
14
|
-
date: 2011-06-
|
|
14
|
+
date: 2011-06-16 00:00:00 -05:00
|
|
15
15
|
default_executable:
|
|
16
16
|
dependencies: []
|
|
17
17
|
|
|
@@ -38,8 +38,6 @@ files:
|
|
|
38
38
|
- lib/core/patterns.rb
|
|
39
39
|
- lib/core/utils.rb
|
|
40
40
|
- lib/dsl/ferrari.rb
|
|
41
|
-
- lib/dsl/letigre.rb
|
|
42
|
-
- lib/dsl/steel.rb
|
|
43
41
|
- tests/test.rb
|
|
44
42
|
has_rdoc: true
|
|
45
43
|
homepage: http://ruleby.org
|
|
@@ -59,9 +57,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
59
57
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
60
58
|
none: false
|
|
61
59
|
requirements:
|
|
62
|
-
- - "
|
|
60
|
+
- - ">="
|
|
63
61
|
- !ruby/object:Gem::Version
|
|
64
|
-
version:
|
|
62
|
+
version: "0"
|
|
65
63
|
requirements: []
|
|
66
64
|
|
|
67
65
|
rubyforge_project: ruleby
|
data/lib/dsl/letigre.rb
DELETED
|
@@ -1,238 +0,0 @@
|
|
|
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
|
|
10
|
-
#
|
|
11
|
-
|
|
12
|
-
module Ruleby
|
|
13
|
-
module LeTigre
|
|
14
|
-
class RulebookHelper
|
|
15
|
-
|
|
16
|
-
def initialize(engine, rulebook)
|
|
17
|
-
@rulebook = rulebook
|
|
18
|
-
@engine = engine
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
attr_reader :engine
|
|
22
|
-
|
|
23
|
-
def rule(name, *args, &then_block)
|
|
24
|
-
if args.empty?
|
|
25
|
-
raise 'No conditions supplied.'
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
options = args[0].kind_of?(Hash) ? args.shift : {}
|
|
29
|
-
|
|
30
|
-
pb = PatternParser.new @rulebook
|
|
31
|
-
pattern = pb.parse args
|
|
32
|
-
|
|
33
|
-
rb = RuleBuilder.new name
|
|
34
|
-
|
|
35
|
-
rb.when(pattern)
|
|
36
|
-
rb.then(&then_block)
|
|
37
|
-
rb.priority = options[:priority] if options[:priority]
|
|
38
|
-
|
|
39
|
-
@engine.assert_rule rb.build_rule
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
class RuleBuilder
|
|
45
|
-
|
|
46
|
-
def initialize(name, pattern=nil, action=nil, priority=0)
|
|
47
|
-
@name = name
|
|
48
|
-
@pattern = pattern
|
|
49
|
-
@action = action
|
|
50
|
-
@priority = priority
|
|
51
|
-
|
|
52
|
-
@tags = {}
|
|
53
|
-
@when_counter = 0
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def when(pattern)
|
|
57
|
-
@pattern = pattern
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def then(&block)
|
|
61
|
-
@action = Core::Action.new(&block)
|
|
62
|
-
@action.name = @name
|
|
63
|
-
@action.priority = @priority
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def priority
|
|
67
|
-
return @priority
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def priority=(p)
|
|
71
|
-
@priority = p
|
|
72
|
-
@action.priority = @priority
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def build_rule
|
|
76
|
-
Core::Rule.new @name, @pattern, @action, @priority
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
class PatternParser
|
|
81
|
-
@@head_error = 'Invalid type specification.'
|
|
82
|
-
@@method_error = "No #method in expression: "
|
|
83
|
-
|
|
84
|
-
@@base_re = /(For each|\w*\s*exists\??|not\??)(.*)/
|
|
85
|
-
@@mode_re = /( (is a|kind of|instance of) )(.*)/
|
|
86
|
-
@@where_re = /(.*)where (.*)/
|
|
87
|
-
@@head_re = /(\w*)( as :(.*))?/
|
|
88
|
-
|
|
89
|
-
@@method_re = /#((\w|\d|\_)*)\??/
|
|
90
|
-
@@bind_re = /#:(\w*|\d*\_*)*/
|
|
91
|
-
@@and_re = /#&&/
|
|
92
|
-
@@tag_re = /(.*) as :(.*)/
|
|
93
|
-
|
|
94
|
-
def initialize(rulebook)
|
|
95
|
-
@rulebook = rulebook
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def parse(lhs_strs)
|
|
99
|
-
pattern = nil
|
|
100
|
-
lhs_strs.each do |lhs|
|
|
101
|
-
# match the quantifier
|
|
102
|
-
if lhs =~ @@base_re
|
|
103
|
-
base = $1
|
|
104
|
-
tail = $2
|
|
105
|
-
else
|
|
106
|
-
base = 'For each'
|
|
107
|
-
tail = lhs
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
raise 'The \'exists\' quantifier is not yet supported.' if base =~ /exists/
|
|
111
|
-
|
|
112
|
-
if tail =~ @@mode_re
|
|
113
|
-
mode = :inherits
|
|
114
|
-
tail = $3
|
|
115
|
-
else
|
|
116
|
-
mode = :equals
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
# check if there is a where clause
|
|
120
|
-
if tail =~ @@where_re
|
|
121
|
-
head = $1.strip
|
|
122
|
-
tail = $2
|
|
123
|
-
else
|
|
124
|
-
head = tail.strip
|
|
125
|
-
tail = nil
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
# match the class type and tag
|
|
129
|
-
if head != ''
|
|
130
|
-
head =~ @@head_re
|
|
131
|
-
clazz = @rulebook.__eval__ $1
|
|
132
|
-
tag = $3 ? $3.to_sym : GeneratedTag.new
|
|
133
|
-
else
|
|
134
|
-
clazz = Object
|
|
135
|
-
tag = GeneratedTag.new
|
|
136
|
-
mode = :inherits
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
deftemplate = Core::Template.new clazz, mode
|
|
140
|
-
head = Core::HeadAtom.new tag, deftemplate
|
|
141
|
-
|
|
142
|
-
atoms = []
|
|
143
|
-
atom_strs = tail ? tail.split(@@and_re) : []
|
|
144
|
-
atom_strs.each do |a|
|
|
145
|
-
# BUG we also need to pass in the head_tag with atoms!
|
|
146
|
-
atoms.push parse_atom(a, deftemplate, atoms)
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
if base =~ /not\??/
|
|
150
|
-
p = mode==:inherits ? Core::NotInheritsPattern.new(head, atoms) :
|
|
151
|
-
Core::NotPattern.new(head, atoms)
|
|
152
|
-
else
|
|
153
|
-
p = mode==:inherits ? Core::InheritsPattern.new(head, atoms) :
|
|
154
|
-
Core::ObjectPattern.new(head, atoms)
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
pattern = pattern ? Core::AndPattern.new(pattern, p) : p
|
|
158
|
-
end
|
|
159
|
-
return pattern
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
private
|
|
163
|
-
def parse_atom(str, deftemplate, atoms)
|
|
164
|
-
expression, tag = nil, nil
|
|
165
|
-
if str =~ @@tag_re
|
|
166
|
-
expression, tag = $1, $2.strip.to_sym
|
|
167
|
-
else
|
|
168
|
-
expression, tag = str, GeneratedTag.new
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
bindings = []
|
|
172
|
-
uniq_binds = []
|
|
173
|
-
expression.scan(@@bind_re).each do |b|
|
|
174
|
-
# HACK how can we create a truely unique variable name?
|
|
175
|
-
uniq_bind = "ruleby_unique_variable_name_#{b[0]}"
|
|
176
|
-
uniq_binds.push uniq_bind
|
|
177
|
-
expression.sub!(/#:#{b[0]}/, uniq_bind)
|
|
178
|
-
bindings.push b[0].strip.to_sym
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
raise @@method_error + expression unless expression =~ @@method_re
|
|
182
|
-
method = $1
|
|
183
|
-
expression.gsub!(/##{method}/, method)
|
|
184
|
-
expression = "true" if expression.strip == method
|
|
185
|
-
|
|
186
|
-
proc = "lambda {|#{method}"
|
|
187
|
-
|
|
188
|
-
uniq_binds.each do |b|
|
|
189
|
-
# TODO make sure 'b' is not equal to 'method' or other b's
|
|
190
|
-
proc += ",#{b}"
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
proc += "| #{expression} }"
|
|
194
|
-
|
|
195
|
-
block = eval proc
|
|
196
|
-
|
|
197
|
-
if bindings.empty?
|
|
198
|
-
return Core::PropertyAtom.new(tag, method, deftemplate, &block)
|
|
199
|
-
elsif references_self?(bindings, atoms)
|
|
200
|
-
bound_methods = resolve_bindings(bindings, atoms)
|
|
201
|
-
return Core::SelfReferenceAtom.new(tag, method, bound_methods, deftemplate, &block)
|
|
202
|
-
else
|
|
203
|
-
return Core::ReferenceAtom.new(tag, method, bindings, deftemplate, &block)
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
def references_self?(bindings, atoms)
|
|
208
|
-
ref_self = 0
|
|
209
|
-
bindings.each do |b|
|
|
210
|
-
atoms.each do |a|
|
|
211
|
-
if (a.tag == b)
|
|
212
|
-
ref_self += 1
|
|
213
|
-
end
|
|
214
|
-
end
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
if ref_self > 0 and ref_self != bindings.size
|
|
218
|
-
raise 'Binding to self and another pattern in the same expression is not yet supported.'
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
return ref_self > 0
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
def resolve_bindings(bindings, atoms)
|
|
225
|
-
bound_methods = []
|
|
226
|
-
bindings.each do |b|
|
|
227
|
-
atoms.each do |a|
|
|
228
|
-
if a.tag == b
|
|
229
|
-
bound_methods.push a.method
|
|
230
|
-
end
|
|
231
|
-
end
|
|
232
|
-
end
|
|
233
|
-
return bound_methods
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
end
|
|
237
|
-
end
|
|
238
|
-
end
|
data/lib/dsl/steel.rb
DELETED
|
@@ -1,314 +0,0 @@
|
|
|
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
|
|
10
|
-
#
|
|
11
|
-
|
|
12
|
-
module Ruleby
|
|
13
|
-
module Steel
|
|
14
|
-
class RulebookHelper
|
|
15
|
-
|
|
16
|
-
include Ruleby
|
|
17
|
-
def initialize(engine)
|
|
18
|
-
raise 'This DSL is deprecated'
|
|
19
|
-
@engine = engine
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
attr_reader :engine
|
|
23
|
-
|
|
24
|
-
def rule(name, &block)
|
|
25
|
-
r = Steel::RuleBuilder.new name
|
|
26
|
-
yield r if block_given?
|
|
27
|
-
@engine.assert_rule r.build_rule
|
|
28
|
-
r
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
class RuleBuilder
|
|
34
|
-
|
|
35
|
-
def initialize(name, pattern=nil, action=nil, priority=0)
|
|
36
|
-
@name = name
|
|
37
|
-
@pattern = pattern
|
|
38
|
-
@action = action
|
|
39
|
-
@priority = priority
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def when(&block)
|
|
43
|
-
wb = WhenBuilder.new
|
|
44
|
-
yield wb
|
|
45
|
-
@pattern = wb.pattern
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def then(&block)
|
|
49
|
-
@action = Core::Action.new(&block)
|
|
50
|
-
@action.name = @name
|
|
51
|
-
@action.priority = @priority
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def when=(pattern)
|
|
55
|
-
@pattern = pattern
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def then=(action)
|
|
59
|
-
@action = action
|
|
60
|
-
@action.name = @name
|
|
61
|
-
@action.priority = @priority
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def priority
|
|
65
|
-
return @priority
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def priority=(p)
|
|
69
|
-
@priority = p
|
|
70
|
-
@action.priority = @priority
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def build_rule
|
|
74
|
-
r = Ruleby::Core::Rule.new @name, @pattern, @action, @priority
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
class WhenBuilder #< RulebookHelper
|
|
79
|
-
def initialize()
|
|
80
|
-
@pattern_hash = Hash.new
|
|
81
|
-
@pattern_keys = []
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def method_missing(method_id, *args, &block)
|
|
85
|
-
method = method_id.to_sym
|
|
86
|
-
wi = nil
|
|
87
|
-
if @pattern_hash.key? method
|
|
88
|
-
wi = @pattern_hash[method]
|
|
89
|
-
elsif :not == method
|
|
90
|
-
@pattern_keys.push method
|
|
91
|
-
return self
|
|
92
|
-
else
|
|
93
|
-
wi = WhenInternal.new method, args[0]
|
|
94
|
-
@pattern_hash[method] = wi
|
|
95
|
-
@pattern_keys.push method
|
|
96
|
-
end
|
|
97
|
-
return wi
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def pattern
|
|
101
|
-
operands = []
|
|
102
|
-
nt = false
|
|
103
|
-
@pattern_keys.each do |key|
|
|
104
|
-
if :not != key
|
|
105
|
-
wi = @pattern_hash[key]
|
|
106
|
-
tag = wi.tag
|
|
107
|
-
type = wi.type
|
|
108
|
-
atoms = wi.to_atoms
|
|
109
|
-
p = nil
|
|
110
|
-
if nt
|
|
111
|
-
p = Ruleby::Core::NotPattern.new(tag, type, atoms)
|
|
112
|
-
nt = false
|
|
113
|
-
else
|
|
114
|
-
p = Ruleby::Core::ObjectPattern.new(tag, type, atoms)
|
|
115
|
-
end
|
|
116
|
-
operands = operands + [p]
|
|
117
|
-
else
|
|
118
|
-
nt = true
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
return and_pattern(operands)
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def and_pattern(operands)
|
|
125
|
-
# TODO raise exception if referenceAtoms from the right do not
|
|
126
|
-
# have the values they referenece in the left
|
|
127
|
-
# TODO raise exception if there are repeated tags?
|
|
128
|
-
left = nil
|
|
129
|
-
operands.each do |operand|
|
|
130
|
-
if left.nil?
|
|
131
|
-
left = operand
|
|
132
|
-
else
|
|
133
|
-
right = operand
|
|
134
|
-
left = Ruleby::Core::AndPattern.new(left, right)
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
left
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def or_pattern(operands)
|
|
141
|
-
# TODO raise exception if referenceAtoms from the right do not
|
|
142
|
-
# have the values they referenece in the left
|
|
143
|
-
# TODO raise exception if there are repeated tags?
|
|
144
|
-
left = nil
|
|
145
|
-
operands.each do |operand|
|
|
146
|
-
if left.nil?
|
|
147
|
-
left = operand
|
|
148
|
-
else
|
|
149
|
-
right = operand
|
|
150
|
-
left = Ruleby::Core::OrPattern.new(left, right)
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
left
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
class WhenInternal
|
|
158
|
-
public_instance_methods.each do |m|
|
|
159
|
-
a = [:method_missing, :new, :public_instance_methods, :__send__, :__id__]
|
|
160
|
-
undef_method m.to_sym unless a.include? m.to_sym
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
attr_reader :tag, :type
|
|
164
|
-
def initialize(tag, type)
|
|
165
|
-
@tag = tag
|
|
166
|
-
@type = type
|
|
167
|
-
@builder = WhenPropertyBuilder.new self
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
def to_atoms
|
|
171
|
-
atoms = []
|
|
172
|
-
tags = {@tag => :class}
|
|
173
|
-
@builder.property_hash.each_value do |wp|
|
|
174
|
-
tags[wp.tag] = wp.name if wp.tag
|
|
175
|
-
end
|
|
176
|
-
@builder.property_keys.each do |key|
|
|
177
|
-
wp = @builder.property_hash[key]
|
|
178
|
-
atoms = atoms + [wp.to_atom(tags)]
|
|
179
|
-
end
|
|
180
|
-
return atoms
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
def &
|
|
184
|
-
return self
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
def method_missing(method_id, *args, &block)
|
|
188
|
-
m = method_id.to_s
|
|
189
|
-
suffix = m.to_s[-1..-1]
|
|
190
|
-
if suffix == '='
|
|
191
|
-
new_m = m[0,m.size-1]
|
|
192
|
-
if args[0].class == Array && args[0].size > 1 && args[0][1] == :%
|
|
193
|
-
wp = @builder.create new_m do |x,y| x == y end
|
|
194
|
-
wp.references args[0][0]
|
|
195
|
-
return wp
|
|
196
|
-
else
|
|
197
|
-
wp = @builder.create new_m do |x| x == args[0] end
|
|
198
|
-
return wp
|
|
199
|
-
end
|
|
200
|
-
else
|
|
201
|
-
wp = @builder.create(m, &block)
|
|
202
|
-
if args.size > 0 && args[0]
|
|
203
|
-
if block_given?
|
|
204
|
-
wp.references args[0]
|
|
205
|
-
else
|
|
206
|
-
wp.tag = args[0]
|
|
207
|
-
end
|
|
208
|
-
end
|
|
209
|
-
return wp
|
|
210
|
-
end
|
|
211
|
-
end
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
class WhenPropertyBuilder
|
|
215
|
-
attr_reader:property_hash
|
|
216
|
-
attr_reader:property_keys
|
|
217
|
-
|
|
218
|
-
def initialize(parent)
|
|
219
|
-
@parent = parent
|
|
220
|
-
@property_hash = Hash.new
|
|
221
|
-
@property_keys = []
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
def create(method_id,&block)
|
|
225
|
-
method = method_id.to_sym
|
|
226
|
-
wp = nil
|
|
227
|
-
if @property_hash.key? method
|
|
228
|
-
wp = @property_hash[method]
|
|
229
|
-
else
|
|
230
|
-
wp = WhenProperty.new @parent, method do |p| true end
|
|
231
|
-
@property_hash[method] = wp
|
|
232
|
-
@property_keys.push method
|
|
233
|
-
end
|
|
234
|
-
if block_given?
|
|
235
|
-
wp.block = block
|
|
236
|
-
end
|
|
237
|
-
return wp
|
|
238
|
-
end
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
class WhenProperty
|
|
242
|
-
|
|
243
|
-
def initialize(parent,name, &block)
|
|
244
|
-
@tag = nil
|
|
245
|
-
@name = name
|
|
246
|
-
@references = nil
|
|
247
|
-
@block = block
|
|
248
|
-
@parent = parent
|
|
249
|
-
end
|
|
250
|
-
attr:tag,true
|
|
251
|
-
attr:type,true
|
|
252
|
-
attr:value,true
|
|
253
|
-
attr_reader:name
|
|
254
|
-
attr_accessor:block
|
|
255
|
-
|
|
256
|
-
def &
|
|
257
|
-
return @parent
|
|
258
|
-
end
|
|
259
|
-
|
|
260
|
-
def bind(n)
|
|
261
|
-
@tag = n
|
|
262
|
-
end
|
|
263
|
-
|
|
264
|
-
def not=(value,ref=nil)
|
|
265
|
-
if ref && ref == :%
|
|
266
|
-
raise 'Using \'not=\' for references is not yet supported'
|
|
267
|
-
set_block do |x,y| x != y end
|
|
268
|
-
references value
|
|
269
|
-
else
|
|
270
|
-
set_block do |s| s != value end
|
|
271
|
-
end
|
|
272
|
-
|
|
273
|
-
end
|
|
274
|
-
def set_block(&block)
|
|
275
|
-
@block = block
|
|
276
|
-
end
|
|
277
|
-
private:set_block
|
|
278
|
-
|
|
279
|
-
def references(refs)
|
|
280
|
-
@references = refs
|
|
281
|
-
end
|
|
282
|
-
|
|
283
|
-
def to_atom(pattern_tags)
|
|
284
|
-
unless @tag
|
|
285
|
-
@tag = GeneratedTag.new
|
|
286
|
-
end
|
|
287
|
-
if @references
|
|
288
|
-
@references = [@references] unless @references.kind_of?(Array)
|
|
289
|
-
i = includes_how_many(@references, pattern_tags.keys)
|
|
290
|
-
if i == 0
|
|
291
|
-
return Ruleby::Core::ReferenceAtom.new(@tag, @name, @references, @parent.type, &@block)
|
|
292
|
-
elsif i == @references.size
|
|
293
|
-
refs = @references.collect{|r| pattern_tags[r] }
|
|
294
|
-
return Ruleby::Core::SelfReferenceAtom.new(@tag, @name, refs, @parent.type, &@block)
|
|
295
|
-
else
|
|
296
|
-
raise 'Referencing self AND other patterns in the same atom is not yet supported'
|
|
297
|
-
end
|
|
298
|
-
else
|
|
299
|
-
return Ruleby::Core::PropertyAtom.new(@tag, @name, @parent.type, &@block)
|
|
300
|
-
end
|
|
301
|
-
end
|
|
302
|
-
|
|
303
|
-
private
|
|
304
|
-
def includes_how_many(list1, list2)
|
|
305
|
-
i = 0
|
|
306
|
-
list2.each do |a|
|
|
307
|
-
i += 1 if list1.include?(a)
|
|
308
|
-
end
|
|
309
|
-
return i
|
|
310
|
-
end
|
|
311
|
-
end
|
|
312
|
-
|
|
313
|
-
end
|
|
314
|
-
end
|