porolog 0.0.7 → 0.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.
- checksums.yaml +4 -4
- data/README.md +18 -4
- data/bin/porolog +38 -2
- data/coverage/badge.svg +1 -1
- data/coverage/index.html +52327 -6692
- data/doc/Array.html +113 -33
- data/doc/Object.html +11 -17
- data/doc/Porolog.html +3681 -73
- data/doc/Symbol.html +17 -20
- data/doc/_index.html +181 -13
- data/doc/class_list.html +1 -1
- data/doc/file.README.html +28 -38
- data/doc/index.html +28 -38
- data/doc/method_list.html +871 -167
- data/doc/top-level-namespace.html +2 -2
- data/lib/porolog.rb +1015 -2
- data/lib/porolog/arguments.rb +16 -14
- data/lib/porolog/core_ext.rb +6 -0
- data/lib/porolog/error.rb +6 -0
- data/lib/porolog/goal.rb +205 -68
- data/lib/porolog/instantiation.rb +300 -0
- data/lib/porolog/predicate.rb +33 -16
- data/lib/porolog/rule.rb +129 -2
- data/lib/porolog/scope.rb +3 -3
- data/lib/porolog/tail.rb +52 -0
- data/lib/porolog/value.rb +9 -12
- data/lib/porolog/variable.rb +307 -0
- data/test/porolog/arguments_test.rb +217 -135
- data/test/porolog/core_ext_test.rb +24 -17
- data/test/porolog/goal_test.rb +481 -74
- data/test/porolog/instantiation_test.rb +874 -0
- data/test/porolog/porolog_test.rb +2121 -13
- data/test/porolog/predicate_test.rb +1 -1
- data/test/porolog/rule_test.rb +395 -0
- data/test/porolog/scope_test.rb +0 -2
- data/test/porolog/tail_test.rb +127 -0
- data/test/porolog/value_test.rb +1 -1
- data/test/porolog/variable_test.rb +1625 -0
- data/test/test_helper.rb +78 -5
- metadata +12 -4
@@ -53,15 +53,14 @@ describe 'Object' do
|
|
53
53
|
|
54
54
|
describe '#/' do
|
55
55
|
|
56
|
-
it 'should create
|
57
|
-
skip 'until Variable added'
|
56
|
+
it 'should create an n Array with a Tail' do
|
58
57
|
assert_Array_with_Tail object1 / :T, [object1], '*:T'
|
59
58
|
assert_Array_with_Tail [object2] / :T, [object2], '*:T'
|
60
|
-
assert_Array_with_Tail object2.tail(:T), [object2], '*:T'
|
59
|
+
#assert_Array_with_Tail object2.tail(:T), [object2], '*:T'
|
61
60
|
assert_Array_with_Tail object3 / :T, [object3], '*:T'
|
62
61
|
assert_Array_with_Tail object4 / :T, [object4], '*:T'
|
63
62
|
assert_Array_with_Tail [object5] / :T, [object5], '*:T'
|
64
|
-
assert_Array_with_Tail
|
63
|
+
#assert_Array_with_Tail object5.tail(:T), [object5], '*:T'
|
65
64
|
end
|
66
65
|
|
67
66
|
end
|
@@ -115,7 +114,6 @@ describe 'Symbol' do
|
|
115
114
|
describe '#/' do
|
116
115
|
|
117
116
|
it 'should create a HeadTail' do
|
118
|
-
skip 'until Variable added'
|
119
117
|
assert_Array_with_Tail symbol1 / :T, [symbol1], '*:T'
|
120
118
|
assert_Array_with_Tail symbol2 / :T, [symbol2], '*:T'
|
121
119
|
assert_Array_with_Tail symbol3 / :T, [symbol3], '*:T'
|
@@ -136,8 +134,21 @@ describe 'Array' do
|
|
136
134
|
|
137
135
|
describe '#/' do
|
138
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
|
+
|
139
151
|
it 'should create a HeadTail' do
|
140
|
-
skip 'until Variable added'
|
141
152
|
assert_Array_with_Tail array1 / :T, array1, '*:T'
|
142
153
|
assert_Array_with_Tail array2 / :T, array2, '*:T'
|
143
154
|
assert_Array_with_Tail array3 / :T, array3, '*:T'
|
@@ -149,7 +160,6 @@ describe 'Array' do
|
|
149
160
|
describe '#variables' do
|
150
161
|
|
151
162
|
it 'should return an array of the embedded Symbols' do
|
152
|
-
skip 'until Tail added'
|
153
163
|
assert_equal [:A, :B, :C], array1.variables
|
154
164
|
assert_equal [], array2.variables
|
155
165
|
assert_equal [], array3.variables
|
@@ -161,7 +171,6 @@ describe 'Array' do
|
|
161
171
|
describe '#value' do
|
162
172
|
|
163
173
|
it 'should return simple Arrays as is' do
|
164
|
-
skip 'until Tail added'
|
165
174
|
assert_equal [1, 2, :A, 4, [:B, 6, 7, :C], 9], array1.value
|
166
175
|
assert_equal [], array2.value
|
167
176
|
assert_equal [UNKNOWN_TAIL], array3.value
|
@@ -169,14 +178,12 @@ describe 'Array' do
|
|
169
178
|
end
|
170
179
|
|
171
180
|
it 'should expand Tails that are an Array' do
|
172
|
-
skip 'until Tail added'
|
173
181
|
array = [1,2,3,Tail.new([7,8,9])]
|
174
182
|
|
175
183
|
assert_equal [1,2,3,7,8,9], array.value
|
176
184
|
end
|
177
185
|
|
178
186
|
it 'should return the value of instantiated variables in a Tail' do
|
179
|
-
skip 'until Variable added'
|
180
187
|
goal = new_goal :tailor, :h, :t
|
181
188
|
array = goal.variablise([:h, :b] / :t)
|
182
189
|
goal.instantiate :h, [1,2,3]
|
@@ -185,12 +192,18 @@ describe 'Array' do
|
|
185
192
|
assert_equal [goal.value([1,2,3]),goal.variable(:b), goal.value(7), goal.value(8), goal.value(9)], array.value
|
186
193
|
end
|
187
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
|
+
|
188
202
|
end
|
189
203
|
|
190
204
|
describe '#type' do
|
191
205
|
|
192
206
|
it 'should return :variable for symbols' do
|
193
|
-
skip 'until Tail added'
|
194
207
|
assert_equal :array, array1.type
|
195
208
|
assert_equal :array, array2.type
|
196
209
|
assert_equal :array, array3.type
|
@@ -202,7 +215,6 @@ describe 'Array' do
|
|
202
215
|
describe '#head' do
|
203
216
|
|
204
217
|
it 'should return the first element when no headsize is provided' do
|
205
|
-
skip 'until Tail added'
|
206
218
|
assert_equal 1, array1.head
|
207
219
|
assert_nil array2.head
|
208
220
|
assert_nil array3.head
|
@@ -210,7 +222,6 @@ describe 'Array' do
|
|
210
222
|
end
|
211
223
|
|
212
224
|
it 'should return the first headsize elements' do
|
213
|
-
skip 'until Tail added'
|
214
225
|
assert_equal [1, 2], array1.head(2)
|
215
226
|
assert_equal [], array2.head(2)
|
216
227
|
assert_equal [UNKNOWN_TAIL], array3.head(2)
|
@@ -218,7 +229,6 @@ describe 'Array' do
|
|
218
229
|
end
|
219
230
|
|
220
231
|
it 'should return an extended head if the tail is uninstantiated' do
|
221
|
-
skip 'until Tail added'
|
222
232
|
assert_equal [1, 2, :A, 4, [:B, 6, 7, :C], 9], array1.head(9)
|
223
233
|
assert_equal [], array2.head(9)
|
224
234
|
assert_equal [UNKNOWN_TAIL], array3.head(9)
|
@@ -230,7 +240,6 @@ describe 'Array' do
|
|
230
240
|
describe '#tail' do
|
231
241
|
|
232
242
|
it 'should return the tail after the first element when no headsize is provided' do
|
233
|
-
skip 'until Tail added'
|
234
243
|
assert_equal [2, :A, 4, [:B, 6, 7, :C], 9], array1.tail
|
235
244
|
assert_equal [], array2.tail
|
236
245
|
assert_equal [UNKNOWN_TAIL], array3.tail
|
@@ -238,7 +247,6 @@ describe 'Array' do
|
|
238
247
|
end
|
239
248
|
|
240
249
|
it 'should return the tail after the first headsize elements' do
|
241
|
-
skip 'until Tail added'
|
242
250
|
assert_equal [:A, 4, [:B, 6, 7, :C], 9], array1.tail(2)
|
243
251
|
assert_equal [], array2.tail(2)
|
244
252
|
assert_equal [UNKNOWN_TAIL], array3.tail(2)
|
@@ -246,7 +254,6 @@ describe 'Array' do
|
|
246
254
|
end
|
247
255
|
|
248
256
|
it 'should return an extended tail if the tail is uninstantiated' do
|
249
|
-
skip 'until Tail added'
|
250
257
|
assert_equal [], array1.tail(9)
|
251
258
|
assert_equal [], array2.tail(9)
|
252
259
|
assert_equal [UNKNOWN_TAIL], array3.tail(9)
|
data/test/porolog/goal_test.rb
CHANGED
@@ -16,6 +16,10 @@ describe 'Porolog' do
|
|
16
16
|
|
17
17
|
describe 'Goal' do
|
18
18
|
|
19
|
+
let(:pred) { Predicate.new :p }
|
20
|
+
let(:args) { pred.(:x,:y) }
|
21
|
+
let(:goal) { Goal.new args }
|
22
|
+
|
19
23
|
describe '.reset' do
|
20
24
|
|
21
25
|
it 'should clear all goals' do
|
@@ -45,10 +49,6 @@ describe 'Porolog' do
|
|
45
49
|
Goal.reset
|
46
50
|
end
|
47
51
|
|
48
|
-
it 'should clear the goal cache' do
|
49
|
-
# TECH-CREDIT: Probably not going to use a cache; we'll see ...
|
50
|
-
end
|
51
|
-
|
52
52
|
end
|
53
53
|
|
54
54
|
describe '.goals' do
|
@@ -58,17 +58,14 @@ describe 'Porolog' do
|
|
58
58
|
|
59
59
|
goal1 = new_goal :predicate1, :a
|
60
60
|
|
61
|
-
assert_equal 1, Goal.goals.size
|
62
61
|
assert_equal [goal1], Goal.goals
|
63
62
|
|
64
63
|
goal2 = new_goal :predicate2, :a, :b
|
65
64
|
|
66
|
-
assert_equal 2, Goal.goals.size
|
67
65
|
assert_equal [goal1,goal2], Goal.goals
|
68
66
|
|
69
67
|
goal3 = new_goal :predicate3, :a, :b, :c
|
70
68
|
|
71
|
-
assert_equal 3, Goal.goals.size
|
72
69
|
assert_equal [goal1,goal2,goal3], Goal.goals
|
73
70
|
end
|
74
71
|
|
@@ -87,9 +84,6 @@ describe 'Porolog' do
|
|
87
84
|
describe '#initialize' do
|
88
85
|
|
89
86
|
it 'should initialize calling_goal' do
|
90
|
-
pred = Predicate.new :p
|
91
|
-
args = pred.(:x,:y)
|
92
|
-
|
93
87
|
goal1 = Goal.new args
|
94
88
|
goal2 = Goal.new args, goal1
|
95
89
|
|
@@ -101,40 +95,112 @@ describe 'Porolog' do
|
|
101
95
|
end
|
102
96
|
|
103
97
|
it 'should initialize arguments' do
|
104
|
-
pred = Predicate.new :p
|
105
|
-
args = pred.(:x,:y)
|
106
|
-
|
107
98
|
goal = Goal.new args, nil
|
108
99
|
|
109
|
-
assert_equal args,
|
100
|
+
assert_equal goal.variablise(args), goal.arguments
|
110
101
|
end
|
111
102
|
|
112
103
|
it 'should initialize terminate' do
|
113
|
-
pred = Predicate.new :p
|
114
|
-
args = pred.(:x,:y)
|
115
|
-
|
116
104
|
goal = Goal.new args, nil
|
117
105
|
|
118
|
-
assert_equal false,
|
106
|
+
assert_equal false, goal.terminated?
|
119
107
|
end
|
120
108
|
|
121
109
|
it 'should initialize variables' do
|
122
|
-
pred = Predicate.new :p
|
123
|
-
args = pred.(:x,:y)
|
124
|
-
|
125
110
|
goal = Goal.new args, nil
|
126
111
|
|
127
|
-
assert_Goal_variables goal, {},
|
112
|
+
assert_Goal_variables goal, { x: nil, y: nil }, [
|
113
|
+
'Goal1.:x',
|
114
|
+
'Goal1.:y',
|
115
|
+
].join("\n")
|
128
116
|
end
|
129
117
|
|
130
118
|
it 'should register the goal as undeleted' do
|
131
|
-
|
132
|
-
|
119
|
+
goal1 = Goal.new args, nil
|
120
|
+
goal2 = Goal.new args, goal1
|
133
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
|
134
130
|
goal1 = Goal.new args, nil
|
135
131
|
goal2 = Goal.new args, goal1
|
136
132
|
|
137
|
-
assert_equal
|
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
|
138
204
|
end
|
139
205
|
|
140
206
|
end
|
@@ -157,9 +223,6 @@ describe 'Porolog' do
|
|
157
223
|
describe '#deleted?' do
|
158
224
|
|
159
225
|
it 'should return the deleted state of a goal' do
|
160
|
-
pred = Predicate.new :p
|
161
|
-
args = pred.(:x,:y)
|
162
|
-
|
163
226
|
goal = Goal.new args
|
164
227
|
|
165
228
|
refute goal.deleted?, 'goal should not be deleted'
|
@@ -170,9 +233,6 @@ describe 'Porolog' do
|
|
170
233
|
end
|
171
234
|
|
172
235
|
it 'should memoize the deleted state of a goal' do
|
173
|
-
pred = Predicate.new :p
|
174
|
-
args = pred.(:x,:y)
|
175
|
-
|
176
236
|
goal = Goal.new args
|
177
237
|
|
178
238
|
check_deleted_spy = Spy.on(goal, :check_deleted).and_call_through
|
@@ -197,11 +257,6 @@ describe 'Porolog' do
|
|
197
257
|
describe '#check_deleted' do
|
198
258
|
|
199
259
|
it 'should return false when the goal is not deleted and keep variables intact' do
|
200
|
-
skip 'until Variable added'
|
201
|
-
|
202
|
-
pred = Predicate.new :p
|
203
|
-
args = pred.(:x,:y)
|
204
|
-
|
205
260
|
goal = Goal.new args
|
206
261
|
goal.variable(:x)
|
207
262
|
goal.variable(:y)
|
@@ -209,17 +264,12 @@ describe 'Porolog' do
|
|
209
264
|
|
210
265
|
variable_remove_spy = Spy.on_instance_method(Variable, :remove)
|
211
266
|
|
212
|
-
refute goal.check_deleted
|
267
|
+
refute goal.check_deleted, 'goal should not be deleted'
|
213
268
|
|
214
269
|
assert_equal 0, variable_remove_spy.calls.size
|
215
270
|
end
|
216
271
|
|
217
272
|
it 'should return true when the goal is deleted and remove all variables' do
|
218
|
-
skip 'until Variable added'
|
219
|
-
|
220
|
-
pred = Predicate.new :p
|
221
|
-
args = pred.(:x,:y)
|
222
|
-
|
223
273
|
goal = Goal.new args
|
224
274
|
goal.variable(:x)
|
225
275
|
goal.variable(:y)
|
@@ -229,21 +279,83 @@ describe 'Porolog' do
|
|
229
279
|
|
230
280
|
Goal.reset
|
231
281
|
|
232
|
-
assert goal.check_deleted
|
282
|
+
assert goal.check_deleted, 'goal should be deleted'
|
233
283
|
|
234
284
|
assert_equal 3, variable_remove_spy.calls.size
|
235
285
|
end
|
236
286
|
|
237
287
|
end
|
238
288
|
|
239
|
-
describe '#
|
289
|
+
describe '#terminate!' do
|
240
290
|
|
241
|
-
it 'should
|
242
|
-
|
291
|
+
it 'should set the goal to terminate and log the event' do
|
292
|
+
goal = Goal.new args
|
243
293
|
|
244
|
-
|
245
|
-
|
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
|
246
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
|
247
359
|
goal = Goal.new args
|
248
360
|
goal.variable(:x)
|
249
361
|
goal.variable(:y)
|
@@ -254,26 +366,148 @@ describe 'Porolog' do
|
|
254
366
|
assert_instance_of Hash, variables
|
255
367
|
|
256
368
|
assert_Goal goal, :p, [:x,:y]
|
257
|
-
assert_Goal_variables goal, { x: nil, y: nil, z: nil },
|
369
|
+
assert_Goal_variables goal, { x: nil, y: nil, z: nil }, [
|
370
|
+
'Goal1.:x',
|
371
|
+
'Goal1.:y',
|
372
|
+
'Goal1.:z',
|
373
|
+
].join("\n")
|
258
374
|
end
|
259
375
|
|
260
376
|
end
|
261
377
|
|
262
|
-
describe '#
|
378
|
+
describe '#inspect_variables' do
|
263
379
|
|
264
|
-
|
265
|
-
|
266
|
-
|
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
|
267
477
|
|
268
|
-
|
269
|
-
|
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
|
270
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
|
271
507
|
assert_equal 4.132, goal.variable(4.132)
|
272
508
|
end
|
273
509
|
|
274
510
|
it 'should create and find a variable from a Symbol or Variable' do
|
275
|
-
skip 'until Variable added'
|
276
|
-
|
277
511
|
refute goal.variables.key?(:v), ':v should not be a variable'
|
278
512
|
|
279
513
|
variable1 = goal.variable :v
|
@@ -292,26 +526,40 @@ describe 'Porolog' do
|
|
292
526
|
|
293
527
|
end
|
294
528
|
|
295
|
-
describe '#
|
529
|
+
describe '#value' do
|
296
530
|
|
297
|
-
|
298
|
-
|
299
|
-
|
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
|
300
549
|
|
301
550
|
describe 'when name is a Symbol' do
|
551
|
+
|
302
552
|
let(:variable_name) { :cymbal }
|
303
553
|
|
304
554
|
it 'should create the Variable' do
|
305
|
-
skip 'until Variable added'
|
306
|
-
|
307
555
|
refute goal.variables.key?(variable_name), "#{variable_name} should not exist"
|
308
556
|
|
309
|
-
|
557
|
+
refute_nil goal.value_of(variable_name)
|
310
558
|
|
311
559
|
assert goal.variables.key?(variable_name), "#{variable_name} should exist"
|
312
560
|
|
313
561
|
variable = goal.variable(variable_name)
|
314
|
-
variable.
|
562
|
+
variable.instantiate 44.5
|
315
563
|
|
316
564
|
assert_equal 44.5, goal.value_of(variable_name)
|
317
565
|
end
|
@@ -319,6 +567,7 @@ describe 'Porolog' do
|
|
319
567
|
end
|
320
568
|
|
321
569
|
describe 'when name is not a Symbol' do
|
570
|
+
|
322
571
|
let(:variable_name) { 99.28 }
|
323
572
|
|
324
573
|
it 'should return the name as the value' do
|
@@ -329,11 +578,55 @@ describe 'Porolog' do
|
|
329
578
|
|
330
579
|
end
|
331
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
|
+
|
332
627
|
describe '#solve' do
|
333
628
|
|
334
629
|
it 'should find no solutions for a goal with no rules' do
|
335
|
-
skip 'until CoreExt added'
|
336
|
-
|
337
630
|
goal1 = new_goal :p, :x, :y
|
338
631
|
|
339
632
|
solutions = goal1.solve
|
@@ -342,8 +635,6 @@ describe 'Porolog' do
|
|
342
635
|
end
|
343
636
|
|
344
637
|
it 'should solve a fact' do
|
345
|
-
skip 'until CoreExt added'
|
346
|
-
|
347
638
|
predicate :fact
|
348
639
|
|
349
640
|
fact(42).fact!
|
@@ -354,8 +645,6 @@ describe 'Porolog' do
|
|
354
645
|
end
|
355
646
|
|
356
647
|
it 'should not solve a falicy' do
|
357
|
-
skip 'until CoreExt added'
|
358
|
-
|
359
648
|
predicate :fact
|
360
649
|
|
361
650
|
fact(42).falicy!
|
@@ -366,8 +655,6 @@ describe 'Porolog' do
|
|
366
655
|
end
|
367
656
|
|
368
657
|
it 'should solve using head and tail with lists' do
|
369
|
-
skip 'until HeadTail added'
|
370
|
-
|
371
658
|
predicate :head_tail
|
372
659
|
|
373
660
|
head_tail([1,2,3,4,5,6,7]).fact!
|
@@ -382,7 +669,8 @@ describe 'Porolog' do
|
|
382
669
|
end
|
383
670
|
|
384
671
|
it 'should solve a goal recursively' do
|
385
|
-
|
672
|
+
#:nocov:
|
673
|
+
skip 'until Standard Predicates added'
|
386
674
|
|
387
675
|
predicate :recursive
|
388
676
|
|
@@ -397,7 +685,126 @@ describe 'Porolog' do
|
|
397
685
|
|
398
686
|
assert_equal [{}], solutions
|
399
687
|
end
|
688
|
+
#:nocov:
|
689
|
+
end
|
690
|
+
|
691
|
+
end
|
692
|
+
|
693
|
+
describe '#satisfy' do
|
694
|
+
|
695
|
+
let(:block) { ->(subgoal){} }
|
696
|
+
|
697
|
+
it 'should return false when the goal has no arguments' do
|
698
|
+
goal = Goal.new nil
|
699
|
+
|
700
|
+
block.expects(:call).times(0)
|
701
|
+
|
702
|
+
refute goal.satisfy(&block), name
|
703
|
+
end
|
704
|
+
|
705
|
+
it 'should access the predicate of its arguments' do
|
706
|
+
goal.arguments.expects(:predicate).with().returns(nil).times(1)
|
707
|
+
block.expects(:call).times(0)
|
708
|
+
|
709
|
+
assert_nil goal.satisfy(&block), name
|
710
|
+
end
|
711
|
+
|
712
|
+
it 'should try to satisfy the predicate with itself' do
|
713
|
+
pred.expects(:satisfy).with(goal).returns(nil).times(1)
|
714
|
+
block.expects(:call).times(0)
|
715
|
+
|
716
|
+
assert_nil goal.satisfy(&block), name
|
717
|
+
end
|
718
|
+
|
719
|
+
it 'should call the block when the predicate is satisfied' do
|
720
|
+
pred.(1,2).fact!
|
721
|
+
pred.(3,4).fact!
|
722
|
+
pred.(5,6).fact!
|
723
|
+
|
724
|
+
block.expects(:call).times(3)
|
725
|
+
|
726
|
+
assert goal.satisfy(&block), name
|
727
|
+
end
|
728
|
+
|
729
|
+
end
|
730
|
+
|
731
|
+
describe '#instantiate' do
|
732
|
+
|
733
|
+
it 'creates an Array with a Tail using the slash notation with Symbols with a goal' do
|
734
|
+
goal = new_goal :bravo, :x, :y, :z
|
735
|
+
|
736
|
+
head_tail = goal.variablise(:head / :tail)
|
737
|
+
|
738
|
+
assert_Array_with_Tail head_tail, [goal.variable(:head)], '*Goal1.:tail'
|
739
|
+
|
740
|
+
assert_Goal_variables goal, { x: nil, y: nil, z: nil, head: nil, tail: nil }, [
|
741
|
+
'Goal1.:x',
|
742
|
+
'Goal1.:y',
|
743
|
+
'Goal1.:z',
|
744
|
+
'Goal1.:head',
|
745
|
+
'Goal1.:tail',
|
746
|
+
].join("\n")
|
747
|
+
end
|
748
|
+
|
749
|
+
it 'creates an Array with a Tail using the slash notation with a single head with a goal' do
|
750
|
+
goal = new_goal :bravo, :x, :y, :z
|
751
|
+
|
752
|
+
head_tail = goal.variablise([:head] / :tail)
|
753
|
+
|
754
|
+
assert_Array_with_Tail head_tail, [goal.variable(:head)], '*Goal1.:tail'
|
755
|
+
|
756
|
+
assert_Goal_variables goal, { x: nil, y: nil, z: nil, head: nil, tail: nil }, [
|
757
|
+
'Goal1.:x',
|
758
|
+
'Goal1.:y',
|
759
|
+
'Goal1.:z',
|
760
|
+
'Goal1.:head',
|
761
|
+
'Goal1.:tail',
|
762
|
+
].join("\n")
|
763
|
+
end
|
764
|
+
|
765
|
+
it 'creates variables from its contents with a goal' do
|
766
|
+
predicate :bravo
|
767
|
+
arguments = Predicate[:bravo].arguments(:x,:y,:z)
|
768
|
+
goal = arguments.goal
|
769
|
+
|
770
|
+
head_tail = [:alpha,bravo(:a,:b,:c),[:carly]] / [:x,[:y],bravo(:p,:q/:r)]
|
771
|
+
|
772
|
+
assert_equal [:alpha,bravo(:a,:b,:c),[:carly], :x,[:y],bravo(:p,:q/:r)].inspect, head_tail.inspect
|
773
|
+
|
774
|
+
assert_Goal_variables goal, { x: nil, y: nil, z: nil }, [
|
775
|
+
'Goal1.:x',
|
776
|
+
'Goal1.:y',
|
777
|
+
'Goal1.:z',
|
778
|
+
].join("\n")
|
779
|
+
|
780
|
+
head_tail = goal.variablise(head_tail)
|
781
|
+
|
782
|
+
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
|
783
|
+
|
784
|
+
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 }, [
|
785
|
+
'Goal1.:x',
|
786
|
+
'Goal1.:y',
|
787
|
+
'Goal1.:z',
|
788
|
+
'Goal1.:alpha',
|
789
|
+
'Goal1.:a',
|
790
|
+
'Goal1.:b',
|
791
|
+
'Goal1.:c',
|
792
|
+
'Goal1.:carly',
|
793
|
+
'Goal1.:p',
|
794
|
+
'Goal1.:q',
|
795
|
+
'Goal1.:r',
|
796
|
+
].join("\n")
|
797
|
+
end
|
798
|
+
|
799
|
+
it 'should combine Array value of head and Array value of tail when it has a goal' do
|
800
|
+
head_tail = [:first] / :last
|
801
|
+
|
802
|
+
goal.instantiate :first, 'alpha', goal
|
803
|
+
goal.instantiate :last, ['omega'], goal
|
804
|
+
|
805
|
+
head_tail = goal.values_of(goal.variablise(head_tail))
|
400
806
|
|
807
|
+
assert_equal ['alpha','omega'], head_tail
|
401
808
|
end
|
402
809
|
|
403
810
|
end
|