porolog 0.0.4 → 1.0.0
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.
- checksums.yaml +4 -4
- data/README.md +30 -5
- data/Rakefile +7 -2
- data/bin/porolog +58 -1
- data/coverage/badge.svg +1 -1
- data/coverage/index.html +76733 -2638
- data/doc/Array.html +1066 -0
- data/doc/Object.html +674 -0
- data/doc/Porolog.html +4153 -74
- data/doc/Symbol.html +501 -0
- data/doc/_index.html +280 -6
- data/doc/class_list.html +1 -1
- data/doc/file.README.html +34 -39
- data/doc/index.html +34 -39
- data/doc/method_list.html +1337 -57
- data/doc/top-level-namespace.html +4 -2
- data/lib/porolog.rb +1144 -4
- data/lib/porolog/arguments.rb +28 -24
- data/lib/porolog/core_ext.rb +188 -0
- data/lib/porolog/error.rb +9 -0
- data/lib/porolog/goal.rb +357 -0
- data/lib/porolog/instantiation.rb +346 -0
- data/lib/porolog/predicate.rb +74 -31
- data/lib/porolog/predicate/builtin.rb +825 -0
- data/lib/porolog/rule.rb +162 -0
- data/lib/porolog/scope.rb +4 -4
- data/lib/porolog/tail.rb +57 -0
- data/lib/porolog/value.rb +105 -0
- data/lib/porolog/variable.rb +325 -0
- data/test/porolog/arguments_test.rb +244 -195
- data/test/porolog/core_ext_test.rb +290 -0
- data/test/porolog/goal_test.rb +891 -0
- data/test/porolog/instantiation_test.rb +910 -0
- data/test/porolog/porolog_test.rb +2376 -13
- data/test/porolog/predicate/builtin_test.rb +1340 -0
- data/test/porolog/predicate_test.rb +84 -30
- data/test/porolog/rule_test.rb +527 -0
- data/test/porolog/scope_test.rb +0 -2
- data/test/porolog/tail_test.rb +127 -0
- data/test/porolog/value_test.rb +315 -0
- data/test/porolog/variable_test.rb +1614 -0
- data/test/samples_test.rb +277 -0
- data/test/test_helper.rb +115 -0
- metadata +34 -7
@@ -0,0 +1,290 @@
|
|
1
|
+
#
|
2
|
+
# test/porolog/core_ext_test.rb - Test Suite for Core Extensions
|
3
|
+
#
|
4
|
+
# Luis Esteban 2 May 2018
|
5
|
+
# created
|
6
|
+
#
|
7
|
+
|
8
|
+
require_relative '../test_helper'
|
9
|
+
|
10
|
+
describe 'Object' do
|
11
|
+
|
12
|
+
let (:object1) { Object.new }
|
13
|
+
let (:object2) { 42 }
|
14
|
+
let (:object3) { { name: 'hello' } }
|
15
|
+
let (:object4) { 'abc' }
|
16
|
+
let (:object5) { 0.5 }
|
17
|
+
|
18
|
+
describe '#myid' do
|
19
|
+
|
20
|
+
it 'should return inspect' do
|
21
|
+
assert_equal object1.inspect, object1.myid
|
22
|
+
assert_equal object2.inspect, object2.myid
|
23
|
+
assert_equal object3.inspect, object3.myid
|
24
|
+
assert_equal object4.inspect, object4.myid
|
25
|
+
assert_equal object5.inspect, object5.myid
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#variables' do
|
31
|
+
|
32
|
+
it 'should return empty array' do
|
33
|
+
assert_equal [], object1.variables
|
34
|
+
assert_equal [], object2.variables
|
35
|
+
assert_equal [], object3.variables
|
36
|
+
assert_equal [], object4.variables
|
37
|
+
assert_equal [], object5.variables
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#type' do
|
43
|
+
|
44
|
+
it 'should return :atomic for atomic types' do
|
45
|
+
assert_equal :atomic, object1.type
|
46
|
+
assert_equal :atomic, object2.type
|
47
|
+
assert_equal :atomic, object3.type
|
48
|
+
assert_equal :atomic, object4.type
|
49
|
+
assert_equal :atomic, object5.type
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#/' do
|
55
|
+
|
56
|
+
it 'should create an n Array with a Tail' do
|
57
|
+
assert_Array_with_Tail object1 / :T, [object1], '*:T'
|
58
|
+
assert_Array_with_Tail [object2] / :T, [object2], '*:T'
|
59
|
+
#assert_Array_with_Tail object2.tail(:T), [object2], '*:T'
|
60
|
+
assert_Array_with_Tail object3 / :T, [object3], '*:T'
|
61
|
+
assert_Array_with_Tail object4 / :T, [object4], '*:T'
|
62
|
+
assert_Array_with_Tail [object5] / :T, [object5], '*:T'
|
63
|
+
#assert_Array_with_Tail object5.tail(:T), [object5], '*:T'
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
describe 'Symbol' do
|
71
|
+
|
72
|
+
let (:symbol1) { :alpha }
|
73
|
+
let (:symbol2) { :_ }
|
74
|
+
let (:symbol3) { :'with some spaces' }
|
75
|
+
let (:symbol4) { :X }
|
76
|
+
let (:symbol5) { :p }
|
77
|
+
|
78
|
+
describe '#myid' do
|
79
|
+
|
80
|
+
it 'should return inspect' do
|
81
|
+
assert_equal symbol1.inspect, symbol1.myid
|
82
|
+
assert_equal symbol2.inspect, symbol2.myid
|
83
|
+
assert_equal symbol3.inspect, symbol3.myid
|
84
|
+
assert_equal symbol4.inspect, symbol4.myid
|
85
|
+
assert_equal symbol5.inspect, symbol5.myid
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
describe '#variables' do
|
91
|
+
|
92
|
+
it 'should return an array of itself' do
|
93
|
+
assert_equal [symbol1], symbol1.variables
|
94
|
+
assert_equal [symbol2], symbol2.variables
|
95
|
+
assert_equal [symbol3], symbol3.variables
|
96
|
+
assert_equal [symbol4], symbol4.variables
|
97
|
+
assert_equal [symbol5], symbol5.variables
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
describe '#type' do
|
103
|
+
|
104
|
+
it 'should return :variable for symbols' do
|
105
|
+
assert_equal :variable, symbol1.type
|
106
|
+
assert_equal :variable, symbol2.type
|
107
|
+
assert_equal :variable, symbol3.type
|
108
|
+
assert_equal :variable, symbol4.type
|
109
|
+
assert_equal :variable, symbol5.type
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
describe '#/' do
|
115
|
+
|
116
|
+
it 'should create a HeadTail' do
|
117
|
+
assert_Array_with_Tail symbol1 / :T, [symbol1], '*:T'
|
118
|
+
assert_Array_with_Tail symbol2 / :T, [symbol2], '*:T'
|
119
|
+
assert_Array_with_Tail symbol3 / :T, [symbol3], '*:T'
|
120
|
+
assert_Array_with_Tail symbol4 / :T, [symbol4], '*:T'
|
121
|
+
assert_Array_with_Tail symbol5 / :T, [symbol5], '*:T'
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
describe 'Array' do
|
129
|
+
|
130
|
+
let(:array1) { [1, 2, :A, 4, [:B, 6, 7, :C], 9] }
|
131
|
+
let(:array2) { [] }
|
132
|
+
let(:array3) { UNKNOWN_ARRAY }
|
133
|
+
let(:array4) { [1, :B, 3, UNKNOWN_TAIL] }
|
134
|
+
|
135
|
+
describe '#/' do
|
136
|
+
|
137
|
+
it 'creates an Array using the slash notation with Arrays' do
|
138
|
+
head_tail = [1] / [2,3,4,5]
|
139
|
+
|
140
|
+
assert_equal [1,2,3,4,5], head_tail
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'should combine a head Array and a tail Array when they have no variables' do
|
144
|
+
assert_equal [1,2,3,4,5,6], [1,2,3] / [4,5,6]
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'should combine an embedded head Array and an embedded tail Array when they have no variables' do
|
148
|
+
assert_equal [1,2,3,4,5,6,7,8,9], [1,2,3] / [4,5,6] / [7,8,9]
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'should create a HeadTail' do
|
152
|
+
assert_Array_with_Tail array1 / :T, array1, '*:T'
|
153
|
+
assert_Array_with_Tail array2 / :T, array2, '*:T'
|
154
|
+
assert_Array_with_Tail array3 / :T, array3, '*:T'
|
155
|
+
assert_Array_with_Tail array4 / :T, array4, '*:T'
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
describe '#variables' do
|
161
|
+
|
162
|
+
it 'should return an array of the embedded Symbols' do
|
163
|
+
assert_equal [:A, :B, :C], array1.variables
|
164
|
+
assert_equal [], array2.variables
|
165
|
+
assert_equal [], array3.variables
|
166
|
+
assert_equal [:B], array4.variables
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
describe '#value' do
|
172
|
+
|
173
|
+
it 'should return simple Arrays as is' do
|
174
|
+
assert_equal [1, 2, :A, 4, [:B, 6, 7, :C], 9], array1.value
|
175
|
+
assert_equal [], array2.value
|
176
|
+
assert_equal [UNKNOWN_TAIL], array3.value
|
177
|
+
assert_equal [1, :B, 3, UNKNOWN_TAIL], array4.value
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'should expand Tails that are an Array' do
|
181
|
+
array = [1,2,3,Tail.new([7,8,9])]
|
182
|
+
|
183
|
+
assert_equal [1,2,3,7,8,9], array.value
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'should return the value of instantiated variables in a Tail' do
|
187
|
+
goal = new_goal :tailor, :h, :t
|
188
|
+
array = goal.variablise([:h, :b] / :t)
|
189
|
+
goal.instantiate :h, [1,2,3]
|
190
|
+
goal.instantiate :t, [7,8,9]
|
191
|
+
|
192
|
+
assert_equal [goal.value([1,2,3]),goal.variable(:b), goal.value(7), goal.value(8), goal.value(9)], array.value
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'should return the value of instantiated variables in a Tail' do
|
196
|
+
goal = new_goal :taylor, :head, :tail
|
197
|
+
array = [Tail.new(goal.value([5,6,7,8]))]
|
198
|
+
|
199
|
+
assert_equal [5,6,7,8], array.value
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
203
|
+
|
204
|
+
describe '#type' do
|
205
|
+
|
206
|
+
it 'should return :variable for symbols' do
|
207
|
+
assert_equal :array, array1.type
|
208
|
+
assert_equal :array, array2.type
|
209
|
+
assert_equal :array, array3.type
|
210
|
+
assert_equal :array, array4.type
|
211
|
+
end
|
212
|
+
|
213
|
+
end
|
214
|
+
|
215
|
+
describe '#head' do
|
216
|
+
|
217
|
+
it 'should return the first element when no headsize is provided' do
|
218
|
+
assert_equal 1, array1.head
|
219
|
+
assert_nil array2.head
|
220
|
+
assert_nil array3.head
|
221
|
+
assert_equal 1, array4.head
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'should return the first headsize elements' do
|
225
|
+
assert_equal [1, 2], array1.head(2)
|
226
|
+
assert_equal [], array2.head(2)
|
227
|
+
assert_equal [UNKNOWN_TAIL], array3.head(2)
|
228
|
+
assert_equal [1, :B], array4.head(2)
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'should return an extended head if the tail is uninstantiated' do
|
232
|
+
assert_equal [1, 2, :A, 4, [:B, 6, 7, :C], 9], array1.head(9)
|
233
|
+
assert_equal [], array2.head(9)
|
234
|
+
assert_equal [UNKNOWN_TAIL], array3.head(9)
|
235
|
+
assert_equal [1, :B, 3, UNKNOWN_TAIL], array4.head(9)
|
236
|
+
end
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
describe '#tail' do
|
241
|
+
|
242
|
+
it 'should return the tail after the first element when no headsize is provided' do
|
243
|
+
assert_equal [2, :A, 4, [:B, 6, 7, :C], 9], array1.tail
|
244
|
+
assert_equal [], array2.tail
|
245
|
+
assert_equal [UNKNOWN_TAIL], array3.tail
|
246
|
+
assert_equal [:B, 3, UNKNOWN_TAIL], array4.tail
|
247
|
+
end
|
248
|
+
|
249
|
+
it 'should return the tail after the first headsize elements' do
|
250
|
+
assert_equal [:A, 4, [:B, 6, 7, :C], 9], array1.tail(2)
|
251
|
+
assert_equal [], array2.tail(2)
|
252
|
+
assert_equal [UNKNOWN_TAIL], array3.tail(2)
|
253
|
+
assert_equal [3, UNKNOWN_TAIL], array4.tail(2)
|
254
|
+
end
|
255
|
+
|
256
|
+
it 'should return an extended tail if the tail is uninstantiated' do
|
257
|
+
assert_equal [], array1.tail(9)
|
258
|
+
assert_equal [], array2.tail(9)
|
259
|
+
assert_equal [UNKNOWN_TAIL], array3.tail(9)
|
260
|
+
assert_equal [UNKNOWN_TAIL], array4.tail(9)
|
261
|
+
end
|
262
|
+
|
263
|
+
end
|
264
|
+
|
265
|
+
describe '#clean' do
|
266
|
+
|
267
|
+
let(:predicate1) { Predicate.new :generic }
|
268
|
+
let(:arguments1) { predicate1.arguments(:m,:n) }
|
269
|
+
let(:goal1) { arguments1.goal }
|
270
|
+
|
271
|
+
let(:array5) { [1, 2, goal1[:A], 4, [goal1[:B], 6, 7, goal1[:C]], 9] }
|
272
|
+
let(:array6) { [1, goal1[:B], 3]/:T }
|
273
|
+
let(:array7) { [1, goal1[:B], 3]/goal1[:T] }
|
274
|
+
|
275
|
+
it 'should return simple Arrays as is' do
|
276
|
+
assert_equal [1, 2, :A, 4, [:B, 6, 7, :C], 9], array1.clean
|
277
|
+
assert_equal [], array2.clean
|
278
|
+
assert_equal [UNKNOWN_TAIL], array3.clean
|
279
|
+
assert_equal [1, :B, 3, UNKNOWN_TAIL], array4.clean
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'should return the values of its elements with variables replaced by nil and Tails replaced by UNKNOWN_TAIL' do
|
283
|
+
assert_equal [1, 2, nil, 4, [nil, 6, 7, nil], 9], array5.clean
|
284
|
+
assert_equal [1, nil, 3, UNKNOWN_TAIL], array6.clean
|
285
|
+
assert_equal [1, nil, 3, UNKNOWN_TAIL], array7.clean
|
286
|
+
end
|
287
|
+
|
288
|
+
end
|
289
|
+
|
290
|
+
end
|
@@ -0,0 +1,891 @@
|
|
1
|
+
#
|
2
|
+
# test/porolog/goal_test.rb - Test Suite for Porolog::Goal
|
3
|
+
#
|
4
|
+
# Luis Esteban 2 May 2018
|
5
|
+
# created
|
6
|
+
#
|
7
|
+
|
8
|
+
require_relative '../test_helper'
|
9
|
+
|
10
|
+
|
11
|
+
describe 'Porolog' do
|
12
|
+
|
13
|
+
before(:all) do
|
14
|
+
reset
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'Goal' do
|
18
|
+
|
19
|
+
let(:pred) { Predicate.new :p }
|
20
|
+
let(:args) { pred.(:x,:y) }
|
21
|
+
let(:goal) { Goal.new args }
|
22
|
+
|
23
|
+
describe '.reset' do
|
24
|
+
|
25
|
+
it 'should clear all goals' do
|
26
|
+
new_goal :predicate1, :a
|
27
|
+
new_goal :predicate2, :a, :b
|
28
|
+
new_goal :predicate3, :a, :b, :c
|
29
|
+
|
30
|
+
assert_equal 3, Goal.goals.size
|
31
|
+
|
32
|
+
Goal.reset
|
33
|
+
|
34
|
+
assert_empty Goal.goals
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should call check_deleted for each goal' do
|
38
|
+
Goal.any_instance.expects(:check_deleted).with().returns(false).times(5)
|
39
|
+
|
40
|
+
new_goal :p, :x, :y
|
41
|
+
new_goal :q, :a
|
42
|
+
new_goal :r, :a, :b, :c
|
43
|
+
|
44
|
+
Goal.reset
|
45
|
+
|
46
|
+
new_goal :j, 1
|
47
|
+
new_goal :k, ['a', 'b', 'c']
|
48
|
+
|
49
|
+
Goal.reset
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '.goals' do
|
55
|
+
|
56
|
+
it 'should return all registered goals' do
|
57
|
+
assert_equal 0, Goal.goals.size
|
58
|
+
|
59
|
+
goal1 = new_goal :predicate1, :a
|
60
|
+
|
61
|
+
assert_equal [goal1], Goal.goals
|
62
|
+
|
63
|
+
goal2 = new_goal :predicate2, :a, :b
|
64
|
+
|
65
|
+
assert_equal [goal1,goal2], Goal.goals
|
66
|
+
|
67
|
+
goal3 = new_goal :predicate3, :a, :b, :c
|
68
|
+
|
69
|
+
assert_equal [goal1,goal2,goal3], Goal.goals
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '.new' do
|
75
|
+
|
76
|
+
it 'should create a new Goal' do
|
77
|
+
goal = Goal.new nil
|
78
|
+
|
79
|
+
assert_instance_of Goal, goal
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#initialize' do
|
85
|
+
|
86
|
+
it 'should initialize calling_goal' do
|
87
|
+
goal1 = Goal.new args
|
88
|
+
goal2 = Goal.new args, goal1
|
89
|
+
|
90
|
+
assert_nil goal1.calling_goal
|
91
|
+
assert_equal goal1, goal2.calling_goal
|
92
|
+
|
93
|
+
assert_Goal goal1, :p, [:x,:y]
|
94
|
+
assert_Goal goal2, :p, [:x,:y]
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should initialize arguments' do
|
98
|
+
goal = Goal.new args, nil
|
99
|
+
|
100
|
+
assert_equal goal.variablise(args), goal.arguments
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should initialize terminate' do
|
104
|
+
goal = Goal.new args, nil
|
105
|
+
|
106
|
+
assert_equal false, goal.terminated?
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'should initialize variables' do
|
110
|
+
goal = Goal.new args, nil
|
111
|
+
|
112
|
+
assert_Goal_variables goal, { x: nil, y: nil }, [
|
113
|
+
'Goal1.:x',
|
114
|
+
'Goal1.:y',
|
115
|
+
].join("\n")
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'should register the goal as undeleted' do
|
119
|
+
goal1 = Goal.new args, nil
|
120
|
+
goal2 = Goal.new args, goal1
|
121
|
+
|
122
|
+
assert_equal [goal1,goal2], Goal.goals
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
describe '#myid' do
|
128
|
+
|
129
|
+
it 'should return the pretty id of the goal' do
|
130
|
+
goal1 = Goal.new args, nil
|
131
|
+
goal2 = Goal.new args, goal1
|
132
|
+
|
133
|
+
assert_equal 'Goal1', goal1.myid
|
134
|
+
assert_equal 'Goal2', goal2.myid
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
describe '#ancestors' do
|
140
|
+
|
141
|
+
it 'should return an Array of the parent goals' do
|
142
|
+
goal1 = Goal.new args
|
143
|
+
goal2 = Goal.new args, goal1
|
144
|
+
goal3 = Goal.new args, goal2
|
145
|
+
goal4 = Goal.new args, goal3
|
146
|
+
|
147
|
+
assert_equal [goal1], goal1.ancestors
|
148
|
+
assert_equal [goal1, goal2], goal2.ancestors
|
149
|
+
assert_equal [goal1, goal2, goal3], goal3.ancestors
|
150
|
+
assert_equal [goal1, goal2, goal3, goal4], goal4.ancestors
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
describe '#ancestry' do
|
156
|
+
|
157
|
+
it 'should return an Array of the parent goals' do
|
158
|
+
goal1 = Goal.new args
|
159
|
+
goal2 = Goal.new args, goal1
|
160
|
+
goal3 = Goal.new args, goal2
|
161
|
+
goal4 = Goal.new args, goal3
|
162
|
+
|
163
|
+
ancestors = [
|
164
|
+
'Goal1 -- Solve p(:x,:y) {:x=>nil, :y=>nil}',
|
165
|
+
' Goal2 -- Solve p(:x,:y) {:x=>nil, :y=>nil}',
|
166
|
+
' Goal3 -- Solve p(:x,:y) {:x=>nil, :y=>nil}',
|
167
|
+
' Goal4 -- Solve p(:x,:y) {:x=>nil, :y=>nil}',
|
168
|
+
]
|
169
|
+
|
170
|
+
assert_equal ancestors[0...1].join("\n"), goal1.ancestry
|
171
|
+
assert_equal ancestors[0...2].join("\n"), goal2.ancestry
|
172
|
+
assert_equal ancestors[0...3].join("\n"), goal3.ancestry
|
173
|
+
assert_equal ancestors[0...4].join("\n"), goal4.ancestry
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
describe '#inspect' do
|
179
|
+
|
180
|
+
it 'should show a description of the goal' do
|
181
|
+
goal1 = Goal.new args
|
182
|
+
goal2 = Goal.new pred.(1,:b,'word'), goal1
|
183
|
+
goal3 = Goal.new args, goal2
|
184
|
+
goal4 = Goal.new args, goal3
|
185
|
+
|
186
|
+
assert_equal 'Goal1 -- Solve p(:x,:y)', goal1.inspect
|
187
|
+
assert_equal 'Goal2 -- Solve p(1,:b,"word")', goal2.inspect
|
188
|
+
assert_equal 'Goal3 -- Solve p(:x,:y)', goal3.inspect
|
189
|
+
assert_equal 'Goal4 -- Solve p(:x,:y)', goal4.inspect
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
describe '#delete!' do
|
195
|
+
|
196
|
+
it 'should delete the goal' do
|
197
|
+
goal1 = Goal.new args
|
198
|
+
goal2 = Goal.new pred.(1,:b,'word'), goal1
|
199
|
+
goal3 = Goal.new args, goal2
|
200
|
+
goal4 = Goal.new args, goal3
|
201
|
+
|
202
|
+
assert goal2.delete!, 'goal should delete'
|
203
|
+
assert_equal [goal1, goal3, goal4], Goal.goals
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
|
208
|
+
describe '#myid' do
|
209
|
+
|
210
|
+
let(:pred) { Predicate.new :p }
|
211
|
+
let(:args) { pred.(:x,:y) }
|
212
|
+
|
213
|
+
it 'should return the pretty id of the goal' do
|
214
|
+
goal1 = Goal.new args, nil
|
215
|
+
goal2 = Goal.new args, goal1
|
216
|
+
|
217
|
+
assert_equal 'Goal1', goal1.myid
|
218
|
+
assert_equal 'Goal2', goal2.myid
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
222
|
+
|
223
|
+
describe '#deleted?' do
|
224
|
+
|
225
|
+
it 'should return the deleted state of a goal' do
|
226
|
+
goal = Goal.new args
|
227
|
+
|
228
|
+
refute goal.deleted?, 'goal should not be deleted'
|
229
|
+
|
230
|
+
Goal.reset
|
231
|
+
|
232
|
+
assert goal.deleted?, 'goal should be deleted'
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'should memoize the deleted state of a goal' do
|
236
|
+
goal = Goal.new args
|
237
|
+
|
238
|
+
check_deleted_spy = Spy.on(goal, :check_deleted).and_call_through
|
239
|
+
|
240
|
+
refute goal.deleted?
|
241
|
+
refute goal.deleted?
|
242
|
+
refute goal.deleted?
|
243
|
+
refute goal.deleted?
|
244
|
+
|
245
|
+
Goal.reset
|
246
|
+
|
247
|
+
assert goal.deleted?
|
248
|
+
assert goal.deleted?
|
249
|
+
assert goal.deleted?
|
250
|
+
assert goal.deleted?
|
251
|
+
|
252
|
+
assert_equal 5, check_deleted_spy.calls.size
|
253
|
+
end
|
254
|
+
|
255
|
+
end
|
256
|
+
|
257
|
+
describe '#check_deleted' do
|
258
|
+
|
259
|
+
it 'should return false when the goal is not deleted and keep variables intact' do
|
260
|
+
goal = Goal.new args
|
261
|
+
goal.variable(:x)
|
262
|
+
goal.variable(:y)
|
263
|
+
goal.variable(:z)
|
264
|
+
|
265
|
+
variable_remove_spy = Spy.on_instance_method(Variable, :remove)
|
266
|
+
|
267
|
+
refute goal.check_deleted, 'goal should not be deleted'
|
268
|
+
|
269
|
+
assert_equal 0, variable_remove_spy.calls.size
|
270
|
+
end
|
271
|
+
|
272
|
+
it 'should return true when the goal is deleted and remove all variables' do
|
273
|
+
goal = Goal.new args
|
274
|
+
goal.variable(:x)
|
275
|
+
goal.variable(:y)
|
276
|
+
goal.variable(:z)
|
277
|
+
|
278
|
+
variable_remove_spy = Spy.on_instance_method(Variable, :remove)
|
279
|
+
|
280
|
+
Goal.reset
|
281
|
+
|
282
|
+
assert goal.check_deleted, 'goal should be deleted'
|
283
|
+
|
284
|
+
assert_equal 3, variable_remove_spy.calls.size
|
285
|
+
end
|
286
|
+
|
287
|
+
end
|
288
|
+
|
289
|
+
describe '#terminate!' do
|
290
|
+
|
291
|
+
it 'should set the goal to terminate and log the event' do
|
292
|
+
goal = Goal.new args
|
293
|
+
|
294
|
+
assert goal.terminate!, 'the goal should be set to terminate'
|
295
|
+
assert_equal ['terminating'], goal.log
|
296
|
+
end
|
297
|
+
|
298
|
+
end
|
299
|
+
|
300
|
+
describe '#terminated?' do
|
301
|
+
|
302
|
+
it 'should return whether the goal is set to terminate or not' do
|
303
|
+
goal = Goal.new args
|
304
|
+
|
305
|
+
refute goal.terminated?, 'the goal should not be initialized to terminate'
|
306
|
+
assert goal.terminate!, 'the goal should be set to terminate'
|
307
|
+
assert goal.terminated?, 'the goal should be set to terminate'
|
308
|
+
end
|
309
|
+
|
310
|
+
end
|
311
|
+
|
312
|
+
describe '#variablise' do
|
313
|
+
|
314
|
+
it 'should convert a Symbol into a Variable' do
|
315
|
+
assert_Variable goal.variablise(:k), :k, goal, [], []
|
316
|
+
end
|
317
|
+
|
318
|
+
it 'should return a Variable as is' do
|
319
|
+
v = Variable.new :r, goal
|
320
|
+
assert_equal v, goal.variablise(v)
|
321
|
+
end
|
322
|
+
|
323
|
+
it 'should convert an Array into a Variables and Objects' do
|
324
|
+
assert_equal [goal.value(1),goal.variable(:a),goal.value('word')], goal.variablise([1,:a,'word'])
|
325
|
+
end
|
326
|
+
|
327
|
+
it 'should return a duplicate of an Arguments' do
|
328
|
+
duplicate = goal.variablise(args)
|
329
|
+
assert_Arguments duplicate, :p, goal.variablise([:x, :y])
|
330
|
+
refute_equal args, duplicate
|
331
|
+
end
|
332
|
+
|
333
|
+
it 'should convert a Tail into a Tail with a variablised value' do
|
334
|
+
assert_Tail goal.variablise(Tail.new :m), '*Goal1.:m'
|
335
|
+
end
|
336
|
+
|
337
|
+
it 'should return a Value as is' do
|
338
|
+
v = Value.new(45, goal)
|
339
|
+
assert_equal v, goal.variablise(v)
|
340
|
+
end
|
341
|
+
|
342
|
+
it 'should return an unknown array as is' do
|
343
|
+
assert_equal UNKNOWN_ARRAY, goal.variablise(UNKNOWN_ARRAY)
|
344
|
+
end
|
345
|
+
|
346
|
+
it 'should return an unknown tail as is' do
|
347
|
+
assert_equal UNKNOWN_TAIL, goal.variablise(UNKNOWN_TAIL)
|
348
|
+
end
|
349
|
+
|
350
|
+
it 'should convert any other Object into a Value' do
|
351
|
+
assert_Value goal.variablise(23.61), 23.61, goal
|
352
|
+
end
|
353
|
+
|
354
|
+
end
|
355
|
+
|
356
|
+
describe '#variables' do
|
357
|
+
|
358
|
+
it 'should return a Hash of variables and their values' do
|
359
|
+
goal = Goal.new args
|
360
|
+
goal.variable(:x)
|
361
|
+
goal.variable(:y)
|
362
|
+
goal.variable(:z)
|
363
|
+
|
364
|
+
variables = goal.variables
|
365
|
+
|
366
|
+
assert_instance_of Hash, variables
|
367
|
+
|
368
|
+
assert_Goal goal, :p, [:x,:y]
|
369
|
+
assert_Goal_variables goal, { x: nil, y: nil, z: nil }, [
|
370
|
+
'Goal1.:x',
|
371
|
+
'Goal1.:y',
|
372
|
+
'Goal1.:z',
|
373
|
+
].join("\n")
|
374
|
+
end
|
375
|
+
|
376
|
+
end
|
377
|
+
|
378
|
+
describe '#inspect_variables' do
|
379
|
+
|
380
|
+
it 'should return a string showing the instantiations of the variables of the goal' do
|
381
|
+
# -- Initial Goal --
|
382
|
+
goal = Goal.new args
|
383
|
+
|
384
|
+
x = goal.variable(:x)
|
385
|
+
y = goal.variable(:y)
|
386
|
+
z = goal.variable(:z)
|
387
|
+
|
388
|
+
expected = [
|
389
|
+
'Goal1.:x',
|
390
|
+
'Goal1.:y',
|
391
|
+
'Goal1.:z',
|
392
|
+
].join("\n")
|
393
|
+
|
394
|
+
assert_equal expected, goal.inspect_variables
|
395
|
+
|
396
|
+
# -- After First Instantiation --
|
397
|
+
# x.head = y
|
398
|
+
x.instantiate y, nil, :head
|
399
|
+
|
400
|
+
expected = [
|
401
|
+
'Goal1.:x',
|
402
|
+
' [:head]Goal1.:y',
|
403
|
+
'Goal1.:y',
|
404
|
+
' Goal1.:x[:head]',
|
405
|
+
'Goal1.:z',
|
406
|
+
].join("\n")
|
407
|
+
|
408
|
+
assert_equal expected, goal.inspect_variables
|
409
|
+
|
410
|
+
# -- After Second Instantiation --
|
411
|
+
# x.head = y
|
412
|
+
# x.tail = z
|
413
|
+
x.instantiate z, nil, :tail
|
414
|
+
|
415
|
+
expected = [
|
416
|
+
'Goal1.:x',
|
417
|
+
' [:head]Goal1.:y',
|
418
|
+
' [:tail]Goal1.:z',
|
419
|
+
'Goal1.:y',
|
420
|
+
' Goal1.:x[:head]',
|
421
|
+
' [:tail]Goal1.:z',
|
422
|
+
'Goal1.:z',
|
423
|
+
' Goal1.:x[:tail]',
|
424
|
+
' [:head]Goal1.:y',
|
425
|
+
].join("\n")
|
426
|
+
|
427
|
+
assert_equal expected, goal.inspect_variables
|
428
|
+
|
429
|
+
# -- After Third Instantiation --
|
430
|
+
# x = [*y, *z]
|
431
|
+
# y = 1,2,3
|
432
|
+
y.instantiate goal.value([1,2,3])
|
433
|
+
|
434
|
+
expected = [
|
435
|
+
'Goal1.:x',
|
436
|
+
' [:head]Goal1.:y',
|
437
|
+
' Goal1.[1, 2, 3]',
|
438
|
+
' [:tail]Goal1.:z',
|
439
|
+
'Goal1.:y',
|
440
|
+
' Goal1.:x[:head]',
|
441
|
+
' [:tail]Goal1.:z',
|
442
|
+
' Goal1.[1, 2, 3]',
|
443
|
+
'Goal1.:z',
|
444
|
+
' Goal1.:x[:tail]',
|
445
|
+
' [:head]Goal1.:y',
|
446
|
+
' Goal1.[1, 2, 3]',
|
447
|
+
].join("\n")
|
448
|
+
|
449
|
+
assert_equal expected, goal.inspect_variables
|
450
|
+
|
451
|
+
# -- After Fourth Instantiation --
|
452
|
+
# x = [*y, *z]
|
453
|
+
# y = 1,2,3
|
454
|
+
# z = 4,5,6
|
455
|
+
z.instantiate goal.value([4,5,6])
|
456
|
+
|
457
|
+
expected = [
|
458
|
+
'Goal1.:x',
|
459
|
+
' [:head]Goal1.:y',
|
460
|
+
' Goal1.[1, 2, 3]',
|
461
|
+
' [:tail]Goal1.:z',
|
462
|
+
' Goal1.[4, 5, 6]',
|
463
|
+
'Goal1.:y',
|
464
|
+
' Goal1.:x[:head]',
|
465
|
+
' [:tail]Goal1.:z',
|
466
|
+
' Goal1.[4, 5, 6]',
|
467
|
+
' Goal1.[1, 2, 3]',
|
468
|
+
'Goal1.:z',
|
469
|
+
' Goal1.:x[:tail]',
|
470
|
+
' [:head]Goal1.:y',
|
471
|
+
' Goal1.[1, 2, 3]',
|
472
|
+
' Goal1.[4, 5, 6]',
|
473
|
+
].join("\n")
|
474
|
+
|
475
|
+
assert_equal expected, goal.inspect_variables
|
476
|
+
end
|
477
|
+
|
478
|
+
end
|
479
|
+
|
480
|
+
describe '#values' do
|
481
|
+
|
482
|
+
it 'should return the values that have been associated with the goal' do
|
483
|
+
goal = Goal.new args
|
484
|
+
|
485
|
+
x = goal.variable(:x)
|
486
|
+
y = goal.variable(:y)
|
487
|
+
z = goal.variable(:z)
|
488
|
+
|
489
|
+
x.instantiate y, nil, :head
|
490
|
+
x.instantiate z, nil, :tail
|
491
|
+
y.instantiate goal.value([1,2,3])
|
492
|
+
z.instantiate goal.value([4,5,6])
|
493
|
+
|
494
|
+
expected = [
|
495
|
+
[1,2,3],
|
496
|
+
[4,5,6],
|
497
|
+
]
|
498
|
+
|
499
|
+
assert_equal expected, goal.values
|
500
|
+
end
|
501
|
+
|
502
|
+
end
|
503
|
+
|
504
|
+
describe '#variable' do
|
505
|
+
|
506
|
+
it 'should return a non-variable as is' do
|
507
|
+
assert_equal 4.132, goal.variable(4.132)
|
508
|
+
end
|
509
|
+
|
510
|
+
it 'should create and find a variable from a Symbol or Variable' do
|
511
|
+
refute goal.variables.key?(:v), ':v should not be a variable'
|
512
|
+
|
513
|
+
variable1 = goal.variable :v
|
514
|
+
|
515
|
+
assert goal.variables.key?(:v), ':v should be a variable'
|
516
|
+
|
517
|
+
variable2 = goal.variable :v
|
518
|
+
|
519
|
+
assert goal.variables.key?(:v), ':v should be a variable'
|
520
|
+
|
521
|
+
variable3 = goal.variable variable2
|
522
|
+
|
523
|
+
assert_equal variable1, variable2
|
524
|
+
assert_equal variable2, variable3
|
525
|
+
end
|
526
|
+
|
527
|
+
end
|
528
|
+
|
529
|
+
describe '#value' do
|
530
|
+
|
531
|
+
it 'should create and find a value from an Object' do
|
532
|
+
refute goal.values.include?(99.02), '99.02 should not be a value'
|
533
|
+
|
534
|
+
value1 = goal.value 99.02
|
535
|
+
|
536
|
+
assert goal.values.include?(99.02), '99.02 should be a value'
|
537
|
+
|
538
|
+
value2 = goal.value 99.02
|
539
|
+
|
540
|
+
assert_Value value1, 99.02, goal
|
541
|
+
assert_Value value2, 99.02, goal
|
542
|
+
|
543
|
+
assert_equal [99.02], goal.values
|
544
|
+
end
|
545
|
+
|
546
|
+
end
|
547
|
+
|
548
|
+
describe '#value_of' do
|
549
|
+
|
550
|
+
describe 'when name is a Symbol' do
|
551
|
+
|
552
|
+
let(:variable_name) { :cymbal }
|
553
|
+
|
554
|
+
it 'should create the Variable' do
|
555
|
+
refute goal.variables.key?(variable_name), "#{variable_name} should not exist"
|
556
|
+
|
557
|
+
refute_nil goal.value_of(variable_name)
|
558
|
+
|
559
|
+
assert goal.variables.key?(variable_name), "#{variable_name} should exist"
|
560
|
+
|
561
|
+
variable = goal.variable(variable_name)
|
562
|
+
variable.instantiate 44.5
|
563
|
+
|
564
|
+
assert_equal 44.5, goal.value_of(variable_name)
|
565
|
+
end
|
566
|
+
|
567
|
+
end
|
568
|
+
|
569
|
+
describe 'when name is not a Symbol' do
|
570
|
+
|
571
|
+
let(:variable_name) { 99.28 }
|
572
|
+
|
573
|
+
it 'should return the name as the value' do
|
574
|
+
assert_equal 99.28, goal.value_of(variable_name)
|
575
|
+
end
|
576
|
+
|
577
|
+
end
|
578
|
+
|
579
|
+
end
|
580
|
+
|
581
|
+
describe '#values_of' do
|
582
|
+
|
583
|
+
it 'should return an Array with values_of applied to each element when given an Array' do
|
584
|
+
goal.instantiate :thomas, '$10'
|
585
|
+
|
586
|
+
expected = [[1,'two'], '$10', 999, 'giraffe', 0.5]
|
587
|
+
|
588
|
+
assert_equal expected, goal.values_of([[1,'two'], :thomas, 999, 'giraffe', 0.5])
|
589
|
+
end
|
590
|
+
|
591
|
+
it 'should return the value_of the Variable when given a Variable' do
|
592
|
+
goal.instantiate :jones, 'Fuzzy'
|
593
|
+
|
594
|
+
variable1 = goal.variable(:jones)
|
595
|
+
|
596
|
+
assert_equal 'Fuzzy', goal.values_of(variable1)
|
597
|
+
end
|
598
|
+
|
599
|
+
it 'should return the value_of the Symbol when given a Symbol' do
|
600
|
+
goal.instantiate :x, 'Staunch'
|
601
|
+
|
602
|
+
assert_equal 'Staunch', goal.values_of(:x)
|
603
|
+
end
|
604
|
+
|
605
|
+
it 'should return the value_of the Value when given a Value' do
|
606
|
+
value1 = goal.value(123.76)
|
607
|
+
|
608
|
+
assert_equal 123.76, goal.values_of(value1)
|
609
|
+
end
|
610
|
+
|
611
|
+
it 'should somehow splat when given a Tail' do
|
612
|
+
tail1 = Tail.new ['apples','oranges','bananas']
|
613
|
+
|
614
|
+
assert_equal 'apples', goal.values_of(tail1)
|
615
|
+
end
|
616
|
+
|
617
|
+
it 'should return the Object as is when given an Object' do
|
618
|
+
object = Object.new
|
619
|
+
|
620
|
+
goal.expects(:value_of).times(0)
|
621
|
+
|
622
|
+
assert_equal object, goal.values_of(object)
|
623
|
+
end
|
624
|
+
|
625
|
+
end
|
626
|
+
|
627
|
+
describe '#solve' do
|
628
|
+
|
629
|
+
it 'should find no solutions for a goal with no rules' do
|
630
|
+
goal1 = new_goal :p, :x, :y
|
631
|
+
|
632
|
+
solutions = goal1.solve
|
633
|
+
|
634
|
+
assert_equal [], solutions
|
635
|
+
end
|
636
|
+
|
637
|
+
it 'should solve a fact' do
|
638
|
+
predicate :fact
|
639
|
+
|
640
|
+
fact(42).fact!
|
641
|
+
|
642
|
+
solutions = fact(42).solve
|
643
|
+
|
644
|
+
assert_equal [{}], solutions
|
645
|
+
end
|
646
|
+
|
647
|
+
it 'should not solve a falicy' do
|
648
|
+
predicate :fact
|
649
|
+
|
650
|
+
fact(42).falicy!
|
651
|
+
|
652
|
+
solutions = fact(42).solve
|
653
|
+
|
654
|
+
assert_equal [], solutions
|
655
|
+
end
|
656
|
+
|
657
|
+
it 'should solve using head and tail with lists' do
|
658
|
+
predicate :head_tail
|
659
|
+
|
660
|
+
head_tail([1,2,3,4,5,6,7]).fact!
|
661
|
+
head_tail(['head','body','foot']).fact!
|
662
|
+
|
663
|
+
solutions = head_tail(:head/:tail).solve
|
664
|
+
|
665
|
+
assert_equal [
|
666
|
+
{ head: 1, tail: [2,3,4,5,6,7] },
|
667
|
+
{ head: 'head', tail: ['body','foot'] },
|
668
|
+
], solutions
|
669
|
+
end
|
670
|
+
|
671
|
+
it 'should solve a goal recursively' do
|
672
|
+
builtin :write
|
673
|
+
predicate :recursive
|
674
|
+
|
675
|
+
recursive([]) << [:CUT, true]
|
676
|
+
recursive(:head/:tail) << [
|
677
|
+
write('(',:head,')'),
|
678
|
+
recursive(:tail)
|
679
|
+
]
|
680
|
+
|
681
|
+
assert_output '(1)(2)(3)(four)(5)(6)(7)' do
|
682
|
+
solutions = recursive([1,2,3,'four',5,6,7]).solve
|
683
|
+
|
684
|
+
assert_equal [{}], solutions
|
685
|
+
end
|
686
|
+
end
|
687
|
+
|
688
|
+
end
|
689
|
+
|
690
|
+
describe '#satisfy' do
|
691
|
+
|
692
|
+
let(:block) { ->(subgoal){} }
|
693
|
+
|
694
|
+
it 'should return false when the goal has no arguments' do
|
695
|
+
goal = Goal.new nil
|
696
|
+
|
697
|
+
block.expects(:call).times(0)
|
698
|
+
|
699
|
+
refute goal.satisfy(&block), name
|
700
|
+
end
|
701
|
+
|
702
|
+
it 'should access the predicate of its arguments' do
|
703
|
+
goal.arguments.expects(:predicate).with().returns(nil).times(1)
|
704
|
+
block.expects(:call).times(0)
|
705
|
+
|
706
|
+
refute goal.satisfy(&block), name
|
707
|
+
end
|
708
|
+
|
709
|
+
it 'should try to satisfy the predicate with itself' do
|
710
|
+
pred.expects(:satisfy).with(goal).returns(nil).times(1)
|
711
|
+
block.expects(:call).times(0)
|
712
|
+
|
713
|
+
refute goal.satisfy(&block), name
|
714
|
+
end
|
715
|
+
|
716
|
+
it 'should call the block when the predicate is satisfied' do
|
717
|
+
pred.(1,2).fact!
|
718
|
+
pred.(3,4).fact!
|
719
|
+
pred.(5,6).fact!
|
720
|
+
|
721
|
+
block.expects(:call).returns(true).times(3)
|
722
|
+
|
723
|
+
assert goal.satisfy(&block), name
|
724
|
+
end
|
725
|
+
|
726
|
+
end
|
727
|
+
|
728
|
+
describe '#instantiate' do
|
729
|
+
|
730
|
+
it 'creates an Array with a Tail using the slash notation with Symbols with a goal' do
|
731
|
+
goal = new_goal :bravo, :x, :y, :z
|
732
|
+
|
733
|
+
head_tail = goal.variablise(:head / :tail)
|
734
|
+
|
735
|
+
assert_Array_with_Tail head_tail, [goal.variable(:head)], '*Goal1.:tail'
|
736
|
+
|
737
|
+
assert_Goal_variables goal, { x: nil, y: nil, z: nil, head: nil, tail: nil }, [
|
738
|
+
'Goal1.:x',
|
739
|
+
'Goal1.:y',
|
740
|
+
'Goal1.:z',
|
741
|
+
'Goal1.:head',
|
742
|
+
'Goal1.:tail',
|
743
|
+
].join("\n")
|
744
|
+
end
|
745
|
+
|
746
|
+
it 'creates an Array with a Tail using the slash notation with a single head with a goal' do
|
747
|
+
goal = new_goal :bravo, :x, :y, :z
|
748
|
+
|
749
|
+
head_tail = goal.variablise([:head] / :tail)
|
750
|
+
|
751
|
+
assert_Array_with_Tail head_tail, [goal.variable(:head)], '*Goal1.:tail'
|
752
|
+
|
753
|
+
assert_Goal_variables goal, { x: nil, y: nil, z: nil, head: nil, tail: nil }, [
|
754
|
+
'Goal1.:x',
|
755
|
+
'Goal1.:y',
|
756
|
+
'Goal1.:z',
|
757
|
+
'Goal1.:head',
|
758
|
+
'Goal1.:tail',
|
759
|
+
].join("\n")
|
760
|
+
end
|
761
|
+
|
762
|
+
it 'creates variables from its contents with a goal' do
|
763
|
+
predicate :bravo
|
764
|
+
arguments = Predicate[:bravo].arguments(:x,:y,:z)
|
765
|
+
goal = arguments.goal
|
766
|
+
|
767
|
+
head_tail = [:alpha,bravo(:a,:b,:c),[:carly]] / [:x,[:y],bravo(:p,:q/:r)]
|
768
|
+
|
769
|
+
assert_equal [:alpha,bravo(:a,:b,:c),[:carly], :x,[:y],bravo(:p,:q/:r)].inspect, head_tail.inspect
|
770
|
+
|
771
|
+
assert_Goal_variables goal, { x: nil, y: nil, z: nil }, [
|
772
|
+
'Goal1.:x',
|
773
|
+
'Goal1.:y',
|
774
|
+
'Goal1.:z',
|
775
|
+
].join("\n")
|
776
|
+
|
777
|
+
head_tail = goal.variablise(head_tail)
|
778
|
+
|
779
|
+
assert_equal '[Goal1.:alpha, bravo(Goal1.:a,Goal1.:b,Goal1.:c), [Goal1.:carly], Goal1.:x, [Goal1.:y], bravo(Goal1.:p,[Goal1.:q, *Goal1.:r])]', head_tail.inspect
|
780
|
+
|
781
|
+
assert_Goal_variables goal, { x: nil, y: nil, z: nil, alpha: nil, a: nil, b: nil, c: nil, carly: nil, p: nil, q: nil, r: nil }, [
|
782
|
+
'Goal1.:x',
|
783
|
+
'Goal1.:y',
|
784
|
+
'Goal1.:z',
|
785
|
+
'Goal1.:alpha',
|
786
|
+
'Goal1.:a',
|
787
|
+
'Goal1.:b',
|
788
|
+
'Goal1.:c',
|
789
|
+
'Goal1.:carly',
|
790
|
+
'Goal1.:p',
|
791
|
+
'Goal1.:q',
|
792
|
+
'Goal1.:r',
|
793
|
+
].join("\n")
|
794
|
+
end
|
795
|
+
|
796
|
+
it 'should combine Array value of head and Array value of tail when it has a goal' do
|
797
|
+
head_tail = [:first] / :last
|
798
|
+
|
799
|
+
goal.instantiate :first, 'alpha', goal
|
800
|
+
goal.instantiate :last, ['omega'], goal
|
801
|
+
|
802
|
+
head_tail = goal.values_of(goal.variablise(head_tail))
|
803
|
+
|
804
|
+
assert_equal ['alpha','omega'], head_tail
|
805
|
+
end
|
806
|
+
|
807
|
+
end
|
808
|
+
|
809
|
+
describe '#inherit_variables' do
|
810
|
+
|
811
|
+
it 'should return true for an initial goal' do
|
812
|
+
goal = new_goal :goal, :x, :y, :z
|
813
|
+
|
814
|
+
assert goal.inherit_variables
|
815
|
+
assert_Goal_variables goal, { x: nil, y: nil, z: nil }, [
|
816
|
+
'Goal1.:x',
|
817
|
+
'Goal1.:y',
|
818
|
+
'Goal1.:z',
|
819
|
+
].join("\n")
|
820
|
+
end
|
821
|
+
|
822
|
+
it 'should instantiate combined variables of both goals' do
|
823
|
+
goal = new_goal :goal, :x, :y, :z
|
824
|
+
subgoal = new_goal :subgoal, :a, :b, :c
|
825
|
+
|
826
|
+
assert subgoal.inherit_variables(goal)
|
827
|
+
assert_Goal_variables goal, { x: nil, y: nil, z: nil, a: nil, b: nil, c: nil }, [
|
828
|
+
'Goal1.:x',
|
829
|
+
' Goal2.:x',
|
830
|
+
'Goal1.:y',
|
831
|
+
' Goal2.:y',
|
832
|
+
'Goal1.:z',
|
833
|
+
' Goal2.:z',
|
834
|
+
'Goal1.:a',
|
835
|
+
' Goal2.:a',
|
836
|
+
'Goal1.:b',
|
837
|
+
' Goal2.:b',
|
838
|
+
'Goal1.:c',
|
839
|
+
' Goal2.:c',
|
840
|
+
].join("\n")
|
841
|
+
assert_Goal_variables subgoal, { a: nil, b: nil, c: nil, x: nil, y: nil, z: nil }, [
|
842
|
+
'Goal2.:a',
|
843
|
+
' Goal1.:a',
|
844
|
+
'Goal2.:b',
|
845
|
+
' Goal1.:b',
|
846
|
+
'Goal2.:c',
|
847
|
+
' Goal1.:c',
|
848
|
+
'Goal2.:x',
|
849
|
+
' Goal1.:x',
|
850
|
+
'Goal2.:y',
|
851
|
+
' Goal1.:y',
|
852
|
+
'Goal2.:z',
|
853
|
+
' Goal1.:z',
|
854
|
+
].join("\n")
|
855
|
+
end
|
856
|
+
|
857
|
+
it 'should not make any instantiations when variables cannot be unified' do
|
858
|
+
goal = new_goal :goal, :x, :y, :z
|
859
|
+
subgoal = new_goal :subgoal, :a, :b, :c
|
860
|
+
|
861
|
+
goal[:x].instantiate 1
|
862
|
+
subgoal[:x].instantiate 2
|
863
|
+
|
864
|
+
refute subgoal.inherit_variables(goal)
|
865
|
+
assert_equal [
|
866
|
+
'Cannot unify because 1 != 2 (variable != variable)',
|
867
|
+
], goal.log
|
868
|
+
assert_equal [
|
869
|
+
'Cannot unify because 1 != 2 (variable != variable)',
|
870
|
+
"Couldn't unify: :x WITH Goal1 AND Goal2"
|
871
|
+
], subgoal.log
|
872
|
+
assert_Goal_variables goal, { x: 1, y: nil, z: nil }, [
|
873
|
+
'Goal1.:x',
|
874
|
+
' Goal1.1',
|
875
|
+
'Goal1.:y',
|
876
|
+
'Goal1.:z',
|
877
|
+
].join("\n")
|
878
|
+
assert_Goal_variables subgoal, { a: nil, b: nil, c: nil, x: 2 }, [
|
879
|
+
'Goal2.:a',
|
880
|
+
'Goal2.:b',
|
881
|
+
'Goal2.:c',
|
882
|
+
'Goal2.:x',
|
883
|
+
' Goal2.2',
|
884
|
+
].join("\n")
|
885
|
+
end
|
886
|
+
|
887
|
+
end
|
888
|
+
|
889
|
+
end
|
890
|
+
|
891
|
+
end
|