ruleby 0.9.b4 → 0.9.b7

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.
Files changed (48) hide show
  1. data/.gitignore +5 -0
  2. data/GPL.txt +341 -0
  3. data/LICENSE.txt +52 -0
  4. data/README.markdown +22 -0
  5. data/benchmarks/basic_rules.rb +61 -0
  6. data/benchmarks/joined_rules.rb +66 -0
  7. data/benchmarks/miss_manners/data.rb +146 -0
  8. data/benchmarks/miss_manners/miss_manners.rb +33 -0
  9. data/benchmarks/miss_manners/model.rb +193 -0
  10. data/benchmarks/miss_manners/rules.rb +105 -0
  11. data/benchmarks/model.rb +36 -0
  12. data/examples/diagnosis.rb +129 -0
  13. data/examples/fibonacci_example1.rb +44 -0
  14. data/examples/fibonacci_example2.rb +40 -0
  15. data/examples/fibonacci_example3.rb +78 -0
  16. data/examples/fibonacci_rulebook.rb +84 -0
  17. data/examples/hello.rb +45 -0
  18. data/examples/ticket.rb +113 -0
  19. data/examples/wordgame.rb +107 -0
  20. data/lib/core/engine.rb +26 -24
  21. data/lib/core/nodes.rb +77 -35
  22. data/lib/ruleby.rb +0 -37
  23. data/ruleby.gemspec +17 -0
  24. data/spec/and_or_spec.rb +252 -0
  25. data/spec/coercion_spec.rb +5 -0
  26. data/spec/collect_spec.rb +1021 -0
  27. data/spec/errors_spec.rb +148 -0
  28. data/spec/ferrari_spec.rb +39 -0
  29. data/spec/function_spec.rb +199 -0
  30. data/spec/hello_spec.rb +34 -0
  31. data/spec/node_sharing_spec.rb +53 -0
  32. data/spec/property_spec.rb +69 -0
  33. data/spec/spec.opts +4 -0
  34. data/spec/spec_helper.rb +9 -0
  35. data/tasks/documentation.rake +32 -0
  36. data/tasks/rspec.rake +21 -0
  37. data/tasks/test.rake +9 -0
  38. data/tests/assert_facts.rb +130 -0
  39. data/tests/common.rb +29 -0
  40. data/tests/duck_type.rb +79 -0
  41. data/tests/gets.rb +48 -0
  42. data/tests/join_nodes.rb +63 -0
  43. data/tests/nil.rb +72 -0
  44. data/tests/not_patterns.rb +91 -0
  45. data/tests/or_patterns.rb +154 -0
  46. data/tests/regex.rb +47 -0
  47. data/tests/self_reference.rb +54 -0
  48. metadata +81 -49
@@ -0,0 +1,66 @@
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
+
12
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '../lib/')
13
+ require 'ruleby'
14
+ require 'model'
15
+
16
+ include Ruleby
17
+
18
+ class TestRulebook < Rulebook
19
+ def rules(n)
20
+ (1..n).each do |index|
21
+ rule "Rule-#{index}".to_sym,
22
+ [Account, :acc,
23
+ method.status == 'standard',
24
+ {method.account_id => :id}
25
+ ],
26
+ [Address, :addr,
27
+ method.addr_id == b(:id),
28
+ method.city == 'Foobar',
29
+ method.state == 'FB',
30
+ method.zip == '12345'],
31
+ &lambda {|vars| }
32
+ end
33
+ end
34
+ end
35
+
36
+ def run_benchmark(rules,facts)
37
+ puts "running benchmark for: #{rules} rules and #{facts} facts"
38
+
39
+ t1 = Time.new
40
+ engine :engine do |e|
41
+ TestRulebook.new(e).rules(rules)
42
+
43
+ t2 = Time.new
44
+ diff = t2.to_f - t1.to_f
45
+ puts 'time to create rule set: ' + diff.to_s
46
+ #e.print
47
+ for k in (1..facts)
48
+ e.assert Account.new('standard', nil, "acc#{k}")
49
+ e.assert Address.new("acc#{k}",'Foobar', 'FB', '12345')
50
+ end
51
+ #exit(0)
52
+ t3 = Time.new
53
+ diff = t3.to_f - t2.to_f
54
+ puts 'time to assert facts: ' + diff.to_s
55
+
56
+ e.match
57
+
58
+ t4 = Time.new
59
+ diff = t4.to_f - t3.to_f
60
+ puts 'time to run agenda: ' + diff.to_s
61
+ end
62
+ end
63
+
64
+ run_benchmark(5, 50)
65
+ puts '-------'
66
+ run_benchmark(50, 50)
@@ -0,0 +1,146 @@
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
+
12
+ module MissManners
13
+ class MannersData
14
+ def initialize
15
+ @guests16 = [
16
+ Guest.new(:n1, :f, :h3),
17
+ Guest.new(:n1, :f, :h1),
18
+ Guest.new(:n1, :f, :h2),
19
+ Guest.new(:n2, :f, :h3),
20
+ Guest.new(:n2, :f, :h2),
21
+ Guest.new(:n3, :m, :h1),
22
+ Guest.new(:n3, :m, :h3),
23
+ Guest.new(:n4, :m, :h2),
24
+ Guest.new(:n4, :m, :h1),
25
+ Guest.new(:n5, :m, :h2),
26
+ Guest.new(:n5, :m, :h3),
27
+ Guest.new(:n6, :m, :h2),
28
+ Guest.new(:n6, :m, :h1),
29
+ Guest.new(:n7, :f, :h2),
30
+ Guest.new(:n7, :f, :h1),
31
+ Guest.new(:n7, :f, :h3),
32
+ Guest.new(:n8, :f, :h3),
33
+ Guest.new(:n8, :f, :h2),
34
+ Guest.new(:n9, :f, :h1),
35
+ Guest.new(:n9, :f, :h3),
36
+ Guest.new(:n9, :f, :h2),
37
+ Guest.new(:n10, :m, :h2),
38
+ Guest.new(:n10, :m, :h3),
39
+ Guest.new(:n11, :m, :h3),
40
+ Guest.new(:n11, :m, :h2),
41
+ Guest.new(:n11, :m, :h1),
42
+ Guest.new(:n12, :m, :h3),
43
+ Guest.new(:n12, :m, :h1),
44
+ Guest.new(:n13, :m, :h2),
45
+ Guest.new(:n13, :m, :h3),
46
+ Guest.new(:n13, :m, :h1),
47
+ Guest.new(:n14, :f, :h3),
48
+ Guest.new(:n14, :f, :h1),
49
+ Guest.new(:n15, :f, :h3),
50
+ Guest.new(:n15, :f, :h2),
51
+ Guest.new(:n15, :f, :h1),
52
+ Guest.new(:n16, :f, :h3),
53
+ Guest.new(:n16, :f, :h2),
54
+ Guest.new(:n16, :f, :h1),
55
+ LastSeat.new(16)]
56
+
57
+ @guests32 = [
58
+ Guest.new(:n1, :m, :h1),
59
+ Guest.new(:n1, :m, :h3),
60
+ Guest.new(:n2, :f, :h3),
61
+ Guest.new(:n2, :f, :h2),
62
+ Guest.new(:n2, :f, :h1),
63
+ Guest.new(:n3, :f, :h1),
64
+ Guest.new(:n3, :f, :h2),
65
+ Guest.new(:n4, :f, :h3),
66
+ Guest.new(:n4, :f, :h1),
67
+ Guest.new(:n5, :f, :h1),
68
+ Guest.new(:n5, :f, :h2),
69
+ Guest.new(:n6, :m, :h1),
70
+ Guest.new(:n6, :m, :h2),
71
+ Guest.new(:n6, :m, :h3),
72
+ Guest.new(:n7, :f, :h2),
73
+ Guest.new(:n7, :f, :h1),
74
+ Guest.new(:n7, :f, :h3),
75
+ Guest.new(:n8, :f, :h1),
76
+ Guest.new(:n8, :f, :h3),
77
+ Guest.new(:n8, :f, :h2),
78
+ Guest.new(:n9, :f, :h1),
79
+ Guest.new(:n9, :f, :h3),
80
+ Guest.new(:n9, :f, :h2),
81
+ Guest.new(:n10, :m, :h2),
82
+ Guest.new(:n10, :m, :h1),
83
+ Guest.new(:n11, :m, :h2),
84
+ Guest.new(:n11, :m, :h1),
85
+ Guest.new(:n12, :m, :h3),
86
+ Guest.new(:n12, :m, :h2),
87
+ Guest.new(:n13, :m, :h1),
88
+ Guest.new(:n13, :m, :h3),
89
+ Guest.new(:n14, :m, :h3),
90
+ Guest.new(:n14, :m, :h2),
91
+ Guest.new(:n15, :f, :h2),
92
+ Guest.new(:n15, :f, :h1),
93
+ Guest.new(:n15, :f, :h3),
94
+ Guest.new(:n16, :f, :h3),
95
+ Guest.new(:n16, :f, :h2),
96
+ Guest.new(:n16, :f, :h1),
97
+ Guest.new(:n17, :m, :h3),
98
+ Guest.new(:n17, :m, :h2),
99
+ Guest.new(:n18, :f, :h2),
100
+ Guest.new(:n18, :f, :h1),
101
+ Guest.new(:n19, :f, :h1),
102
+ Guest.new(:n19, :f, :h2),
103
+ Guest.new(:n19, :f, :h3),
104
+ Guest.new(:n20, :f, :h1),
105
+ Guest.new(:n20, :f, :h2),
106
+ Guest.new(:n20, :f, :h3),
107
+ Guest.new(:n21, :m, :h2),
108
+ Guest.new(:n21, :m, :h3),
109
+ Guest.new(:n21, :m, :h1),
110
+ Guest.new(:n22, :f, :h1),
111
+ Guest.new(:n22, :f, :h2),
112
+ Guest.new(:n22, :f, :h3),
113
+ Guest.new(:n23, :f, :h3),
114
+ Guest.new(:n23, :f, :h1),
115
+ Guest.new(:n23, :f, :h2),
116
+ Guest.new(:n24, :m, :h1),
117
+ Guest.new(:n24, :m, :h3),
118
+ Guest.new(:n25, :f, :h3),
119
+ Guest.new(:n25, :f, :h2),
120
+ Guest.new(:n25, :f, :h1),
121
+ Guest.new(:n26, :f, :h3),
122
+ Guest.new(:n26, :f, :h2),
123
+ Guest.new(:n26, :f, :h1),
124
+ Guest.new(:n27, :m, :h3),
125
+ Guest.new(:n27, :m, :h1),
126
+ Guest.new(:n27, :m, :h2),
127
+ Guest.new(:n28, :m, :h3),
128
+ Guest.new(:n28, :m, :h1),
129
+ Guest.new(:n29, :m, :h3),
130
+ Guest.new(:n29, :m, :h2),
131
+ Guest.new(:n29, :m, :h1),
132
+ Guest.new(:n30, :m, :h2),
133
+ Guest.new(:n30, :m, :h1),
134
+ Guest.new(:n30, :m, :h3),
135
+ Guest.new(:n31, :m, :h2),
136
+ Guest.new(:n31, :m, :h1),
137
+ Guest.new(:n32, :m, :h1),
138
+ Guest.new(:n32, :m, :h3),
139
+ Guest.new(:n32, :m, :h2),
140
+ LastSeat.new(32)]
141
+ end
142
+
143
+ attr_reader :guests16
144
+ attr_reader :guests32
145
+ end
146
+ end
@@ -0,0 +1,33 @@
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
+
12
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '../../lib/')
13
+ require 'ruleby'
14
+ require 'model'
15
+ require 'data'
16
+ require 'rules'
17
+
18
+ include Ruleby
19
+ include MissManners
20
+
21
+ t1 = Time.new
22
+ engine :e do |e|
23
+ MannersRulebook.new(e).rules
24
+ MannersData.new.guests16.each do |g|
25
+ e.assert g
26
+ end
27
+ e.assert Context.new(:start)
28
+ e.assert Count.new(1)
29
+ e.match
30
+ end
31
+ t2 = Time.new
32
+ diff = t2.to_f - t1.to_f
33
+ puts diff.to_s
@@ -0,0 +1,193 @@
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
+
12
+ module MissManners
13
+
14
+ class Chosen
15
+ def initialize(id,guestName,hobby)
16
+ @id = id
17
+ @guestName = guestName
18
+ @hobby = hobby
19
+ end
20
+ attr_reader :id, :guestName, :hobby
21
+ def to_s
22
+ "{Chosen id=#{@id}, name=#{@guestName}, hobbies=#{@hobby}}"
23
+ end
24
+ end
25
+
26
+ class Context
27
+ START_UP = 0
28
+ ASSIGN_SEATS = 1
29
+ MAKE_PATH = 2
30
+ CHECK_DONE = 3
31
+ PRINT_RESULTS = 4
32
+ STATE_STRINGS = ["START_UP","ASSIGN_SEATS","MAKE_PATH","CHECK_DONE","PRINT_RESULTS"]
33
+ def initialize(state)
34
+ if state == :start
35
+ @state = START_UP
36
+ else
37
+ raise "Context #{state.to_s} does not exist for Context Enum"
38
+ end
39
+ end
40
+ attr :state, true
41
+ def string_value
42
+ return STATE_STRINGS[@state]
43
+ end
44
+ def is_state(state)
45
+ return @state == state
46
+ end
47
+ def to_s
48
+ return "[Context state=" + string_value.to_s + "]";
49
+ end
50
+ end
51
+
52
+ class Count
53
+ def initialize(value)
54
+ @value = value
55
+ end
56
+ attr :value, true
57
+ def ==(object)
58
+ if object.object_id == self.object_id
59
+ return true
60
+ elsif object == nil || !(object.kind_of?(Count))
61
+ return false
62
+ end
63
+ return @value == object.value;
64
+ end
65
+ def to_s
66
+ return "[Count value=#{@value.to_s}]"
67
+ end
68
+ def to_hash
69
+ return value.to_hash
70
+ end
71
+ end
72
+
73
+ class Guest
74
+ def initialize(name,sex,hobby)
75
+ @name = name
76
+ @sex = sex
77
+ @hobby = hobby
78
+ end
79
+ attr_reader :name,:sex,:hobby
80
+ def to_s
81
+ return "[Guest name=" + @name.to_s + ", sex=" + @sex.to_s + ", hobbies=" + @hobby.to_s + "]";
82
+ end
83
+ end
84
+
85
+ class Hobby
86
+ @stringH1 = "h1"
87
+ @stringH2 = "h2"
88
+ @stringH3 = "h3"
89
+ @stringH4 = "h4"
90
+ @stringH5 = "h5"
91
+ HOBBY_STRINGS = [@stringH1,@stringH2,@stringH3,@stringH4,@stringH5]
92
+ def initialize(hobby)
93
+ @hobbyIndex = hobby-1
94
+ @hobby = HOBBY_STRINGS[@hobbyIndex]
95
+ end
96
+ H1 = Hobby.new(1)
97
+ H2 = Hobby.new(2)
98
+ H3 = Hobby.new(3)
99
+ H4 = Hobby.new(4)
100
+ H5 = Hobby.new(5)
101
+ attr_reader :hobby
102
+ def resolve(hobby)
103
+ if @stringH1 == hobby
104
+ return H1
105
+ elsif @stringH2 == hobby
106
+ return H2
107
+ elsif @stringH3 == hobby
108
+ return H3
109
+ elsif @stringH4 == hobby
110
+ return H4
111
+ elsif @stringH5 == hobby
112
+ return H5
113
+ else
114
+ raise "Hobby '" + @hobby.to_s + "' does not exist for Hobby Enum"
115
+ end
116
+ end
117
+ def to_hash
118
+ return @hobbyIndex.to_hash
119
+ end
120
+ def to_s
121
+ return @hobby
122
+ end
123
+ end
124
+
125
+ class LastSeat
126
+ def initialize(seat)
127
+ @seat = seat
128
+ end
129
+ attr_reader :seat
130
+ def to_s
131
+ return "[LastSeat seat=#{@seat.to_s}]"
132
+ end
133
+ end
134
+
135
+ class Path
136
+ def initialize(id,seat,guestName)
137
+ @id = id
138
+ @guestName = guestName
139
+ @seat = seat
140
+ end
141
+ attr_reader :id, :guestName, :seat
142
+ def to_s
143
+ "[Path id=#{@id.to_s}, name=#{@guestName.to_s}, seat=#{@seat.to_s}]"
144
+ end
145
+ end
146
+
147
+ class Seating
148
+ def initialize(id,pid,path,leftSeat,leftGuestName,rightSeat,rightGuestName)
149
+ @id = id
150
+ @pid = pid
151
+ @path = path
152
+ @leftSeat = leftSeat
153
+ @leftGuestName = leftGuestName
154
+ @rightSeat = rightSeat
155
+ @rightGuestName = rightGuestName
156
+ end
157
+ attr :path, true
158
+ attr_reader :id,:pid,:leftSeat,:leftGuestName,:rightSeat,:rightGuestName
159
+ def to_s
160
+ return "[Seating id=#{@id.to_s} , pid=#{pid.to_s} , pathDone=#{@path.to_s} , leftSeat=#{@leftSeat.to_s}, leftGuestName=#{@leftGuestName.to_s}, rightSeat=#{@rightSeat.to_s}, rightGuestName=#{@rightGuestName.to_s}]";
161
+ end
162
+ end
163
+
164
+ class Sex
165
+ STRING_M = 'm'
166
+ STRING_F = 'f'
167
+ SEX_LIST = [ STRING_M, STRING_F ]
168
+ def initialize(sex)
169
+ @sex = sex
170
+ end
171
+ M = Sex.new( 0 )
172
+ F = Sex.new( 1 )
173
+ def sex
174
+ return SEX_LIST[sex]
175
+ end
176
+ def resolve(sex)
177
+ if STRING_M == sex
178
+ return M
179
+ elsif STRING_F == sex
180
+ return F
181
+ else
182
+ raise "Sex '#{@sex.to_s}' does not exist for Sex Enum"
183
+ end
184
+ end
185
+ def to_s
186
+ return @sex.to_s
187
+ end
188
+ def to_hash
189
+ return @sex.to_hash
190
+ end
191
+ end
192
+
193
+ end
@@ -0,0 +1,105 @@
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
+
12
+ require 'model'
13
+
14
+ module MissManners
15
+
16
+ class MannersRulebook < Ruleby::Rulebook
17
+ def rules
18
+ rule :assignFirstSeat,
19
+ [Context,:context, m.state == Context::START_UP],
20
+ [Guest,:guest],
21
+ [Count,:count] do |vars|
22
+ guestName = vars[:guest].name
23
+ seating = Seating.new(vars[:count].value,1,true,1,guestName,1,guestName)
24
+ assert seating
25
+ path = Path.new(vars[:count].value, 1, guestName)
26
+ assert path
27
+ retract vars[:count]
28
+ vars[:count].value = vars[:count].value + 1
29
+ assert vars[:count]
30
+ puts "assign first seat : #{seating.to_s} : #{path.to_s}"
31
+ vars[:context].state = Context::ASSIGN_SEATS
32
+ modify vars[:context]
33
+ end
34
+
35
+ rule :findSeating,
36
+ [Context,:context, {m.state == Context::ASSIGN_SEATS => :state}],
37
+ [Count,:count, {m.value => :countValue}],
38
+ [Seating,:seating, {m.path == true =>:p, m.id=>:seatingId, m.pid=>:seatingPid, m.rightSeat=>:seatingRightSeat, m.rightGuestName=>:seatingRightGuestName}],
39
+ [Guest,:g, {m.name=>:name, m.sex=>:rightGuestSex, m.hobby=>:rightGuestHobby}, m.name == b(:seatingRightGuestName)],
40
+ [Guest,:lg, {m.name=>:leftGuestName, m.sex=>:sex, m.hobby == b(:rightGuestHobby) => :hobby}, m.sex(:rightGuestSex, &c{|s,rgs| s != rgs} )],
41
+ [:~,Path, m.id == b(:seatingId), m.guestName == b(:leftGuestName)],
42
+ [:~,Chosen, m.id == b(:seatingId), m.guestName == b(:leftGuestName), m.hobby == b(:leftGuestHobby)] do |vars|
43
+ rightSeat = vars[:seatingRightSeat]
44
+ seatId = vars[:seatingId]
45
+ countValue = vars[:count].value
46
+ seating = Seating.new(countValue,seatId,false,rightSeat,vars[:seatingRightGuestName],rightSeat+1,vars[:leftGuestName])
47
+ path = Path.new(countValue,rightSeat+1,vars[:leftGuestName])
48
+ chosen = Chosen.new(seatId, vars[:leftGuestName], vars[:rightGuestHobby] )
49
+ puts "find seating : #{seating} : #{path} : #{chosen}"
50
+ assert seating
51
+ assert path
52
+ assert chosen
53
+ vars[:count].value = countValue + 1
54
+ modify vars[:count]
55
+ vars[:context].state = Context::MAKE_PATH
56
+ modify vars[:context]
57
+ end
58
+
59
+ rule :makePath,
60
+ [Context,:context, {m.state == Context::MAKE_PATH => :s}],
61
+ [Seating,:seating, {m.id=>:seatingId, m.pid=>:seatingPid, m.path == false =>:p}],
62
+ [Path,:path, {m.guestName=>:pathGuestName, m.seat=>:pathSeat}, m.id == b(:seatingPid)],
63
+ [:~,Path,m.id == b(:seatingId), m.guestName == b(:pathGuestName)] do |vars|
64
+ path = Path.new(vars[:seatingId],vars[:pathSeat],vars[:pathGuestName])
65
+ assert path
66
+ puts "make Path : #{path}"
67
+ end
68
+
69
+ # NOTE We had to add the priority because Ruleby's conflict resolution strategy
70
+ # is not robust enough. If it worked like CLIPS, the priority would not
71
+ # be nessecary because the 'make path' activations would have more
72
+ # recent facts supporting it. This is really an error in the Miss Manners
73
+ # benchmark, so it is not considered cheating.
74
+ rule :pathDone, {:priority => -5},
75
+ [Context,:context, m.state == Context::MAKE_PATH],
76
+ [Seating,:seating, m.path == false] do |vars|
77
+ vars[:seating].path = true
78
+ modify vars[:seating]
79
+ vars[:context].state = Context::CHECK_DONE
80
+ modify vars[:context]
81
+ puts "path Done : #{vars[:seating]}"
82
+ end
83
+
84
+ rule :areWeDone,
85
+ [Context,:context, m.state == Context::CHECK_DONE],
86
+ [LastSeat,:ls, {m.seat => :lastSeat}],
87
+ [Seating,:seating, m.rightSeat == b(:lastSeat)] do |vars|
88
+ vars[:context].state = Context::PRINT_RESULTS
89
+ modify vars[:context]
90
+ end
91
+
92
+ rule :continue, {:priority => -5},
93
+ [Context,:context,m.state == Context::CHECK_DONE] do |vars|
94
+ vars[:context].state = Context::ASSIGN_SEATS
95
+ modify vars[:context]
96
+ end
97
+
98
+ rule :allDone,
99
+ [Context,:context,m.state == Context::PRINT_RESULTS] do |vars|
100
+ puts 'All done'
101
+ end
102
+ end
103
+ end
104
+
105
+ end